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: package org.netbeans.modules.visualweb.insync.beans;
042:
043: import com.sun.rave.designtime.Constants;
044: import com.sun.rave.designtime.EventDescriptor;
045: import org.netbeans.modules.visualweb.insync.java.DelegatorMethod;
046: import org.netbeans.modules.visualweb.insync.java.JavaClass;
047: import java.beans.EventSetDescriptor;
048: import java.beans.MethodDescriptor;
049: import java.lang.reflect.Modifier;
050: import java.util.ArrayList;
051: import java.util.Iterator;
052: import java.util.List;
053:
054: import org.netbeans.modules.visualweb.extension.openide.util.Trace;
055: import org.netbeans.modules.visualweb.insync.java.Method;
056: import org.netbeans.modules.visualweb.insync.java.Statement;
057:
058: /**
059: * Representation of a wiring for a single event listener, which maps to a single add*Listener
060: * statement in the init block. Will contain one or more Events that route the specific events to
061: * the handler methods
062: */
063: public class EventSet extends BeansNode {
064:
065: public static final EventSet[] EMPTY_ARRAY = {};
066:
067: // General event set fields
068: final protected Bean bean; // owning bean
069: final protected EventSetDescriptor descriptor;
070:
071: final protected List<Event> events = new ArrayList<Event>();
072:
073: // Java source-based event set fields
074: private Statement stmt;
075: private JavaClass adapterClass;
076: private boolean inserted;
077:
078: //--------------------------------------------------------------------------------- Construction
079:
080: /**
081: * Partially construct an EventSet to be fully populated later
082: *
083: * @param beansUnit
084: * @param bean
085: * @param name
086: */
087: protected EventSet(Bean bean, EventSetDescriptor descriptor) {
088: super (bean.getUnit());
089: this .bean = bean;
090: this .descriptor = descriptor;
091: }
092:
093: /**
094: * Construct an EventSet bound to existing statement & its bean. Called only from factory below.
095: *
096: * @param beansUnit
097: */
098: protected EventSet(Bean bean, EventSetDescriptor descriptor,
099: Statement stmt, JavaClass adapter) {
100: this (bean, descriptor);
101: this .stmt = stmt;
102: this .adapterClass = adapter;
103: if (adapter != null)
104: bindEvents();
105:
106: assert Trace.trace("insync.beans", "ES new bound EventSet: "
107: + this );
108: }
109:
110: /**
111: * Create a EventSet setting bound to a specific statement of the form:
112: *
113: * bean.addXyzListener(new XyzAdapter() {
114: * ...events...
115: * });
116: *
117: * @param unit
118: * @param s
119: * @return the new bound event set if bindable, else null
120: */
121: static EventSet newBoundInstance(BeansUnit unit, Statement stmt) {
122: Bean bean = unit.getBean(stmt.getBeanName());
123: if (bean == null) {
124: return null;
125: }
126: EventSetDescriptor esd = bean
127: .getEventSetDescriptorForAdder(stmt
128: .getPropertySetterName());
129: if (esd == null) {
130: return null;
131: }
132:
133: JavaClass adapter = stmt.getAdapterClass();
134: if (adapter != null) {
135: EventSet eventSet = new EventSet(bean, esd, stmt, adapter);
136: eventSet.setInserted(true);
137: return eventSet;
138: }
139: return null;
140: }
141:
142: /**
143: * Construct a new EventSet, creating the underlying statement methods
144: *
145: * @param bean
146: * @param name
147: */
148: EventSet(Bean bean, EventSetDescriptor descriptor, boolean unused) {
149: this (bean, descriptor);
150: assert Trace.trace("insync.beans", "ES new created EventSet: "
151: + this );
152: }
153:
154: /**
155: * @param md
156: * @param m
157: * @return
158: */
159: protected Event newBoundEvent(MethodDescriptor md, DelegatorMethod m) {
160: return Event.newBoundInstance(this , md, m);
161: }
162:
163: /**
164: * Scan our descriptor's methods and create individual events that match
165: */
166: protected void bindEvents() {
167: MethodDescriptor[] lmds = descriptor
168: .getListenerMethodDescriptors();
169: for (int i = 0; i < lmds.length; i++) {
170: DelegatorMethod m = adapterClass
171: .getDelegatorMethod(lmds[i].getName(), lmds[i]
172: .getMethod().getParameterTypes());
173: if (m != null) {
174: Event e = newBoundEvent(lmds[i], m);
175: if (e != null)
176: events.add(e);
177: }
178: }
179: }
180:
181: protected DelegatorMethod stubDelegatorMethod(
182: MethodDescriptor mdescr) {
183: Class retType = mdescr.getMethod().getReturnType();
184:
185: // now add parameter(s)
186: Class[] pts = mdescr.getMethod().getParameterTypes();
187: String[] pns = Naming.paramNames(pts, mdescr
188: .getParameterDescriptors());
189:
190: String body = null;
191: if (retType != Void.TYPE) {
192: body = "return null;";
193: }
194:
195: org.netbeans.modules.visualweb.insync.java.MethodInfo info = new org.netbeans.modules.visualweb.insync.java.MethodInfo(
196: mdescr.getName(), retType, Modifier.PUBLIC, pns, pts,
197: body, null);
198: return adapterClass.addDelegatorMethod(info);
199: }
200:
201: private void stubBody(Method method) {
202: Class retType = getMethodDescriptor(method.getName())
203: .getMethod().getReturnType();
204: String body = null;
205: if (retType != Void.TYPE) {
206: body = "return null;";
207: }
208: method.replaceBody(body);
209: }
210:
211: protected DelegatorMethod getDelegatorMethod(MethodDescriptor mdescr) {
212: DelegatorMethod delegate = adapterClass.getDelegatorMethod(
213: mdescr.getMethod().getName(), mdescr.getMethod()
214: .getParameterTypes());
215: if (delegate == null)
216: delegate = stubDelegatorMethod(mdescr);
217: return delegate;
218: }
219:
220: protected void removeDelegatorMethod(Method delegator) {
221: Class type = getAdapterType();
222: if (type != null) {
223: delegator.remove();
224: } else {
225: stubBody(delegator);
226: }
227: }
228:
229: /**
230: * Insert the stub source entry for this EventSet
231: */
232: public void insertEntry() {
233: Class atype = getAdapterType();
234: String adapterClassName;
235: if (atype != null) {
236: adapterClassName = atype.getName();
237: } else {
238: adapterClassName = getListenerType().getName();
239: }
240: Method method = unit.getPropertiesInitMethod();
241: if (descriptor.getAddListenerMethod() != null) {
242: stmt = method.addEventSetStatement(bean.getName(),
243: descriptor.getAddListenerMethod().getName(),
244: adapterClassName);
245: adapterClass = stmt.getAdapterClass();
246: if (atype == null) {
247: // stub all methods in adapter body if we are extending just the interface
248: MethodDescriptor[] mdescrs = descriptor
249: .getListenerMethodDescriptors();
250: for (int i = 0; i < mdescrs.length; i++) {
251: stubDelegatorMethod(mdescrs[i]);
252: }
253: }
254:
255: for (Event event : events) {
256: event.insertEntry();
257: event.setHandler();
258: }
259: inserted = true;
260: }
261: }
262:
263: /**
264: * Release this EventSet's hold on the underlying source. Use when another object will take over.
265: * Clear child event list, etc. This eventSet instance is dead & should not be used.
266: */
267: protected void releaseEntry() {
268: events.clear();
269: stmt = null;
270: }
271:
272: /**
273: * Clear child event list, and remove this eventSet's statement from the init method. Removing
274: * this statement will take out all the event's entries, so they don't have to be explicitly
275: * removed. This eventSet instance is dead & should not be used.
276: *
277: * @return true iff the source entry for this event was actually removed.
278: */
279: public boolean removeEntry() {
280: assert Trace.trace("insync.beans", "ES.removeEntry: " + this );
281: boolean removed = false;
282: events.clear();
283: if (inserted & stmt != null) {
284: removed = stmt.remove();
285: stmt = null;
286: }
287: return removed;
288: }
289:
290: //------------------------------------------------------------------------------------ Accessors
291:
292: /**
293: * Get the descriptor for this EventSet
294: */
295: public EventSetDescriptor getDescriptor() {
296: return descriptor;
297: }
298:
299: /**
300: * Get the name of this EventSet
301: */
302: public String getName() {
303: return descriptor.getName();
304: }
305:
306: /**
307: * Get this EventSet's working adapter class
308: */
309: public JavaClass getAdapter() {
310: return adapterClass;
311: }
312:
313: /**
314: * Get this EventSet's event listener interface type
315: */
316: public Class getListenerType() {
317: return descriptor.getListenerType();
318: }
319:
320: /**
321: * Get this EventSet's event adapter type, if one exists
322: */
323: protected Class getAdapterType() {
324: String lname = getListenerType().getName();
325: int lpos = lname.lastIndexOf("Listener");
326: if (lpos >= 0) {
327: String aname = lname.substring(0, lpos) + "Adapter";
328: try {
329: return unit.getBeanClass(aname);
330: } catch (ClassNotFoundException e) {
331: }
332: }
333: return null;
334: }
335:
336: //--------------------------------------------------------------------------------------- Events
337:
338: /**
339: *
340: */
341: public MethodDescriptor getMethodDescriptor(String name) {
342: MethodDescriptor[] mds = descriptor
343: .getListenerMethodDescriptors();
344: for (int i = 0; i < mds.length; i++) {
345: if (mds[i].getName().equals(name))
346: return mds[i];
347: }
348: return null;
349: }
350:
351: /**
352: *
353: */
354: public Event[] getEvents() {
355: return (Event[]) events.toArray(Event.EMPTY_ARRAY);
356: }
357:
358: /**
359: *
360: */
361: public Event getEvent(String name) {
362: for (Iterator i = events.iterator(); i.hasNext();) {
363: Event e = (Event) i.next();
364: if (e.getName().equals(name))
365: return e;
366: }
367: return null;
368: }
369:
370: /**
371: *
372: */
373: protected Event newCreatedEvent(MethodDescriptor md, String value) {
374: return new Event(this , md, value);
375: }
376:
377: /**
378: *
379: */
380: public Event setEvent(EventDescriptor ed, MethodDescriptor md,
381: String value) {
382: Event e = getEvent(md.getName());
383: if (e != null) {
384: Object defaultBody = ed.getEventSetDescriptor().getValue(
385: Constants.EventDescriptor.DEFAULT_EVENT_BODY);
386: if (defaultBody instanceof String) {
387: e.setDefaultBody((String) defaultBody);
388: }
389: Object parameterNames = ed
390: .getEventSetDescriptor()
391: .getValue(Constants.EventDescriptor.PARAMETER_NAMES);
392: if (parameterNames instanceof String[]) {
393: e.setParameterNames((String[]) parameterNames);
394: }
395: Object requiredImports = ed.getEventSetDescriptor()
396: .getValue(
397: Constants.EventDescriptor.REQUIRED_IMPORTS);
398: if (requiredImports instanceof String[]) {
399: e.setRequiredImports((String[]) requiredImports);
400: }
401: e.setHandler(value);
402: } else {
403: e = newCreatedEvent(md, value);
404: if (e != null)
405: events.add(e);
406: }
407: return e;
408: }
409:
410: /**
411: *
412: */
413: public void unsetEvent(Event e) {
414: if (events.remove(e)) {
415: e.removeEntry();
416: if (events.isEmpty())
417: bean.unsetEventSet(this ); // will call back to our removeEntry()
418: }
419: }
420:
421: public String getAddListenerMethodName() {
422: if (descriptor.getAddListenerMethod() != null) {
423: return descriptor.getAddListenerMethod().getName();
424: }
425: return null;
426: }
427:
428: public boolean isInserted() {
429: return inserted;
430: }
431:
432: public void setInserted(boolean inserted) {
433: this .inserted = inserted;
434: }
435:
436: //--------------------------------------------------------------------------------------- Object
437:
438: /**
439: *
440: */
441: public void toString(StringBuffer sb) {
442: sb.append(" n:");
443: sb.append(getName());
444: sb.append(" adapter:");
445: sb.append(adapterClass);
446: sb.append(" events:");
447: Event[] events = getEvents();
448: for (int i = 0; i < events.length; i++)
449: sb.append(events[i].toString());
450: }
451: }
|