1/*
2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * This file is available under and governed by the GNU General Public
28 * License version 2 only, as published by the Free Software Foundation.
29 * However, the following notice accompanied the original version of this
30 * file, and Oracle licenses the original version of this file under the BSD
31 * license:
32 */
33/*
34   Copyright 2009-2013 Attila Szegedi
35
36   Licensed under both the Apache License, Version 2.0 (the "Apache License")
37   and the BSD License (the "BSD License"), with licensee being free to
38   choose either of the two at their discretion.
39
40   You may not use this file except in compliance with either the Apache
41   License or the BSD License.
42
43   If you choose to use this file in compliance with the Apache License, the
44   following notice applies to you:
45
46       You may obtain a copy of the Apache License at
47
48           http://www.apache.org/licenses/LICENSE-2.0
49
50       Unless required by applicable law or agreed to in writing, software
51       distributed under the License is distributed on an "AS IS" BASIS,
52       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
53       implied. See the License for the specific language governing
54       permissions and limitations under the License.
55
56   If you choose to use this file in compliance with the BSD License, the
57   following notice applies to you:
58
59       Redistribution and use in source and binary forms, with or without
60       modification, are permitted provided that the following conditions are
61       met:
62       * Redistributions of source code must retain the above copyright
63         notice, this list of conditions and the following disclaimer.
64       * Redistributions in binary form must reproduce the above copyright
65         notice, this list of conditions and the following disclaimer in the
66         documentation and/or other materials provided with the distribution.
67       * Neither the name of the copyright holder nor the names of
68         contributors may be used to endorse or promote products derived from
69         this software without specific prior written permission.
70
71       THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
72       IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
73       TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
74       PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
75       BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
76       CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
77       SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
78       BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
79       WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
80       OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
81       ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
82*/
83
84package jdk.dynalink.beans;
85
86import java.lang.invoke.MethodHandles.Lookup;
87import java.util.Collections;
88import java.util.Set;
89import jdk.dynalink.DynamicLinkerFactory;
90import jdk.dynalink.StandardNamespace;
91import jdk.dynalink.StandardOperation;
92import jdk.dynalink.linker.GuardedInvocation;
93import jdk.dynalink.linker.GuardingDynamicLinker;
94import jdk.dynalink.linker.LinkRequest;
95import jdk.dynalink.linker.LinkerServices;
96import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker;
97
98/**
99 * A linker for ordinary Java objects. Normally used as the ultimate fallback
100 * linker by the {@link DynamicLinkerFactory} so it is given the chance to link
101 * calls to all objects that no other linker recognized. Specifically, this
102 * linker will:
103 * <ul>
104 * <li>expose all public methods of form {@code setXxx()}, {@code getXxx()},
105 * and {@code isXxx()} as property setters and getters for
106 * {@link StandardOperation#SET} and {@link StandardOperation#GET} operations in the
107 * {@link StandardNamespace#PROPERTY} namespace;</li>
108 * <li>expose all public methods for retrieval for
109 * {@link StandardOperation#GET} operation in the {@link StandardNamespace#METHOD} namespace;
110 * the methods thus retrieved can then be invoked using {@link StandardOperation#CALL}.</li>
111 * <li>expose all public fields as properties, unless there are getters or
112 * setters for the properties of the same name;</li>
113 * <li> expose elements of native Java arrays, {@link java.util.List} and {@link java.util.Map} objects as
114 * {@link StandardOperation#GET} and {@link StandardOperation#SET} operations in the
115 * {@link StandardNamespace#ELEMENT} namespace;</li>
116 * <li>expose a virtual property named {@code length} on Java arrays, {@link java.util.Collection} and
117 * {@link java.util.Map} objects;</li>
118 * <li>expose {@link StandardOperation#NEW} on instances of {@link StaticClass}
119 * as calls to constructors, including those static class objects that represent
120 * Java arrays (their constructors take a single {@code int} parameter
121 * representing the length of the array to create);</li>
122 * <li>expose static methods, fields, and properties of classes in a similar
123 * manner to how instance method, fields, and properties are exposed, on
124 * {@link StaticClass} objects.</li>
125 * <li>expose a virtual property named {@code static} on instances of
126 * {@link java.lang.Class} to access their {@link StaticClass}.</li>
127 * </ul>
128 * <p><strong>Overloaded method resolution</strong> is performed automatically
129 * for property setters, methods, and constructors. Additionally, manual
130 * overloaded method selection is supported by having a call site specify a name
131 * for a method that contains an explicit signature, e.g.
132 * {@code StandardOperation.GET.withNamespace(METHOD).named("parseInt(String,int)")}
133 * You can use non-qualified class names in such signatures regardless of those
134 * classes' packages, they will match any class with the same non-qualified name. You
135 * only have to use a fully qualified class name in case non-qualified class
136 * names would cause selection ambiguity (that is extremely rare). Overloaded
137 * resolution for constructors is not automatic as there is no logical place to
138 * attach that functionality to but if a language wishes to provide this
139 * functionality, it can use {@link #getConstructorMethod(Class, String)} as a
140 * useful building block for it.</p>
141 * <p><strong>Variable argument invocation</strong> is handled for both methods
142 * and constructors.</p>
143 * <p><strong>Caller sensitive methods</strong> can be linked as long as they
144 * are otherwise public and link requests have call site descriptors carrying
145 * full-strength {@link Lookup} objects and not weakened lookups or the public
146 * lookup.</p>
147 * <p><strong>The behavior for handling missing members</strong> can be
148 * customized by passing a {@link MissingMemberHandlerFactory} to the
149 * {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory) constructor}.
150 * </p>
151 * <p>The class also exposes various methods for discovery of available
152 * property and method names on classes and class instances, as well as access
153 * to per-class linkers using the {@link #getLinkerForClass(Class)}
154 * method.</p>
155 */
156public class BeansLinker implements GuardingDynamicLinker {
157    private static final ClassValue<TypeBasedGuardingDynamicLinker> linkers = new ClassValue<TypeBasedGuardingDynamicLinker>() {
158        @Override
159        protected TypeBasedGuardingDynamicLinker computeValue(final Class<?> clazz) {
160            // If ClassValue.put() were public, we could just pre-populate with these known mappings...
161            return
162                clazz == Class.class ? new ClassLinker() :
163                clazz == StaticClass.class ? new StaticClassLinker() :
164                DynamicMethod.class.isAssignableFrom(clazz) ? new DynamicMethodLinker() :
165                new BeanLinker(clazz);
166        }
167    };
168
169    private final MissingMemberHandlerFactory missingMemberHandlerFactory;
170
171    /**
172     * Creates a new beans linker. Equivalent to
173     * {@link BeansLinker#BeansLinker(MissingMemberHandlerFactory)} with
174     * {@code null} passed as the missing member handler factory, resulting in
175     * the default behavior for linking and evaluating missing members.
176     */
177    public BeansLinker() {
178        this(null);
179    }
180
181    /**
182     * Creates a new beans linker with the specified factory for creating
183     * missing member handlers. The passed factory can be null if the default
184     * behavior is adequate. See {@link MissingMemberHandlerFactory} for details.
185     * @param missingMemberHandlerFactory a factory for creating handlers for
186     * operations on missing members.
187     */
188    public BeansLinker(final MissingMemberHandlerFactory missingMemberHandlerFactory) {
189        this.missingMemberHandlerFactory = missingMemberHandlerFactory;
190    }
191
192    /**
193     * Returns a bean linker for a particular single class. Useful when you need
194     * to override or extend the behavior of linking for some classes in your
195     * language runtime's linker, but still want to delegate to the default
196     * behavior in some cases.
197     * @param clazz the class
198     * @return a bean linker for that class
199     */
200    public TypeBasedGuardingDynamicLinker getLinkerForClass(final Class<?> clazz) {
201        final TypeBasedGuardingDynamicLinker staticLinker = getStaticLinkerForClass(clazz);
202        if (missingMemberHandlerFactory == null) {
203            return staticLinker;
204        }
205        return new NoSuchMemberHandlerBindingLinker(staticLinker, missingMemberHandlerFactory);
206    }
207
208    private static class NoSuchMemberHandlerBindingLinker implements TypeBasedGuardingDynamicLinker {
209        private final TypeBasedGuardingDynamicLinker linker;
210        private final MissingMemberHandlerFactory missingMemberHandlerFactory;
211
212        NoSuchMemberHandlerBindingLinker(final TypeBasedGuardingDynamicLinker linker, final MissingMemberHandlerFactory missingMemberHandlerFactory) {
213            this.linker = linker;
214            this.missingMemberHandlerFactory = missingMemberHandlerFactory;
215        }
216
217        @Override
218        public boolean canLinkType(final Class<?> type) {
219            return linker.canLinkType(type);
220        }
221
222        @Override
223        public GuardedInvocation getGuardedInvocation(final LinkRequest linkRequest, final LinkerServices linkerServices) throws Exception {
224            return linker.getGuardedInvocation(linkRequest,
225                    LinkerServicesWithMissingMemberHandlerFactory.get(
226                            linkerServices, missingMemberHandlerFactory));
227        }
228    }
229
230    static TypeBasedGuardingDynamicLinker getStaticLinkerForClass(final Class<?> clazz) {
231        return linkers.get(clazz);
232    }
233
234    /**
235     * Returns true if the object is a Java dynamic method (e.g., one
236     * obtained through a {@code GET:METHOD} operation on a Java object or
237     * {@link StaticClass} or through
238     * {@link #getConstructorMethod(Class, String)}.
239     *
240     * @param obj the object we want to test for being a Java dynamic method.
241     * @return true if it is a dynamic method, false otherwise.
242     */
243    public static boolean isDynamicMethod(final Object obj) {
244        return obj instanceof DynamicMethod;
245    }
246
247    /**
248     * Returns true if the object is a Java constructor (obtained through
249     * {@link #getConstructorMethod(Class, String)}}.
250     *
251     * @param obj the object we want to test for being a Java constructor.
252     * @return true if it is a constructor, false otherwise.
253     */
254    public static boolean isDynamicConstructor(final Object obj) {
255        return obj instanceof DynamicMethod && ((DynamicMethod)obj).isConstructor();
256    }
257
258    /**
259     * Return the dynamic method of constructor of the given class and the given
260     * signature. This method is useful for exposing a functionality for
261     * selecting an overloaded constructor based on an explicit signature, as
262     * this functionality is not otherwise exposed by Dynalink as
263     * {@link StaticClass} objects act as overloaded constructors without
264     * explicit signature selection. Example usage would be:
265     * {@code getConstructorMethod(java.awt.Color.class, "int, int, int")}.
266     * @param clazz the class
267     * @param signature full signature of the constructor. Note how you can use
268     * names of primitive types, array names with normal Java notation (e.g.
269     * {@code "int[]"}), and normally you can even use unqualified class names
270     * (e.g. {@code "String, List"} instead of
271     * {@code "java.lang.String, java.util.List"} as long as they don't cause
272     * ambiguity in the specific parameter position.
273     * @return dynamic method for the constructor or null if no constructor with
274     * the specified signature exists.
275     */
276    public static Object getConstructorMethod(final Class<?> clazz, final String signature) {
277        return StaticClassLinker.getConstructorMethod(clazz, signature);
278    }
279
280    /**
281     * Returns a set of names of all readable instance properties of a class.
282     * @param clazz the class
283     * @return a set of names of all readable instance properties of a class.
284     */
285    public static Set<String> getReadableInstancePropertyNames(final Class<?> clazz) {
286        final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
287        if(linker instanceof BeanLinker) {
288            return ((BeanLinker)linker).getReadablePropertyNames();
289        }
290        return Collections.emptySet();
291    }
292
293    /**
294     * Returns a set of names of all writable instance properties of a class.
295     * @param clazz the class
296     * @return a set of names of all writable instance properties of a class.
297     */
298    public static Set<String> getWritableInstancePropertyNames(final Class<?> clazz) {
299        final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
300        if(linker instanceof BeanLinker) {
301            return ((BeanLinker)linker).getWritablePropertyNames();
302        }
303        return Collections.emptySet();
304    }
305
306    /**
307     * Returns a set of names of all instance methods of a class.
308     * @param clazz the class
309     * @return a set of names of all instance methods of a class.
310     */
311    public static Set<String> getInstanceMethodNames(final Class<?> clazz) {
312        final TypeBasedGuardingDynamicLinker linker = getStaticLinkerForClass(clazz);
313        if(linker instanceof BeanLinker) {
314            return ((BeanLinker)linker).getMethodNames();
315        }
316        return Collections.emptySet();
317    }
318
319    /**
320     * Returns a set of names of all readable static properties of a class.
321     * @param clazz the class
322     * @return a set of names of all readable static properties of a class.
323     */
324    public static Set<String> getReadableStaticPropertyNames(final Class<?> clazz) {
325        return StaticClassLinker.getReadableStaticPropertyNames(clazz);
326    }
327
328    /**
329     * Returns a set of names of all writable static properties of a class.
330     * @param clazz the class
331     * @return a set of names of all writable static properties of a class.
332     */
333    public static Set<String> getWritableStaticPropertyNames(final Class<?> clazz) {
334        return StaticClassLinker.getWritableStaticPropertyNames(clazz);
335    }
336
337    /**
338     * Returns a set of names of all static methods of a class.
339     * @param clazz the class
340     * @return a set of names of all static methods of a class.
341     */
342    public static Set<String> getStaticMethodNames(final Class<?> clazz) {
343        return StaticClassLinker.getStaticMethodNames(clazz);
344    }
345
346    @Override
347    public GuardedInvocation getGuardedInvocation(final LinkRequest request, final LinkerServices linkerServices)
348            throws Exception {
349        final Object receiver = request.getReceiver();
350        if(receiver == null) {
351            // Can't operate on null
352            return null;
353        }
354        return getLinkerForClass(receiver.getClass()).getGuardedInvocation(request,
355                LinkerServicesWithMissingMemberHandlerFactory.get(linkerServices,
356                        missingMemberHandlerFactory));
357    }
358}
359