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.Position;
044: import java.beans.BeanInfo;
045: import java.beans.EventSetDescriptor;
046: import java.beans.PropertyDescriptor;
047: import java.util.ArrayList;
048: import java.util.Iterator;
049: import java.util.List;
050: import org.netbeans.modules.visualweb.extension.openide.util.Trace;
051: import com.sun.rave.designtime.Constants;
052: import com.sun.rave.designtime.DesignBean;
053: import org.netbeans.modules.visualweb.insync.models.FacesModel;
054: import org.netbeans.modules.visualweb.insync.models.FacesModelSet;
055: import org.netbeans.modules.web.jsf.api.facesmodel.ManagedBean;
056: import org.openide.filesystems.FileObject;
057:
058: /**
059: * Representation of a JavaBean instance field within our outer host BeansUnit being built. Initial
060: * property settings are maintained as Property instances, and handled events are maintained as
061: * Events within EventSets.
062: *
063: * @author cquinn
064: */
065: public class Bean extends BeansNode {
066:
067: public static final Bean[] EMPTY_ARRAY = {};
068:
069: static final boolean CREATE_GETTER = true; // generate host getter for this bean
070: static final boolean CREATE_SETTER = true; // generate host setter for this bean
071:
072: protected final BeanInfo beanInfo;
073: protected final List<Property> properties = new ArrayList<Property>();
074: protected final List<EventSet> eventSets = new ArrayList<EventSet>();
075:
076: private String name;
077: private List<String> typeParameterNames;
078: private boolean inserted;
079:
080: //--------------------------------------------------------------------------------- Construction
081:
082: /**
083: * Construct a new created bean
084: *
085: * @param unit
086: * @param beanInfo
087: * @param name
088: */
089: protected Bean(BeansUnit unit, BeanInfo beanInfo, String name) {
090: super (unit);
091: this .beanInfo = beanInfo;
092: this .name = name;
093: }
094:
095: /**
096: * Construct a new bean bound to existing field & accessor methods
097: *
098: * @param unit Owning host unit
099: * @param beanInfo
100: * @param name
101: * @param typeNames
102: */
103: protected Bean(BeansUnit unit, BeanInfo beanInfo, String name,
104: List<String> typeNames) {
105: this (unit, beanInfo, name);
106: typeParameterNames = typeNames;
107: bindCleanup();
108: }
109:
110: /**
111: * Remove this bean's field, methods and statements from the host class. This bean instance is
112: * dead & should not be used.
113: *
114: * @return true iff the source entry for this bean was actually removed.
115: */
116: public boolean removeEntry() {
117: assert Trace.trace("insync.beans", "B.removeEntry: " + this );
118: boolean removed = false;
119: for (Iterator i = properties.iterator(); i.hasNext();) {
120: Property p = (Property) i.next();
121: removed |= p.removeEntry();
122: i.remove();
123: }
124: for (Iterator i = eventSets.iterator(); i.hasNext();) {
125: EventSet es = (EventSet) i.next();
126: removed |= es.removeEntry();
127: i.remove();
128: }
129: removed |= true; //!CQ don't really know since clazz didn't tell us...
130: return removed;
131: }
132:
133: /**
134: * Bind to an existing cleanup method call within the unit's cleanup method body
135: */
136: public void bindCleanup() {
137: }
138:
139: //------------------------------------------------------------------------------------ Parenting
140:
141: /**
142: * @return the parent of this bean, null if top-level bean or dead
143: */
144: public Bean getParent() {
145: return null;
146: }
147:
148: /**
149: * Take the opportinuty to scan for and bind to this bean's parent
150: *
151: * @return the parent of this bean iff not previously bound
152: */
153: public Bean bindParent() {
154: return null;
155: }
156:
157: /**
158: * @return true if this bean is capable of being a parent
159: */
160: public boolean isParentCapable() {
161: return false; // plain old Java beans don't know about any kind of parenting
162: }
163:
164: /**
165: * Add a child bean to this bean at a given location.
166: *
167: * @param child The child bean to add
168: * @param pos The position within the children to add the given child
169: */
170: public void addChild(Bean child, Position pos) {
171: }
172:
173: /**
174: * Remove a child bean from this bean.
175: *
176: * @param child
177: */
178: public void removeChild(Bean child) {
179: }
180:
181: /**
182: * @return the array of child beans--zero size if none currently, or null if this is not a
183: * parent
184: * @see isParentCapable
185: */
186: public Bean[] getChildren() {
187: return null;
188: }
189:
190: /**
191: * Given an instance for this bean and it's parent, perform the appropriate operation on those
192: * objects to establish the live parent-child relationship.
193: * Overridden in subclasses that know about specific bean parent-child relationships
194: *
195: * @param instance the bean instance to parent
196: * @param parent the parent to parent to
197: * @return true if done parenting, or false to be re-called with parent's parent
198: */
199: public boolean performInstanceParenting(Object instance,
200: Object parent, Position pos) {
201: return true;
202: }
203:
204: /**
205: * Same as performInstanceParenting(), except performs the un-parenting.
206: *
207: * @param instance the bean instance to parent
208: * @param parent the parent to parent to
209: */
210: public void performInstanceUnparenting(Object instance,
211: Object parent) {
212: }
213:
214: //------------------------------------------------------------------------------------ Accessors
215:
216: /**
217: * @return the beanInfo for this bean
218: */
219: public BeanInfo getBeanInfo() {
220: return beanInfo;
221: }
222:
223: /**
224: * @return the type of this bean
225: */
226: public Class getType() {
227: return beanInfo.getBeanDescriptor().getBeanClass();
228: }
229:
230: /**
231: * @return the instance name of this bean, null if dead.
232: */
233: public String getName() {
234: return name;
235: }
236:
237: /**
238: * @return whether there is a getter method available
239: */
240: public boolean hasGetter() {
241: return true;
242: }
243:
244: /**
245: * Get the cleanup method name for this bean if it has one
246: * @return the cleanup method name
247: */
248: public String getCleanupMethod() {
249: Object cleanupO = beanInfo.getBeanDescriptor().getValue(
250: Constants.BeanDescriptor.CLEANUP_METHOD);
251: if (cleanupO instanceof String)
252: return (String) cleanupO;
253: return null;
254: }
255:
256: /**
257: * Can the name of this bean be set? Default is to always say yes.
258: *
259: * @return true iff the name of this bean can be set
260: */
261: public boolean canSetName() {
262: return true;
263: }
264:
265: /**
266: * Set the name of this bean, affects the field name as well as the accessor method names
267: *
268: * @param newname The new name to give this bean, possibly as a base for suffixes.
269: * @param autoNumber If true, name will be suffixed with a number if needed to make it unique
270: * @param liveBean The referencing liveBean for possible naming fixup callback
271: * @return The new name, after any fixup or numbering. Null if naming failed.
272: */
273: public String setName(String newname, boolean autoNumber,
274: DesignBean liveBean) {
275: if (autoNumber) {
276: newname = unit.nextAvailableName(newname, this , false);
277: } else if (!unit.isBeanNameAvailable(newname, this )) {
278: return null;
279: }
280:
281: String oldname = name;
282: if (!oldname.equals(newname)) {
283: //System.err.println("B.setName " + oldname + "=>" + name);
284: name = newname;
285: if (inserted) {
286: List<FileObject> fObjs = new ArrayList<FileObject>();
287: FacesModel currentModel = (FacesModel) unit.getModel();
288: fObjs.add(currentModel.getJavaFile());
289: if (!currentModel.isPageBean()) {
290: //In case of non-page beans, it is necessary to update the property
291: //binding expression and accessor methods in lesser scoped beans
292: FacesModel[] models = ((FacesModelSet) currentModel
293: .getOwner()).getFacesModels();
294: for (int i = 0; i < models.length; i++) {
295: FileObject fObj = models[i].getJavaFile();
296: //If the faces model is not yet synced(because it may not be open), then
297: //get the file object for java file via its corresponding jsp file
298: if (fObj == null
299: && (models[i].getFile() == models[i]
300: .getMarkupFile())) {
301: fObj = FacesModel.getJavaForJsp(models[i]
302: .getFile());
303: }
304: fObjs.add(fObj);
305: }
306: }
307:
308: unit.getThisClass().renameProperty(oldname, newname,
309: fObjs);
310: }
311: }
312: return newname;
313: }
314:
315: /**
316: * @return The DOM element underlying this bean, if applicable.
317: */
318: public org.w3c.dom.Element getElement() {
319: return null;
320: }
321:
322: //----------------------------------------------------------------------------------- Properties
323:
324: /**
325: * Get the PropertyDescriptor for a property of this bean indicated by the property name
326: *
327: * @param propertyName the property name to look for
328: * @return the PropertyDescriptor for the property
329: */
330: public PropertyDescriptor getPropertyDescriptor(String propertyName) {
331: PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
332: for (int i = 0; i < pds.length; i++) {
333: if (pds[i].getName().equals(propertyName))
334: return pds[i];
335: }
336: return null;
337: }
338:
339: /**
340: * Get the PropertyDescriptor for a property of this bean indicated by the property setter
341: * method name
342: *
343: * @param setterName the setter method name to lookup the property by
344: * @return the PropertyDescriptor for the property
345: */
346: public PropertyDescriptor getPropertyDescriptorForSetter(
347: String setterName) {
348: PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
349: for (int i = 0; i < pds.length; i++) {
350: java.lang.reflect.Method m = pds[i].getWriteMethod();
351: if (m != null && m.getName().equals(setterName))
352: return pds[i];
353: }
354: return null;
355: }
356:
357: /**
358: * Determines if a given Property, defined by its PropertyDescriptor, is a markup based Property
359: * or not.
360: *
361: * @param pd PropertyDescriptor that identifies the property
362: * @return True iff this bean is markup based and the particular property is also.
363: */
364: public boolean isMarkupProperty(PropertyDescriptor pd) {
365: return false;
366: }
367:
368: /**
369: * @return An array of Property instances representing the set properties for this bean.
370: */
371: public Property[] getProperties() {
372: return properties.toArray(Property.EMPTY_ARRAY);
373: }
374:
375: /**
376: * Get a Property of this bean by name.
377: *
378: * @param name The Property name to look up
379: * @return The Property if found, null if not.
380: */
381: public Property getProperty(String name) {
382: for (Iterator i = properties.iterator(); i.hasNext();) {
383: Property p = (Property) i.next();
384: if (p.getName().equals(name))
385: return p;
386: }
387: return null;
388: }
389:
390: /**
391: *
392: *
393: public Property getProperty(PropertyDescriptor pd) {
394: for (Iterator i = properties.iterator(); i.hasNext(); ) {
395: Property p = (Property)i.next();
396: if (p.getDescriptor() == pd)
397: return p;
398: }
399: return null;
400: }*/
401:
402: /**
403: * Create a new property object ready to have its value set. Overridden in subclasses to create
404: * different property subclasses based on information in the descriptor.
405: *
406: * @param pd The descriptor that defines the property
407: * @return The newly created property object, never null.
408: */
409: protected Property newCreatedProperty(PropertyDescriptor pd) {
410: return new Property(this , pd);
411: }
412:
413: /**
414: * Set a property, identified by name, to a given value or value source. Both the value instance
415: * and source must be provided. A new property will be created to hold this setting if needed.
416: *
417: * @param name The name of the property to set.
418: * @param value The instance of the value to set
419: * @param valueSource The source string that represents the value
420: * @return The property that was set and possibly created, or null if the property was not found
421: */
422: public Property setProperty(String name, Object value,
423: String valueSource) {
424: Property p = getProperty(name);
425: if (p == null) {
426: PropertyDescriptor pd = getPropertyDescriptor(name);
427: if (pd == null)
428: return null;
429: p = newCreatedProperty(pd);
430: properties.add(p);
431: }
432: p.setValue(value, valueSource);
433: return p;
434: }
435:
436: /**
437: * Unset (remove) a given property from this bean.
438: *
439: * @param p Property to unset & remove.
440: */
441: public void unsetProperty(Property p) {
442: properties.remove(p);
443: p.removeEntry();
444: }
445:
446: /**
447: * Unset (remove) a given property, indicated by name, from this bean.
448: *
449: * @param name Property name to unset and remove.
450: */
451: public void unsetProperty(String name) {
452: Property p = getProperty(name);
453: if (p != null)
454: unsetProperty(p);
455: }
456:
457: //------------------------------------------------------------------------------------ EventSets
458:
459: /**
460: * Get the descriptor for an event set of this bean indicated by the event set name.
461: *
462: * @param name the event set name to lookup
463: * @return The EventSetDescriptor for the given event set
464: */
465: public EventSetDescriptor getEventSetDescriptor(String name) {
466: EventSetDescriptor[] esds = beanInfo.getEventSetDescriptors();
467: for (int i = 0; i < esds.length; i++) {
468: if (esds[i].getName().equals(name))
469: return esds[i];
470: }
471: return null;
472: }
473:
474: /**
475: * Get the descriptor for an event set of this bean indicated by the event set's adder method
476: * name.
477: *
478: * @param adderName Event set adder method name.
479: * @return The EventSetDescriptor for the given event set
480: */
481: public EventSetDescriptor getEventSetDescriptorForAdder(
482: String adderName) {
483: EventSetDescriptor[] esds = beanInfo.getEventSetDescriptors();
484: for (int i = 0; i < esds.length; i++) {
485: java.lang.reflect.Method m = esds[i].getAddListenerMethod();
486: if (m != null && m.getName().equals(adderName))
487: return esds[i];
488: }
489: return null;
490: }
491:
492: /**
493: * @return An array of EventSet instances representing the hooked event sets for this bean.
494: */
495: public EventSet[] getEventSets() {
496: return eventSets.toArray(EventSet.EMPTY_ARRAY);
497: }
498:
499: /**
500: * Get an EventSet of this bean by name.
501: *
502: * @param name The EventSet name to look for
503: * @return EventSet of this bean with the given name, or null if not found.
504: */
505: public EventSet getEventSet(String name) {
506: for (Iterator i = eventSets.iterator(); i.hasNext();) {
507: EventSet es = (EventSet) i.next();
508: if (es.getName().equals(name))
509: return es;
510: }
511: return null;
512: }
513:
514: /**
515: * Create a new EventSet object. Overridden in subclasses to create different EventSet
516: * subclasses based on information in the descriptor.
517: *
518: * @param esd The descriptor that defines the EventSet.
519: * @return The newly created EventSet object, never null.
520: */
521: protected EventSet newCreatedEventSet(EventSetDescriptor esd) {
522: return new EventSet(this , esd, true);
523: }
524:
525: /**
526: * Set (hook) a given event set indicated by name. A new EventSet will be created if needed.
527: *
528: * @param name The EventSet name to set.
529: * @return The existing or newly created EventSet.
530: */
531: public EventSet setEventSet(String name) {
532: EventSet es = getEventSet(name);
533: if (es == null) {
534: EventSetDescriptor esd = getEventSetDescriptor(name);
535: es = newCreatedEventSet(esd);
536: eventSets.add(es);
537: }
538: return es;
539: }
540:
541: /**
542: * Remove a logical event set and release its hold on the source elements, but do not actually
543: * remove the source. Used when some other modelling code will take over.
544: *
545: * @param es EventSet to release.
546: */
547: public void releaseEventSet(EventSet es) {
548: eventSets.remove(es);
549: es.releaseEntry();
550: }
551:
552: /**
553: * Unset (unhook) a given EventSet and remove its source representation.
554: *
555: * @param es EventSet to unset.
556: */
557: public void unsetEventSet(EventSet es) {
558: eventSets.remove(es);
559: es.removeEntry();
560: }
561:
562: /**
563: * Unset (unhook) a given EventSet, indicated by name, and remove its source representation.
564: *
565: * @param name EventSet name to unset.
566: */
567: public void unsetEventSet(String name) {
568: EventSet es = getEventSet(name);
569: if (es != null)
570: unsetEventSet(es);
571: }
572:
573: //--------------------------------------------------------------------------------------- Object
574:
575: /*
576: * @see org.netbeans.modules.visualweb.insync.beans.BeansNode#toString(java.lang.StringBuffer)
577: */
578: public void toString(StringBuffer sb) {
579: sb.append(" name:");
580: sb.append(getName());
581: sb.append(" props:");
582: Property[] props = getProperties();
583: for (int i = 0; i < props.length; i++)
584: sb.append(props[i].toString());
585: sb.append(" eventSets:");
586: EventSet[] eventSets = getEventSets();
587: for (int i = 0; i < eventSets.length; i++)
588: sb.append(eventSets[i].toString());
589: if (isParentCapable()) {
590: sb.append(" kids:");
591: Bean[] kids = getChildren();
592: for (int i = 0; i < kids.length; i++)
593: sb.append(kids[i].toString());
594: }
595: }
596:
597: /**
598: * If I return null, indicates I could not determine scope.
599: * "request", "session", "application"
600: * @return
601: */
602: public String getScope() {
603: if (unit.getModel() instanceof FacesModel) {
604: FacesModel facesModel = (FacesModel) unit.getModel();
605: ManagedBean.Scope scope = facesModel
606: .getManagedBeanEntryScope();
607: if (scope == null)
608: return null;
609: return scope.toString();
610: }
611: return null;
612: }
613:
614: public boolean shouldInsertCleanupEntry() {
615: String scope = getScope();
616: if (scope == null) {
617: return true;
618: }
619: if ("request".equals(scope)) {
620: return true;
621: }
622: return false;
623: }
624:
625: public List<String> getTypeParameterNames() {
626: return typeParameterNames;
627: }
628:
629: public boolean isGetterRequired() {
630: return CREATE_GETTER;
631: }
632:
633: public boolean isSetterRequired() {
634: return CREATE_SETTER;
635: }
636:
637: public boolean isInserted() {
638: return inserted;
639: }
640:
641: public void setInserted(boolean inserted) {
642: this.inserted = inserted;
643: }
644: }
|