001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package com.sun.data.provider.impl;
043:
044: import java.io.IOException;
045: import java.io.ObjectInputStream;
046: import java.io.ObjectOutputStream;
047: import java.io.Serializable;
048: import java.lang.reflect.Method;
049: import java.util.ArrayList;
050: import java.util.HashMap;
051: import com.sun.data.provider.DataListener;
052: import com.sun.data.provider.DataProviderException;
053: import com.sun.data.provider.FieldKey;
054: import com.sun.data.provider.RefreshableDataListener;
055: import com.sun.data.provider.RefreshableDataProvider;
056:
057: /**
058: * <p>A DataProvider implementation to wrap the singleton (non-array) return
059: * value from a method. Set the <code>dataClassInstance</code>,
060: * <code>dataMethod</code>, and <code>dataMethodArguments</code> properties to
061: * point to a method on a class instance. The result from that method call
062: * will be wrapped as a DataProvider.</p>
063: *
064: * @author cao, Joe Nuxoll
065: */
066: public class MethodResultDataProvider implements
067: RefreshableDataProvider, Serializable {
068:
069: /**
070: * Constructs a new MethodResultDataProvider with no dataClassInstance
071: * or dataMethod specified.
072: */
073: public MethodResultDataProvider() {
074: }
075:
076: /**
077: * Constructs a new MethodResultDataProvider using the specified
078: * dataClassInstance and dataMethod.
079: *
080: * @param dataClassInstance The class instance where the method is invoked
081: * @param dataMethod The method where the data is from
082: */
083: public MethodResultDataProvider(Object dataClassInstance,
084: Method dataMethod) {
085: this ();
086: setDataClassInstance(dataClassInstance);
087: setDataMethod(dataMethod);
088: }
089:
090: /**
091: * Returns the dataClassInstance that contains the dataMethod to be invoked.
092: *
093: * @return Object
094: */
095: public Object getDataClassInstance() {
096: return dataClassInstance;
097: }
098:
099: /**
100: * Sets the dataClassInstance that contains the dataMethod to be invoked.
101: *
102: * @param instance Object
103: */
104: public void setDataClassInstance(Object instance) {
105: this .dataClassInstance = instance;
106: resultProvider.setObject(null);
107: refreshFieldKeys();
108: }
109:
110: /**
111: * Returns the currently set dataMethod
112: *
113: * @return Method
114: */
115: public Method getDataMethod() {
116: return dataMethod;
117: }
118:
119: /**
120: * Sets the dataMethod that will be invoked
121: *
122: * @param method Method
123: */
124: public void setDataMethod(Method method) {
125: this .dataMethod = method;
126: resultProvider.setObject(null);
127: refreshFieldKeys();
128: }
129:
130: /**
131: * Read-only access to the result object from the invocation of the
132: * dataMethod
133: *
134: * @return Object
135: */
136: public Object getResultObject() throws DataProviderException {
137: testInvokeDataMethod();
138: return resultProvider.getObject();
139: }
140:
141: /**
142: * <p>Sets the includeFields property. This affects the set of {@link
143: * FieldKey}s that this {@link com.sun.data.provider.DataProvider} emits.
144: * If includeFields is set to true (the default), then public fields will
145: * be included in the list of available keys (intermixed with the public
146: * properties). If it is set to false, then only the public properties
147: * will be available.</p>
148: *
149: * @param includeFields <code>true</code> to include the public fields, or
150: * <code>false</code> to exclude them (and only show public
151: * properties)
152: */
153: public void setIncludeFields(boolean includeFields) {
154: resultProvider.setIncludeFields(includeFields);
155: }
156:
157: /**
158: * @return The boolean state of the includeFields property
159: */
160: public boolean isIncludeFields() {
161: return resultProvider.isIncludeFields();
162: }
163:
164: /**
165: * Refreshes the list of available fieldKeys (based on the return type of
166: * the dataMethod)
167: */
168: protected void refreshFieldKeys() {
169: resultProvider.clearFieldKeys();
170: if (dataMethod != null) {
171: Class returnType = dataMethod.getReturnType();
172: /* FIXME - use refactored stuff
173: resultProvider.addFieldKeys(
174: ObjectDataProvider.generateFieldKeys(returnType, true));
175: */
176: }
177: }
178:
179: /**
180: * Sets the dataMethodArguments, which will be passed to the dataMethod
181: * when it is invoked.
182: *
183: * @param methodArgs Object[]
184: */
185: public void setDataMethodArguments(Object[] methodArgs) {
186: this .dataMethodArgs = methodArgs;
187: resultProvider.setObject(null);
188: refreshFieldKeys();
189: }
190:
191: /**
192: * Returns the dataMethodArguments
193: *
194: * @return Object[]
195: */
196: public Object[] getDataMethodArguments() {
197: return dataMethodArgs;
198: }
199:
200: //-------------------------------------------------------- Method Invocation
201:
202: /**
203: * Invokes the dataMethod using the arguments specified by the
204: * dataMethodArguments property.
205: */
206: public void invokeDataMethod() throws DataProviderException {
207: invokeDataMethod(getDataMethodArguments());
208: }
209:
210: /**
211: * Invokes the dataMethod using the specified arguments.
212: *
213: * @param args Object[]
214: */
215: public void invokeDataMethod(Object[] args)
216: throws DataProviderException {
217: this .dataMethodArgs = args;
218: resultProvider.setObject(null);
219: if (dataMethod == null || dataClassInstance == null) {
220: return;
221: }
222: try {
223: Object o = null;
224: if (java.beans.Beans.isDesignTime()) {
225: o = AbstractDataProvider.getFakeData(dataMethod
226: .getReturnType());
227: } else {
228: o = dataMethod.invoke(dataClassInstance, args);
229: }
230: resultProvider.setObject(o);
231: fireRefreshed();
232: } catch (Exception e) {
233: throw new DataProviderException(e);
234: }
235: }
236:
237: /**
238: * Tests to see if the dataMethod has been invoked, and invokes it if it
239: * has not.
240: */
241: protected void testInvokeDataMethod() throws DataProviderException {
242: if (resultProvider.getObject() == null) {
243: invokeDataMethod();
244: }
245: }
246:
247: // ---------------------------------- RefreshableDataProvider Implementation
248:
249: /**
250: * Invokes the dataMethod on the dataClassInstance to refresh the data
251: * provider's contets
252: */
253: public void refresh() throws DataProviderException {
254: invokeDataMethod();
255: }
256:
257: /** {@inheritDoc} */
258: public void addRefreshableDataListener(RefreshableDataListener l) {
259: resultProvider.addDataListener(l);
260: }
261:
262: /** {@inheritDoc} */
263: public void removeRefreshableDataListener(RefreshableDataListener l) {
264: resultProvider.removeDataListener(l);
265: }
266:
267: /** {@inheritDoc} */
268: public RefreshableDataListener[] getRefreshableDataListeners() {
269: DataListener[] dpListeners = resultProvider.getDataListeners();
270: if (dpListeners == null) {
271: return new RefreshableDataListener[0];
272: } else {
273: ArrayList rdlList = new ArrayList();
274: for (int i = 0; i < dpListeners.length; i++) {
275: if (dpListeners[i] instanceof RefreshableDataListener) {
276: rdlList.add(dpListeners[i]);
277: }
278: }
279: return (RefreshableDataListener[]) rdlList
280: .toArray(new RefreshableDataListener[rdlList.size()]);
281: }
282: }
283:
284: /**
285: * Fires a refreshed event to each registered {@link RefreshableDataListener}
286: *
287: * @see RefreshableDataListener#refreshed(RefreshableDataProvider)
288: */
289: protected void fireRefreshed() {
290: RefreshableDataListener[] rdls = getRefreshableDataListeners();
291: for (int i = 0; i < rdls.length; i++) {
292: rdls[i].refreshed(this );
293: }
294: }
295:
296: private Object dataClassInstance;
297: private transient Method dataMethod;
298: private Object[] dataMethodArgs;
299: private ObjectDataProvider resultProvider = new ObjectDataProvider();
300:
301: private void writeObject(ObjectOutputStream out) throws IOException {
302: if (dataMethod != null) {
303: HashMap sig = new HashMap();
304: sig.put("class", dataMethod.getDeclaringClass()); // NOI18N
305: sig.put("name", dataMethod.getName()); // NOI18N
306: sig.put("params", dataMethod.getParameterTypes()); // NOI18N
307: out.writeObject(sig);
308: }
309: }
310:
311: private void readObject(ObjectInputStream in) throws IOException,
312: ClassNotFoundException {
313: Object o = in.readObject();
314: if (o instanceof HashMap) {
315: HashMap sig = (HashMap) o;
316: Class clazz = (Class) sig.get("class"); // NOI18N
317: String name = (String) sig.get("name"); // NOI18N
318: Class[] params = (Class[]) sig.get("params"); // NOI18N
319: try {
320: this .dataMethod = clazz.getMethod(name, params);
321: } catch (NoSuchMethodException nsmx) {
322: }
323: }
324: }
325:
326: //---------------------------------------------- DataProvider Implementation
327:
328: /** {@inheritDoc} */
329: public FieldKey[] getFieldKeys() throws DataProviderException {
330: return resultProvider.getFieldKeys();
331: }
332:
333: /** {@inheritDoc} */
334: public FieldKey getFieldKey(String fieldId)
335: throws DataProviderException {
336: return resultProvider.getFieldKey(fieldId);
337: }
338:
339: /** {@inheritDoc} */
340: public Class getType(FieldKey fieldKey)
341: throws DataProviderException {
342: return resultProvider.getType(fieldKey);
343: }
344:
345: /** {@inheritDoc} */
346: public Object getValue(FieldKey fieldKey)
347: throws DataProviderException {
348: testInvokeDataMethod();
349: return resultProvider.getValue(fieldKey);
350: }
351:
352: /** {@inheritDoc} */
353: public boolean isReadOnly(FieldKey fieldKey)
354: throws DataProviderException {
355: testInvokeDataMethod();
356: return resultProvider.isReadOnly(fieldKey);
357: }
358:
359: /** {@inheritDoc} */
360: public void setValue(FieldKey fieldKey, Object value)
361: throws DataProviderException {
362: testInvokeDataMethod();
363: resultProvider.setValue(fieldKey, value);
364: }
365:
366: /** {@inheritDoc} */
367: public void addDataListener(DataListener listener) {
368: resultProvider.addDataListener(listener);
369: }
370:
371: /** {@inheritDoc} */
372: public void removeDataListener(DataListener listener) {
373: resultProvider.removeDataListener(listener);
374: }
375:
376: /** {@inheritDoc} */
377: public DataListener[] getDataListeners() {
378: return resultProvider.getDataListeners();
379: }
380: }
|