1/*
2 * Copyright (c) 2000, 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
26package java.beans;
27
28/**
29 * An {@code Expression} object represents a primitive expression
30 * in which a single method is applied to a target and a set of
31 * arguments to return a result - as in {@code "a.getFoo()"}.
32 * <p>
33 * In addition to the properties of the super class, the
34 * {@code Expression} object provides a <em>value</em> which
35 * is the object returned when this expression is evaluated.
36 * The return value is typically not provided by the caller and
37 * is instead computed by dynamically finding the method and invoking
38 * it when the first call to {@code getValue} is made.
39 *
40 * @see #getValue
41 * @see #setValue
42 *
43 * @since 1.4
44 *
45 * @author Philip Milne
46 */
47public class Expression extends Statement {
48
49    private static Object unbound = new Object();
50
51    private Object value = unbound;
52
53    /**
54     * Creates a new {@link Expression} object
55     * for the specified target object to invoke the method
56     * specified by the name and by the array of arguments.
57     * <p>
58     * The {@code target} and the {@code methodName} values should not be {@code null}.
59     * Otherwise an attempt to execute this {@code Expression}
60     * will result in a {@code NullPointerException}.
61     * If the {@code arguments} value is {@code null},
62     * an empty array is used as the value of the {@code arguments} property.
63     *
64     * @param target  the target object of this expression
65     * @param methodName  the name of the method to invoke on the specified target
66     * @param arguments  the array of arguments to invoke the specified method
67     *
68     * @see #getValue
69     */
70    @ConstructorProperties({"target", "methodName", "arguments"})
71    public Expression(Object target, String methodName, Object[] arguments) {
72        super(target, methodName, arguments);
73    }
74
75    /**
76     * Creates a new {@link Expression} object with the specified value
77     * for the specified target object to invoke the  method
78     * specified by the name and by the array of arguments.
79     * The {@code value} value is used as the value of the {@code value} property,
80     * so the {@link #getValue} method will return it
81     * without executing this {@code Expression}.
82     * <p>
83     * The {@code target} and the {@code methodName} values should not be {@code null}.
84     * Otherwise an attempt to execute this {@code Expression}
85     * will result in a {@code NullPointerException}.
86     * If the {@code arguments} value is {@code null},
87     * an empty array is used as the value of the {@code arguments} property.
88     *
89     * @param value  the value of this expression
90     * @param target  the target object of this expression
91     * @param methodName  the name of the method to invoke on the specified target
92     * @param arguments  the array of arguments to invoke the specified method
93     *
94     * @see #setValue
95     */
96    public Expression(Object value, Object target, String methodName, Object[] arguments) {
97        this(target, methodName, arguments);
98        setValue(value);
99    }
100
101    /**
102     * {@inheritDoc}
103     * <p>
104     * If the invoked method completes normally,
105     * the value it returns is copied in the {@code value} property.
106     * Note that the {@code value} property is set to {@code null},
107     * if the return type of the underlying method is {@code void}.
108     *
109     * @throws NullPointerException if the value of the {@code target} or
110     *                              {@code methodName} property is {@code null}
111     * @throws NoSuchMethodException if a matching method is not found
112     * @throws SecurityException if a security manager exists and
113     *                           it denies the method invocation
114     * @throws Exception that is thrown by the invoked method
115     *
116     * @see java.lang.reflect.Method
117     * @since 1.7
118     */
119    @Override
120    public void execute() throws Exception {
121        setValue(invoke());
122    }
123
124    /**
125     * If the value property of this instance is not already set,
126     * this method dynamically finds the method with the specified
127     * methodName on this target with these arguments and calls it.
128     * The result of the method invocation is first copied
129     * into the value property of this expression and then returned
130     * as the result of {@code getValue}. If the value property
131     * was already set, either by a call to {@code setValue}
132     * or a previous call to {@code getValue} then the value
133     * property is returned without either looking up or calling the method.
134     * <p>
135     * The value property of an {@code Expression} is set to
136     * a unique private (non-{@code null}) value by default and
137     * this value is used as an internal indication that the method
138     * has not yet been called. A return value of {@code null}
139     * replaces this default value in the same way that any other value
140     * would, ensuring that expressions are never evaluated more than once.
141     * <p>
142     * See the {@code execute} method for details on how
143     * methods are chosen using the dynamic types of the target
144     * and arguments.
145     *
146     * @see Statement#execute
147     * @see #setValue
148     *
149     * @return The result of applying this method to these arguments.
150     * @throws Exception if the method with the specified methodName
151     * throws an exception
152     */
153    public Object getValue() throws Exception {
154        if (value == unbound) {
155            setValue(invoke());
156        }
157        return value;
158    }
159
160    /**
161     * Sets the value of this expression to {@code value}.
162     * This value will be returned by the getValue method
163     * without calling the method associated with this
164     * expression.
165     *
166     * @param value The value of this expression.
167     *
168     * @see #getValue
169     */
170    public void setValue(Object value) {
171        this.value = value;
172    }
173
174    /*pp*/ String instanceName(Object instance) {
175        return instance == unbound ? "<unbound>" : super.instanceName(instance);
176    }
177
178    /**
179     * Prints the value of this expression using a Java-style syntax.
180     */
181    public String toString() {
182        return instanceName(value) + "=" + super.toString();
183    }
184}
185