0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.visualweb.insync.live;
0042:
0043: import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
0044: import java.awt.Image;
0045: import java.awt.datatransfer.DataFlavor;
0046: import java.awt.datatransfer.Transferable;
0047: import java.beans.BeanDescriptor;
0048: import java.beans.BeanInfo;
0049: import java.beans.Introspector;
0050: import java.io.IOException;
0051: import java.io.PrintWriter;
0052: import java.net.URL;
0053: import java.util.ArrayList;
0054: import java.util.Collection;
0055: import java.util.Collections;
0056: import java.util.HashMap;
0057: import java.util.IdentityHashMap;
0058: import java.util.Iterator;
0059: import java.util.List;
0060: import java.util.Map;
0061: import java.util.WeakHashMap;
0062:
0063: import javax.faces.component.UIComponent;
0064: import javax.faces.context.FacesContext;
0065: import javax.faces.el.ValueBinding;
0066:
0067: import org.openide.ErrorManager;
0068: import org.openide.util.NbBundle;
0069: import org.netbeans.modules.visualweb.extension.openide.util.Trace;
0070: import org.openide.util.datatransfer.ExTransferable;
0071: import org.openide.filesystems.FileObject;
0072: import org.openide.filesystems.FileStateInvalidException;
0073:
0074: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectUtils;
0075: import com.sun.rave.designtime.Constants;
0076: import com.sun.rave.designtime.Result;
0077: import com.sun.rave.designtime.DesignBean;
0078: import com.sun.rave.designtime.DesignInfo;
0079: import com.sun.rave.designtime.DesignContext;
0080: import com.sun.rave.designtime.ContextMethod;
0081: import com.sun.rave.designtime.Customizer2;
0082: import com.sun.rave.designtime.DesignEvent;
0083: import com.sun.rave.designtime.DesignProject;
0084: import com.sun.rave.designtime.DesignProperty;
0085: import com.sun.rave.designtime.Position;
0086: import com.sun.rave.designtime.event.DesignContextListener;
0087: import com.sun.rave.designtime.faces.FacesDesignContext;
0088: import com.sun.rave.designtime.faces.ResolveResult;
0089: import org.netbeans.modules.visualweb.insync.ParserAnnotation;
0090: import org.netbeans.modules.visualweb.insync.ResultHandler;
0091: import org.netbeans.modules.visualweb.insync.UndoEvent;
0092: import org.netbeans.modules.visualweb.insync.Unit;
0093: import org.netbeans.modules.visualweb.insync.Util;
0094: import org.netbeans.modules.visualweb.insync.beans.Bean;
0095: import org.netbeans.modules.visualweb.insync.beans.Naming;
0096: import org.netbeans.modules.visualweb.insync.beans.BeansUnit;
0097: import org.netbeans.modules.visualweb.insync.faces.FacesBean;
0098: import org.netbeans.modules.visualweb.insync.faces.FacesPageUnit;
0099: import org.netbeans.modules.visualweb.insync.faces.HtmlBean;
0100: import org.netbeans.modules.visualweb.insync.faces.MarkupBean;
0101: import org.netbeans.modules.visualweb.insync.markup.MarkupUnit;
0102: import org.netbeans.modules.visualweb.insync.models.FacesModel;
0103: import org.netbeans.modules.visualweb.insync.models.FacesModelSet;
0104: import org.netbeans.modules.visualweb.jsfsupport.container.RaveFacesContext; //import com.sun.rave.project.model.GenericItem;
0105: //import com.sun.rave.project.model.WebAppProject;
0106: import org.netbeans.modules.visualweb.api.designerapi.DesignerServiceHack;
0107: import org.netbeans.modules.web.jsf.api.facesmodel.ManagedBean;
0108:
0109: /**
0110: * @author Carl Quinn
0111: */
0112: public class LiveUnit implements Unit, DesignContext,
0113: FacesDesignContext {
0114:
0115: protected FacesModel model;
0116: protected BeansUnit sourceUnit;
0117: // protected GenericItem projItem;
0118: protected FileObject file;
0119:
0120: protected final IdentityHashMap liveBeanHash = new IdentityHashMap(); // instance => lbean map
0121: protected final ArrayList liveBeanList = new ArrayList(); // lbean list, no specific order
0122: protected final SourceLiveRoot rootContainer;
0123:
0124: protected boolean itemAffected; // flag to signal an item change event is needed after
0125:
0126: ContextMethodHelper contextMethodHelper; //Helper class which provides the ContextMethod API implementation
0127: protected boolean hasResurectedSinceInstantiated;
0128:
0129: //--------------------------------------------------------------------------------- Construction
0130:
0131: /**
0132: * Construct an BeansUnit from an existing source file
0133: * @param model
0134: * @param sourceUnit
0135: * @param file
0136: */
0137: public LiveUnit(FacesModel model, BeansUnit sourceUnit,
0138: FileObject file) {
0139: this .model = model;
0140: this .sourceUnit = sourceUnit;
0141: this .rootContainer = new SourceLiveRoot(this );
0142: if (sourceUnit instanceof FacesPageUnit)
0143: this .rootContainer.setInstance(((FacesPageUnit) sourceUnit)
0144: .getViewRoot());
0145: this .file = file;
0146: contextMethodHelper = new ContextMethodHelper(this );
0147: //Trace.enableTraceCategory("insync.live");
0148: }
0149:
0150: /*
0151: * @see org.netbeans.modules.visualweb.insync.Unit#destroy()
0152: */
0153: public void destroy() {
0154: model = null;
0155: sourceUnit = null;
0156: this .rootContainer.setInstance(null);
0157: }
0158:
0159: //------------------------------------------------------------------------------------ Accessors
0160:
0161: /**
0162: * @return
0163: */
0164: public BeansUnit getBeansUnit() {
0165: return sourceUnit;
0166: }
0167:
0168: /**
0169: * @return
0170: */
0171: public FacesModel getModel() {
0172: return model;
0173: }
0174:
0175: /**
0176: * Get the DesignBean that is managing a given java source bean.
0177: * Note: this method is specific to BeansDesignBean
0178: * @return the DesignBean that is managing a given java source bean.
0179: */
0180: public DesignBean getDesignBean(Bean bean) {
0181: assert Trace.trace("insync.live", "LU.getDesignBean:" + bean);
0182: ArrayList lbeans = getBeansList();
0183: for (int i = 0, n = lbeans.size(); i < n; i++) {
0184: Object o = lbeans.get(i);
0185: if (o instanceof BeansDesignBean) {
0186: BeansDesignBean lbean = (BeansDesignBean) o;
0187: //assert Trace.trace("insync.live", " LU.getDesignBean checking:" + lbean);
0188: if (lbean.bean == bean)
0189: return lbean;
0190: }
0191: }
0192: return null;
0193: }
0194:
0195: /*
0196: * @see com.sun.rave.designtime.DesignContext#getBeanByName(java.lang.String)
0197: */
0198: public DesignBean getBeanByName(String name) {
0199: assert Trace.trace("insync.live", "LU.getDesignBean:" + name);
0200: int n = liveBeanList.size();
0201: //!CQ should use a hash here somehow... would need to flush or update on name changes
0202: for (int i = 0; i < n; i++) {
0203: DesignBean lb = (DesignBean) liveBeanList.get(i);
0204: if (lb.getInstanceName().equals(name))
0205: return lb;
0206: }
0207: return null;
0208: }
0209:
0210: /*
0211: * The live beans may have been replaced during a sync, since lookFor
0212: * was created.
0213: * So find the equivalent one to lookFor.
0214: */
0215: public DesignBean getBeanEquivalentTo(DesignBean lookFor) {
0216: if (lookFor == null) {
0217: return null;
0218: }
0219:
0220: // #102260 The bean is still alive, return it immediately.
0221: if (liveBeanList.contains(lookFor)) {
0222: return lookFor;
0223: }
0224:
0225: // XXX This is not fully working solution.
0226: // I-m using name here, but that may not be good enough. What
0227: // if the bean is in a sub page ? May need to do some hierarchy
0228: // based lookup, but for now this will do
0229: return getBeanByName(lookFor.getInstanceName());
0230: }
0231:
0232: /*
0233: * @see com.sun.rave.designtime.DesignContext#addResource(java.net.URL, boolean)
0234: */
0235: public String addResource(URL resource, boolean copy)
0236: throws IOException {
0237: String updatedRes = null;
0238: updatedRes = JsfProjectUtils.addResource(file, resource, copy);
0239: return updatedRes;
0240: }
0241:
0242: /*
0243: * @see com.sun.rave.designtime.DesignContext#resolveResource(java.lang.String)
0244: */
0245: public URL resolveResource(String resource) {
0246: try {
0247: URL fileUrl = file.getURL();
0248: return new URL(fileUrl, resource);
0249: } catch (java.net.MalformedURLException mue) {
0250: ErrorManager.getDefault().notify(
0251: ErrorManager.INFORMATIONAL, mue);
0252: } catch (FileStateInvalidException fsie) {
0253: ErrorManager.getDefault().notify(
0254: ErrorManager.INFORMATIONAL, fsie);
0255: }
0256: return null;
0257: }
0258:
0259: //---------------------------------------------------------------------------------- DisplayInfo
0260:
0261: /*
0262: * @see com.sun.rave.designtime.DisplayInfo#getDisplayName()
0263: */
0264: public String getDisplayName() {
0265: String beanName = sourceUnit.getBeanName();
0266: if (beanName != null) {
0267: return beanName.replace('$', '/');
0268: }
0269: return null;
0270: }
0271:
0272: /*
0273: * @see com.sun.rave.designtime.DisplayInfo#getDescription()
0274: */
0275: public String getDescription() {
0276: return getDisplayName();
0277: }
0278:
0279: /*
0280: * @see com.sun.rave.designtime.DisplayInfo#getLargeIcon()
0281: */
0282: public Image getLargeIcon() {
0283: return null;
0284: }
0285:
0286: /*
0287: * @see com.sun.rave.designtime.DisplayInfo#getSmallIcon()
0288: */
0289: public Image getSmallIcon() {
0290: return null;
0291: }
0292:
0293: /*
0294: * @see com.sun.rave.designtime.DisplayInfo#getHelpKey()
0295: */
0296: public String getHelpKey() {
0297: return null;
0298: }
0299:
0300: //----------------------------------------------------------------------------------- Unit Input
0301:
0302: /*
0303: * @see org.netbeans.modules.visualweb.insync.Unit#getState()
0304: */
0305: public State getState() {
0306: // As good a guess as any as to what the state should be ?
0307: if (sourceUnit == null) {
0308: return Unit.State.BUSTED;
0309: }
0310: return sourceUnit.getState();
0311: }
0312:
0313: /*
0314: * @see org.netbeans.modules.visualweb.insync.Unit#getErrors()
0315: */
0316: public ParserAnnotation[] getErrors() {
0317: return sourceUnit.getErrors();
0318: }
0319:
0320: /*
0321: * @see org.netbeans.modules.visualweb.insync.Unit#readLock()
0322: */
0323: public void readLock() {
0324: sourceUnit.readLock();
0325: }
0326:
0327: /*
0328: * @see org.netbeans.modules.visualweb.insync.Unit#readUnlock()
0329: */
0330: public void readUnlock() {
0331: sourceUnit.readUnlock();
0332: }
0333:
0334: /*
0335: * @see org.netbeans.modules.visualweb.insync.Unit#sync()
0336: */
0337: public boolean sync() {
0338: assert Trace.trace("insync.live", "LU.sync");
0339: boolean wasBusted = getState().isBusted();
0340: // rebuild the live instances only when the source and hence models below change
0341: boolean synced = sourceUnit.sync();
0342: if (!hasResurectedSinceInstantiated) {
0343: hasResurectedSinceInstantiated = true;
0344: synced = true;
0345: }
0346: if (synced) {
0347: resurrect();
0348: }
0349: if (synced || wasBusted != getState().isBusted()) {
0350: fireContextChanged();
0351: }
0352: return synced;
0353: }
0354:
0355: /**
0356: * Add a new live bean to our containers & parent hierarchy.
0357: *
0358: * @param slbean
0359: * @param slparent
0360: * @param pos
0361: */
0362: private void addDesignBean(SourceDesignBean slbean,
0363: SourceDesignBean slparent, Position pos) {
0364: liveBeanList.add(slbean);
0365: Object instance = slbean.getInstance();
0366: if (instance != null && instance != Boolean.TRUE
0367: && instance != Boolean.FALSE) {
0368: liveBeanHash.put(instance, slbean);
0369: }
0370: if (slparent != null)
0371: slparent.addLiveChild(slbean, pos);
0372: // registerProjectListener(slbean);
0373: }
0374:
0375: /**
0376: * Resurrect a live bean from its source bean, including all the child beans.
0377: *
0378: * @param slparent
0379: * @param bean
0380: */
0381: private void resurrectDesignBean(SourceDesignBean slparent,
0382: Bean bean) {
0383: try {
0384: // Get the class and beaninfo objects
0385: BeanInfo beanInfo = bean.getBeanInfo();
0386: Class beanClass = beanInfo.getBeanDescriptor()
0387: .getBeanClass();
0388: DesignInfo liveBeanInfo = getDesignInfo(beanClass,
0389: getModel().getFacesModelSet()
0390: .getProjectClassLoader());
0391:
0392: // Perform the instance creation and parenting
0393: // Eat any exceptions and continue without an instance... !CQ can we really?
0394: Object instance = sourceUnit.instantiateBean(beanClass);
0395: if (instance != null) {
0396: // immediate parent may NOT be the desired instance parent, so walk up until accepted
0397: for (DesignBean slp = slparent; slp != null
0398: && !bean.performInstanceParenting(instance, slp
0399: .getInstance(), null); slp = slp
0400: .getBeanParent())
0401: ;
0402: }
0403:
0404: //!CQ this chunk is specific to BeansDesignBean
0405: SourceDesignBean slbean = instantiateDesignBean(beanInfo,
0406: liveBeanInfo, slparent, instance, bean);
0407:
0408: addDesignBean(slbean, slparent, null);
0409: if (slbean.isContainer()) {
0410: Bean[] beankids = bean.getChildren();
0411: for (int i = 0; i < beankids.length; i++) {
0412: // Sanity check
0413: assert getDesignBean(beankids[i]) == null : "LU.resurrectBean "
0414: + bean
0415: + " PROBLEM: child already resurrected:"
0416: + beankids[i];
0417: resurrectDesignBean(slbean, beankids[i]);
0418: }
0419: }
0420: // No need to call recursive setReady() method here as the resurrectDesignBean() is
0421: // going through the beans recursively
0422: slbean.ready = true;
0423: } catch (Exception e) {
0424: assert Trace.trace("insync.live",
0425: "LU.read: Bean type uninstantiable: "
0426: + bean.getType());
0427: //assert Trace.trace("insync.live", e);
0428: }
0429: }
0430:
0431: // static int count;
0432: /**
0433: * Rebuild the entire live bean tree from underlying source beans
0434: */
0435: void resurrect() {
0436: // System.out.println(Thread.currentThread());
0437: // System.out.println("count: " + count++);
0438: // new Exception().printStackTrace();
0439: // run through any old beans and let them cleanup their instances
0440: ClassLoader oldContextClassLoader = Thread.currentThread()
0441: .getContextClassLoader();
0442: try {
0443: Thread.currentThread().setContextClassLoader(
0444: getBeansUnit().getClassLoader());
0445: for (Iterator i = liveBeanList.iterator(); i.hasNext();) {
0446: SourceDesignBean slb = (SourceDesignBean) i.next();
0447: // unregisterProjectListener(slb);
0448: slb.invokeCleanupMethod();
0449: }
0450:
0451: // start fresh
0452: liveBeanHash.clear();
0453: liveBeanList.clear();
0454:
0455: // always add our generic rootContainer, cleaning it up first.
0456: rootContainer.clearLiveChildren();
0457: // Make sure the faces context is initialized properly to allow resolvers to have access to the correct context
0458: setFacesContextCurrentInstance();
0459: try {
0460: // retrieve the instance to go with the root...
0461: rootContainer.setInstance(sourceUnit.getRootInstance());
0462:
0463: // Update rootContainer's bean?: unit.sourceUnit.getHostClass();
0464: addDesignBean(rootContainer, null, null);
0465:
0466: // scan source beans and create matching live wrappers and bind them
0467: //!CQ this chunk is specific to BeansDesignBean
0468: Bean[] beans = sourceUnit.getBeans();
0469: assert Trace.trace("insync.live",
0470: "LU.read: resurrecting " + beans.length
0471: + " beans");
0472: for (int i = 0; i < beans.length; i++) {
0473: // skip if has a parent--will be done by parent when it is resurrected
0474: if (beans[i].getParent() == null)
0475: resurrectDesignBean(rootContainer, beans[i]);
0476: }
0477:
0478: // run accross each new live bean and load its properties & fire its created events
0479: for (Iterator i = liveBeanList.iterator(); i.hasNext();) {
0480: SourceDesignBean slbean = (SourceDesignBean) i
0481: .next();
0482: slbean.loadProperties();
0483: //slbean.loadEvents(); //!CQ why not these too?
0484: //fireDesignBeanCreated(slbean); //!CQ not really creating, just reconstructing
0485: }
0486: fireContextChanged(); //!CQ is this a good one for notifying of a reconstruct?
0487: } catch (Exception exc) {
0488: exc.printStackTrace();
0489: } finally {
0490: resetFacesContextCurrentInstance();
0491: }
0492: } catch (Exception exc) {
0493: exc.printStackTrace();
0494: } finally {
0495: Thread.currentThread().setContextClassLoader(
0496: oldContextClassLoader);
0497: resetFacesContextCurrentInstance();
0498: }
0499: }
0500:
0501: //---------------------------------------------------------------------------------- Unit Output
0502:
0503: /*
0504: * @see org.netbeans.modules.visualweb.insync.Unit#writeLock(org.netbeans.modules.visualweb.insync.UndoEvent)
0505: */
0506: public void writeLock(UndoEvent event) {
0507: sourceUnit.writeLock(event);
0508: }
0509:
0510: /*
0511: * @see org.netbeans.modules.visualweb.insync.Unit#writeUnlock(org.netbeans.modules.visualweb.insync.UndoEvent)
0512: */
0513: public boolean writeUnlock(UndoEvent event) {
0514: boolean unlocked = sourceUnit.writeUnlock(event);
0515: if (unlocked) {
0516: if (itemAffected) {
0517: itemAffected = false;
0518: getModel().fireModelChanged();
0519: }
0520: flushContextData(); //!CQ this may be getting called way too much
0521: }
0522: return unlocked;
0523: }
0524:
0525: /*
0526: * @see org.netbeans.modules.visualweb.insync.Unit#isWriteLocked()
0527: */
0528: public boolean isWriteLocked() {
0529: return sourceUnit.isWriteLocked();
0530: }
0531:
0532: /**
0533: *
0534: */
0535: public void dumpTo(PrintWriter w) {
0536: //TODO
0537: }
0538:
0539: //---------------------------------------------------------------------------------- DesignContext
0540:
0541: /*
0542: * @see com.sun.rave.designtime.DesignContext#canCreateBean(java.lang.String, com.sun.rave.designtime.DesignBeanContainer)
0543: */
0544: public boolean canCreateBean(String type, DesignBean parent,
0545: Position pos) {
0546: ClassLoader oldContextClassLoader = Thread.currentThread()
0547: .getContextClassLoader();
0548: try {
0549: Thread.currentThread().setContextClassLoader(
0550: getBeansUnit().getClassLoader());
0551: Bean beanParent = parent instanceof BeansDesignBean ? ((BeansDesignBean) parent)
0552: .getBean()
0553: : null;
0554: BeanInfo bi = sourceUnit.getBeanInfo(type);
0555: return bi != null && canCreateAsChildOf(parent, bi, type)
0556: && canCreateChild(parent, type)
0557: && sourceUnit.canCreateBean(bi, beanParent);
0558: } finally {
0559: Thread.currentThread().setContextClassLoader(
0560: oldContextClassLoader);
0561: }
0562: }
0563:
0564: /**
0565: * Check whether the given type can be created as a child of the given parent.
0566: * That's true by default, unless either the parent or the child refuses (through
0567: * checks in their DesignInfos.)
0568: *
0569: * @param parent The parent DesignBean
0570: * @param type The class of the potential child
0571: * @return Whether the child can be adopted by this parent
0572: */
0573: private boolean canCreateChild(DesignBean parent, String type) {
0574: if (parent == null) {
0575: return true;
0576: }
0577: try {
0578: Class typeClass = sourceUnit.getBeanClass(type);
0579: DesignInfo parentInfo = parent.getDesignInfo();
0580: if (parentInfo != null
0581: && !parentInfo.acceptChild(parent, null, typeClass)) {
0582: return false;
0583: }
0584: DesignInfo childInfo = getDesignInfo(typeClass, getModel()
0585: .getFacesModelSet().getProjectClassLoader());
0586: if (childInfo != null
0587: && !childInfo.acceptParent(parent, null, typeClass)) {
0588: return false;
0589: }
0590: } catch (ClassNotFoundException cnfe) {
0591: org.openide.ErrorManager.getDefault().log(
0592: "Couldn't find class " + type);
0593: }
0594: // No evidence to the contrary
0595: return true;
0596: }
0597:
0598: /**
0599: * Check whether the given type can be created as a child of the given parent. That's true by
0600: * default, unless the child specifies a particular set of eligible parents. If so,
0601: * only subtypes of the specified parents will be accepted as a parent for this component.
0602: */
0603: private boolean canCreateAsChildOf(DesignBean parent, BeanInfo bi,
0604: String type) {
0605: if (bi == null)
0606: return true;
0607:
0608: // Check specific "allowed parent" list
0609: BeanDescriptor bd = bi.getBeanDescriptor();
0610: if (bd == null) {
0611: return true;
0612: }
0613: Object o = null; //bd.getValue(Constants.BeanDescriptor.REQUIRED_PARENT_TYPES);
0614: if (o != null && o instanceof String[]) {
0615: Class parentClass = UIComponent.class;
0616: if (parent == null) {
0617: if (sourceUnit instanceof FacesPageUnit) {
0618: parent = getDesignBean(((FacesPageUnit) sourceUnit)
0619: .getDefaultParent());
0620: }
0621: }
0622: if (parent != null) {
0623: parentClass = parent.getInstance().getClass();
0624: }
0625: String[] allowed = (String[]) o;
0626: boolean found = false;
0627: for (int i = 0; i < allowed.length; i++) {
0628: try {
0629: Class c = sourceUnit.getBeanClass(allowed[i]);
0630: if (c.isAssignableFrom(parentClass)) {
0631: found = true;
0632: break;
0633: }
0634: } catch (ClassNotFoundException cnfe) {
0635: org.openide.ErrorManager.getDefault()
0636: .log(
0637: "Couldn't find allowed class "
0638: + allowed[i]);
0639: }
0640: }
0641: // Specified required parents but no eligible was found
0642: if (!found) {
0643: return false;
0644: }
0645: }
0646: return true;
0647: }
0648:
0649: /**
0650: * Perform the actual construction of the DesignBean implementation, including parent wiring for
0651: * both the DesignBean hierarchy as well as the instance hierarchy
0652: *
0653: * @param beanClass
0654: * @param beanInfo
0655: * @param liveBeanInfo
0656: * @param parent
0657: * @param facet
0658: * @param pos
0659: * @return
0660: */
0661: protected SourceDesignBean newDesignBean(Class beanClass,
0662: BeanInfo beanInfo, DesignInfo liveBeanInfo,
0663: DesignBean parent, String facet, Position pos,
0664: String instanceName) {
0665: if (instanceName == null) {
0666: // Retrieve the optional suggested instance name base
0667: Object instanceNameO = beanInfo.getBeanDescriptor()
0668: .getValue(Constants.BeanDescriptor.INSTANCE_NAME);
0669: instanceName = instanceNameO instanceof String ? (String) instanceNameO
0670: : null;
0671: }
0672:
0673: // Create the source representation for the live bean
0674: //!CQ this chunk is specific to BeansDesignBean
0675: Bean beanParent = parent instanceof BeansDesignBean ? ((BeansDesignBean) parent)
0676: .getBean()
0677: : null;
0678: Bean bean = sourceUnit.addBean(beanInfo, beanParent,
0679: instanceName, facet, pos);
0680:
0681: // Readjust the parent if the source layer did. Especially filling in for a null.
0682: if (bean.getParent() != beanParent) {
0683: beanParent = bean.getParent();
0684: parent = getDesignBean(beanParent);
0685: }
0686:
0687: // Perform the instance creation and parenting
0688: // Eat any exceptions and continue without an instance...
0689: Object instance = null;
0690: if (parent == null)
0691: parent = rootContainer;
0692: try {
0693: instance = sourceUnit.instantiateBean(beanClass);
0694: if (instance != null)
0695: // immediate parent may NOT be the desired instance parent, so walk up until accepted
0696: for (DesignBean slp = parent; slp != null
0697: && !bean.performInstanceParenting(instance, slp
0698: .getInstance(), pos); slp = slp
0699: .getBeanParent())
0700: ;
0701: } catch (Exception e) {
0702: assert Trace.trace("insync.live", "Caught " + e
0703: + " instantiating " + beanClass.getName());
0704: e.printStackTrace();
0705: }
0706:
0707: // Construct the actual DesignBean--either a leaf or a container implementation
0708: // Add it to our containers and wire up parentage
0709: //!CQ this chunk is specific to BeansDesignBean
0710: SourceDesignBean slparent = (SourceDesignBean) parent;
0711: SourceDesignBean slbean = instantiateDesignBean(beanInfo,
0712: liveBeanInfo, slparent, instance, bean);
0713: addDesignBean(slbean, slparent, pos);
0714: return slbean;
0715: }
0716:
0717: protected BeansDesignBean instantiateDesignBean(BeanInfo beanInfo,
0718: DesignInfo liveBeanInfo, SourceDesignBean parent,
0719: Object instance, Bean bean) {
0720:
0721: if (bean instanceof FacesBean) {
0722: return new FacesDesignBean(this , beanInfo, liveBeanInfo,
0723: parent, instance, (FacesBean) bean);
0724: }
0725: if (bean instanceof MarkupBean) {
0726: return new MarkupDesignBean(this , beanInfo, liveBeanInfo,
0727: parent, instance, (MarkupBean) bean);
0728: }
0729: if (bean.getTypeParameterNames() != null) {
0730: return new BeansDesignBeanExt(this , beanInfo, liveBeanInfo,
0731: parent, instance, bean);
0732: }
0733:
0734: return new BeansDesignBean(this , beanInfo, liveBeanInfo,
0735: parent, instance, bean);
0736: }
0737:
0738: /**
0739: * Perform the actual construction of the DesignBean implementation, including parent wiring for
0740: * both the DesignBean hierarchy as well as the instance hierarchy
0741: *
0742: * @param type
0743: * @param parent
0744: * @param facet
0745: * @param pos
0746: * @return
0747: * @throws ClassNotFoundException
0748: */
0749: protected SourceDesignBean newDesignBean(String type,
0750: DesignBean parent, String facet, Position pos,
0751: String instanceName) throws ClassNotFoundException {
0752: Class beanClass = sourceUnit.getBeanClass(type);
0753: if (beanClass != null) {
0754: BeanInfo beanInfo = BeansUnit.getBeanInfo(beanClass,
0755: getModel().getFacesModelSet()
0756: .getProjectClassLoader());
0757: if (beanInfo != null) {
0758: DesignInfo liveBeanInfo = getDesignInfo(beanClass,
0759: getModel().getFacesModelSet()
0760: .getProjectClassLoader());
0761: return newDesignBean(beanClass, beanInfo, liveBeanInfo,
0762: parent, facet, pos, instanceName);
0763: }
0764: }
0765: return null;
0766: }
0767:
0768: /**
0769: * Creates an array of DesignBeans given a clipboard image, parent and facet spec.
0770: *
0771: * @param image
0772: * @param parent
0773: * @param pos
0774: * @return
0775: */
0776: protected SourceDesignBean[] createDesignBeans(ClipImage image,
0777: DesignBean parent, Position pos) {
0778: // create all of the raw beans
0779: for (int i = 0; i < image.beans.length; i++)
0780: createDesignBean(image.beans[i], parent, pos); //!CQ maybe skip nulls
0781: // now populate their properties
0782: for (int i = 0; i < image.beans.length; i++)
0783: if (image.beans[i].bean != null
0784: && image.beans[i].props != null)
0785: populateDesignBean(image.beans[i]);
0786: // count how many actually got created
0787: int count = 0;
0788: for (int i = 0; i < image.beans.length; i++)
0789: if (image.beans[i].bean != null)
0790: count++;
0791: // return an array of just the good ones
0792: SourceDesignBean[] slbs = new SourceDesignBean[count];
0793: for (int i = 0, c = 0; i < image.beans.length; i++)
0794: if (image.beans[i].bean != null)
0795: slbs[c++] = image.beans[i].bean;
0796: // strip away all of the temp bean refs in the image
0797: image.strip();
0798: //fireContextChanged(); //!CQ now firing beanCreated from paste
0799: return slbs;
0800: }
0801:
0802: /**
0803: * Creates a DesignBean given a clipboard image, parent and facet spec.
0804: *
0805: * @param image
0806: * @param parent
0807: * @param pos
0808: * @return
0809: */
0810: protected SourceDesignBean createDesignBean(
0811: SourceDesignBean.ClipImage image, DesignBean parent,
0812: Position pos) {
0813: try {
0814: String name = Naming.getBaseName(image.instanceName);
0815: image.bean = newDesignBean(image.type.getName(), parent,
0816: image.facetName, pos, name);
0817: if (image.bean != null) {
0818: // do children also...
0819: if (image.children != null) {
0820: for (int j = 0; j < image.children.length; j++)
0821: createDesignBean(image.children[j], image.bean,
0822: null);
0823: }
0824: }
0825: } catch (ClassNotFoundException e) {
0826: e.printStackTrace();
0827: }
0828:
0829: return image.bean;
0830: }
0831:
0832: /**
0833: * Populate the properties of a DesignBean given a clipboard image
0834: *
0835: * @param image
0836: */
0837: protected void populateDesignBean(SourceDesignBean.ClipImage image) {
0838: if (image.props != null) {
0839: for (int j = 0; j < image.props.length; j++) {
0840: SourceDesignProperty.ClipImage pimage = image.props[j];
0841: SourceDesignProperty slp = (SourceDesignProperty) image.bean
0842: .getProperty(pimage.name);
0843: if (slp != null) {
0844: Object val = pimage.value instanceof SourceDesignBean.ClipImage ? ((SourceDesignBean.ClipImage) pimage.value).bean
0845: : pimage.value;
0846: if (val instanceof ValueBinding) {
0847: try {
0848: //val = ((ValueBinding)val).getValue(getFacesContext());
0849: String valSrc = ((ValueBinding) val)
0850: .getExpressionString();
0851: slp.setValueSource(valSrc);
0852: } catch (Exception e) {
0853: val = null;
0854: }
0855: } else if (val != null)
0856: slp.setValue(val);
0857: }
0858: }
0859: }
0860:
0861: if (image.events != null) {
0862: for (int j = 0; j < image.events.length; j++) {
0863: SourceDesignEvent.ClipImage eimage = image.events[j];
0864: SourceDesignEvent sle = (SourceDesignEvent) image.bean
0865: .getEvent(eimage.name);
0866: if (sle != null) {
0867: Object val = eimage.handler;
0868: if (val instanceof String) {
0869: sle.setHandlerName((String) val);
0870: }
0871: }
0872: }
0873: }
0874:
0875: // do children also...
0876: if (image.children != null) {
0877: for (int j = 0; j < image.children.length; j++)
0878: populateDesignBean(image.children[j]);
0879: }
0880: }
0881:
0882: /**
0883: * Creates a DesignBean given type, parent and facet spec. Gathers needed info and calls
0884: * newDesignBean within a write lock to do the work.
0885: *
0886: * @param type
0887: * @param parent
0888: * @param facet
0889: * @param pos
0890: * @return
0891: */
0892: protected SourceDesignBean createBeanOrFacet(String type,
0893: DesignBean parent, String facet, Position pos) {
0894: if (!canCreateBean(type, parent, pos))
0895: return null;
0896: UndoEvent event = null;
0897: SourceDesignBean slbean = null;
0898: try {
0899: String description = NbBundle.getMessage(LiveUnit.class,
0900: "CreateBean"); //NOI18N
0901: event = model.writeLock(description);
0902: slbean = newDesignBean(type, parent, facet, pos, null);
0903: } catch (Exception e) {
0904: e.printStackTrace();
0905: } finally {
0906: model.writeUnlock(event);
0907: }
0908: if (slbean != null) {
0909: fireBeanCreated(slbean);
0910: }
0911: return slbean;
0912: }
0913:
0914: /*
0915: * @see com.sun.rave.designtime.DesignContext#createBean(java.lang.String, com.sun.rave.designtime.DesignBeanContainer)
0916: */
0917: public DesignBean createBean(String type, DesignBean parent,
0918: Position pos) {
0919: ClassLoader oldContextClassLoader = Thread.currentThread()
0920: .getContextClassLoader();
0921: try {
0922: Thread.currentThread().setContextClassLoader(
0923: getBeansUnit().getClassLoader());
0924: return createBeanOrFacet(type, parent, null, pos);
0925: } finally {
0926: Thread.currentThread().setContextClassLoader(
0927: oldContextClassLoader);
0928: }
0929: }
0930:
0931: /*
0932: * @see com.sun.rave.designtime.DesignContext#canMoveBean(com.sun.rave.designtime.DesignBean, com.sun.rave.designtime.DesignBean, com.sun.rave.designtime.Position)
0933: */
0934: public boolean canMoveBean(DesignBean lbean, DesignBean newParent,
0935: Position pos) {
0936: // Prevent moving to root bean. The child beans can be added to the root bean only programatically.
0937: if (newParent instanceof SourceLiveRoot) {
0938: return false;
0939: }
0940: ClassLoader oldContextClassLoader = Thread.currentThread()
0941: .getContextClassLoader();
0942: try {
0943: Thread.currentThread().setContextClassLoader(
0944: getBeansUnit().getClassLoader());
0945: // See if the target position is accepted by the involved components
0946: Class typeClass = lbean.getInstance().getClass();
0947: DesignInfo parentInfo = newParent.getDesignInfo();
0948: if (parentInfo != null
0949: && !parentInfo.acceptChild(newParent, lbean,
0950: typeClass)) {
0951: return false;
0952: }
0953: DesignInfo childInfo = lbean.getDesignInfo();
0954: if (childInfo != null
0955: && !childInfo.acceptParent(newParent, lbean,
0956: typeClass)) {
0957: return false;
0958: }
0959:
0960: return lbean instanceof SourceDesignBean
0961: && newParent.isContainer()
0962: && ((SourceDesignBean) lbean).unit == this
0963: && ((SourceDesignBean) newParent).unit == this ;
0964: //!CQ TODO more checks, & relax cross-unit moving
0965: } finally {
0966: Thread.currentThread().setContextClassLoader(
0967: oldContextClassLoader);
0968: }
0969: }
0970:
0971: /*
0972: * @see com.sun.rave.designtime.DesignContext#moveDesignBean(com.sun.rave.designtime.DesignBean, com.sun.rave.designtime.DesignBeanContainer)
0973: */
0974: public boolean moveBean(DesignBean lbean, DesignBean newParent,
0975: Position pos) {
0976: if (!canMoveBean(lbean, newParent, pos))
0977: return false;
0978:
0979: // Looks OK to move. Gather info
0980: SourceDesignBean slbean = (SourceDesignBean) lbean;
0981: Object instance = slbean.getInstance();
0982: Bean bean = ((BeansDesignBean) lbean).bean; //!CQ assuming a Beans live bean for now
0983: SourceDesignBean oldparent = (SourceDesignBean) slbean
0984: .getBeanParent();
0985:
0986: UndoEvent event = null;
0987: try {
0988: String description = NbBundle.getMessage(LiveUnit.class,
0989: "MoveBean"); //NOI18N
0990: event = model.writeLock(description);
0991:
0992: // TODO - suppress firing of removes and additions here, should
0993: // only have a single "moved" at the end
0994: oldparent.removeLiveChild(slbean);
0995: if (instance != null)
0996: bean.performInstanceUnparenting(instance, oldparent
0997: .getInstance());
0998: sourceUnit.moveBean(bean,
0999: ((BeansDesignBean) newParent).bean, pos);
1000: ((SourceDesignBean) newParent).addLiveChild(slbean, pos);
1001: if (instance != null)
1002: bean.performInstanceParenting(instance, newParent
1003: .getInstance(), pos);
1004: } finally {
1005: model.writeUnlock(event);
1006: }
1007: fireBeanMoved(slbean, oldparent, pos);
1008: return true;
1009: }
1010:
1011: /*
1012: * Reorder the children beans.
1013: */
1014: public boolean reorderBeanChidren(DesignBean parentBean, int[] perm) {
1015: if (perm == null || perm.length <= 1) {
1016: return false;
1017: }
1018:
1019: SourceDesignBean parentSourceBean = (SourceDesignBean) parentBean;
1020:
1021: String description = NbBundle.getMessage(LiveUnit.class,
1022: "ReorderBeans"); //NOI18N
1023: UndoEvent event = model.writeLock(description);
1024: try {
1025: // Save the original order
1026: DesignBean[] sourceDesignBeans = parentSourceBean
1027: .getChildBeans();
1028:
1029: for (int i = 0; i < perm.length; i++) {
1030: // Move if needed
1031: if (i != perm[i]) {
1032: moveBean(sourceDesignBeans[i], parentBean,
1033: new Position(perm[i]));
1034: }
1035: }
1036: } finally {
1037: model.writeUnlock(event);
1038: }
1039: parentSourceBean.fireDesignBeanChanged();
1040: return true;
1041: }
1042:
1043: static final String FlavorMime = "application/x-creator-components;class="
1044: + //NOI18N
1045: ClipImage.class.getName();
1046:
1047: /**
1048: * Clipboard image for a whole set of cut/copied SourceDesignBeans.
1049: * !TODO should merge this with BeanCreateInfo and BeanCreateInfoSet
1050: * @author cquinn
1051: */
1052: public static class ClipImage {
1053:
1054: SourceDesignBean.ClipImage[] beans;
1055:
1056: public static SourceDesignBean.ClipImage find(
1057: SourceDesignBean.ClipImage[] domain, Object bean) {
1058: for (int i = 0; i < domain.length; i++) {
1059: if (domain[i].bean.getInstance() == bean) {
1060: return domain[i];
1061: } else if (domain[i].children != null) {
1062: SourceDesignBean.ClipImage ci = find(
1063: domain[i].children, bean);
1064: if (ci != null)
1065: return ci;
1066: }
1067: }
1068: return null;
1069: }
1070:
1071: public String[] getTypes() {
1072: String[] types = new String[beans.length];
1073: for (int i = 0; i < beans.length; i++)
1074: types[i] = beans[i].type.getName();
1075: return types;
1076: }
1077:
1078: /**
1079: * Walk target bean list and point property cross references back into image
1080: */
1081: private void fixup(SourceDesignBean.ClipImage[] targtbeans) {
1082: for (int i = 0; i < targtbeans.length; i++) {
1083: SourceDesignBean.ClipImage beanim = targtbeans[i];
1084: if (beanim.props != null) {
1085: for (int j = 0; j < beanim.props.length; j++) {
1086: SourceDesignProperty.ClipImage propim = beanim.props[j];
1087: SourceDesignBean.ClipImage ci = find(beans,
1088: propim.value);
1089: if (ci != null)
1090: propim.value = ci;
1091: }
1092: }
1093: if (beanim.children != null)
1094: fixup(beanim.children);
1095: }
1096: }
1097:
1098: /**
1099: * Walk target bean list and strip temporary live bean pointers
1100: */
1101: private static void strip(
1102: SourceDesignBean.ClipImage[] targtbeans) {
1103: for (int i = 0; i < targtbeans.length; i++) {
1104: targtbeans[i].bean = null;
1105: if (targtbeans[i].children != null)
1106: strip(targtbeans[i].children);
1107: }
1108: }
1109:
1110: /**
1111: *
1112: */
1113: void fixup() {
1114: fixup(beans);
1115: }
1116:
1117: /**
1118: *
1119: */
1120: void strip() {
1121: strip(beans);
1122: }
1123:
1124: /*
1125: * @see java.lang.Object#toString()
1126: */
1127: public String toString() {
1128: StringBuffer sb = new StringBuffer();
1129: sb.append("[Context.ClipImage beans=");
1130: for (int i = 0; i < beans.length; i++)
1131: beans[i].toString(sb);
1132: sb.append("]");
1133: return sb.toString();
1134: }
1135: }
1136:
1137: static final DataFlavor flavor = new DataFlavor(FlavorMime,
1138: NbBundle.getMessage(LiveUnit.class, "Components")); //NOI18N
1139:
1140: // can pass in ClassLoader too if useful
1141: /*
1142: * @see com.sun.rave.designtime.DesignContext#copyBeans(com.sun.rave.designtime.DesignBean[])
1143: */
1144: public Transferable copyBeans(DesignBean[] beans) {
1145:
1146: final ClipImage clip = new ClipImage();
1147: clip.beans = new SourceDesignBean.ClipImage[beans.length];
1148: for (int i = 0; i < beans.length; i++)
1149: clip.beans[i] = ((SourceDesignBean) beans[i])
1150: .getClipImage();
1151: clip.fixup();
1152: clip.strip();
1153:
1154: Transferable transferable = new ExTransferable.Single(flavor) {
1155: public Object getData() {
1156: return clip;
1157: }
1158: };
1159: return transferable;
1160: }
1161:
1162: /*
1163: * @see com.sun.rave.designtime.DesignContext#pasteBeans(java.awt.datatransfer.Transferable, com.sun.rave.designtime.DesignBean, com.sun.rave.designtime.Position)
1164: */
1165: public DesignBean[] pasteBeans(Transferable persistData,
1166: DesignBean parent, Position pos) {
1167: UndoEvent event = null;
1168: DesignBean[] lbeans = null;
1169: try {
1170: String description = NbBundle.getMessage(LiveUnit.class,
1171: "PasteBean"); //NOI18N
1172: event = model.writeLock(description);
1173:
1174: if (persistData != null) {
1175: DataFlavor[] df = persistData.getTransferDataFlavors();
1176: if (df == null)
1177: return null;
1178: try {
1179: for (int dfi = 0; dfi < df.length; dfi++) {
1180: //Log.err.log("Flavor " + i + " is " + df[i]);
1181: //Log.err.log("mimetype is " + df[i].getMimeType());
1182: if (df[dfi].isMimeTypeEqual(FlavorMime)) { //NOI18N
1183: Object data = persistData
1184: .getTransferData(df[dfi]);
1185: if (data instanceof ClipImage)
1186: // perform the actual paste operation
1187: lbeans = createDesignBeans(
1188: (ClipImage) data, parent, pos);
1189: break; // done: either got it, or clipboard was funky
1190: }
1191: }
1192: } catch (Exception e) {
1193: ErrorManager.getDefault().notify(e);
1194: }
1195: }
1196: } finally {
1197: model.writeUnlock(event);
1198: }
1199: if (lbeans != null) {
1200: for (int i = 0; i < lbeans.length; i++) {
1201: fireBeanCreated(lbeans[i]);
1202: }
1203: for (int i = 0; i < lbeans.length; i++) {
1204: getModel().beanPasted(lbeans[i]);
1205: }
1206: }
1207: return lbeans;
1208: }
1209:
1210: /**
1211: * Called during deletion to remove the bean from its parent & remove all the bean's persistence
1212: * source
1213: *
1214: * @param lbean The bean to remove from all containers.
1215: */
1216: protected void removeBean(DesignBean lbean) {
1217: assert Trace.trace("insync.live", "LU.removeDesignBean "
1218: + lbean);
1219: Object instance = lbean.getInstance();
1220: liveBeanHash.remove(instance);
1221: liveBeanList.remove(lbean);
1222: SourceDesignBean lparent = (SourceDesignBean) lbean
1223: .getBeanParent();
1224: lparent.removeLiveChild((SourceDesignBean) lbean);
1225:
1226: String name = lbean.getInstanceName();
1227: Bean bean = ((BeansDesignBean) lbean).bean;
1228: if (instance != null)
1229: bean.performInstanceUnparenting(instance, lparent
1230: .getInstance());
1231: sourceUnit.removeBean(bean);
1232: }
1233:
1234: /*
1235: * @see com.sun.rave.designtime.DesignContext#deleteBean(com.sun.rave.designtime.DesignBean)
1236: */
1237: public boolean deleteBean(DesignBean lbean) {
1238: ClassLoader oldContextClassLoader = Thread.currentThread()
1239: .getContextClassLoader();
1240: try {
1241: Thread.currentThread().setContextClassLoader(
1242: getBeansUnit().getClassLoader());
1243: if (lbean == rootContainer || lbean == null
1244: || !(lbean instanceof SourceDesignBean))
1245: return false;
1246: UndoEvent event = null;
1247: try {
1248: String description = NbBundle.getMessage(
1249: LiveUnit.class, "DeleteBean"); //NOI18N
1250: event = model.writeLock(description);
1251: SourceDesignBean slbean = (SourceDesignBean) lbean;
1252: if (slbean.isContainer()) {
1253: DesignBean[] lbeans = slbean.getChildBeans();
1254: for (int i = 0; i < lbeans.length; i++) {
1255: boolean ok = deleteBean(lbeans[i]);
1256: if (!ok)
1257: return false;
1258: }
1259: }
1260: // unregisterProjectListener(lbean);
1261: slbean.invokeCleanupMethod();
1262: removeBean(lbean);
1263: } finally {
1264: model.writeUnlock(event);
1265: }
1266: fireBeanDeleted(lbean);
1267: return true;
1268: } finally {
1269: Thread.currentThread().setContextClassLoader(
1270: oldContextClassLoader);
1271: }
1272: }
1273:
1274: // /** DesignBeans that implement DesignProjectListener should be
1275: // * registered as project listeners when created, and unregistered
1276: // * when tossed away.
1277: // */
1278: // private void unregisterProjectListener(DesignBean bean) {
1279: // if (bean.getDesignInfo() instanceof DesignProjectListener) {
1280: // DesignProjectListener listener = (DesignProjectListener)bean.getDesignInfo();
1281: // if (model.isActivated()) {
1282: // listener.contextDeactivated(this);
1283: // }
1284: // model.getFacesModelSet().removeDesignProjectListener(listener);
1285: // }
1286: // }
1287: //
1288: // /** DesignBeans that implement DesignProjectListener should be
1289: // * registered as project listeners when created, and unregistered
1290: // * when tossed away.
1291: // */
1292: // private void registerProjectListener(DesignBean bean) {
1293: // if (bean.getDesignInfo() instanceof DesignProjectListener) {
1294: // DesignProjectListener listener = (DesignProjectListener)bean.getDesignInfo();
1295: // if (model.isActivated()) {
1296: // listener.contextActivated(this);
1297: // }
1298: // model.getFacesModelSet().addDesignProjectListener(listener);
1299: // }
1300: // }
1301:
1302: /*
1303: * @see com.sun.rave.designtime.DesignContext#getBean(java.lang.Object)
1304: */
1305: public DesignBean getBeanForInstance(Object instance) {
1306: return (DesignBean) liveBeanHash.get(instance);
1307: }
1308:
1309: /*
1310: * @see com.sun.rave.designtime.DesignContext#getRootContainer()
1311: */
1312: public DesignBean getRootContainer() {
1313: return rootContainer;
1314: }
1315:
1316: /*
1317: * @see com.sun.rave.designtime.DesignContext#getBeans()
1318: */
1319: public DesignBean[] getBeans() {
1320: return (DesignBean[]) liveBeanList
1321: .toArray(new DesignBean[liveBeanList.size()]);
1322: }
1323:
1324: /**
1325: * Return a list of the DesignBeans. NOTE: This returns the original list
1326: * used internally - do <b>NOT</b> muck with it! It is intended for internal
1327: * functions needing to iterate over the array contents quickly.
1328: */
1329: public ArrayList getBeansList() {
1330: return liveBeanList;
1331: }
1332:
1333: /*
1334: * @see com.sun.rave.designtime.DesignContext#getBeansOfType(java.lang.Class)
1335: */
1336: public DesignBean[] getBeansOfType(Class type) {
1337: ArrayList lbeans = getBeansList();
1338: ArrayList bst = new ArrayList();
1339: for (int i = 0, n = lbeans.size(); i < n; i++) {
1340: DesignBean b = (DesignBean) lbeans.get(i);
1341: Object instance = b.getInstance();
1342: Class beanType;
1343: if (instance != null) {
1344: beanType = instance.getClass();
1345: } else {
1346: beanType = b.getBeanInfo().getBeanDescriptor()
1347: .getBeanClass();
1348: }
1349: if (type.isAssignableFrom(beanType)) {
1350: bst.add(b);
1351: }
1352: }
1353: return (DesignBean[]) bst.toArray(new DesignBean[bst.size()]);
1354: }
1355:
1356: /**
1357: * User data managed and persisted by this context.
1358: */
1359: HashMap userData = new HashMap();
1360:
1361: /*
1362: * @see com.sun.rave.designtime.DesignContext#setContextData(java.lang.String, java.lang.Object)
1363: */
1364: public void setContextData(String key, Object data) {
1365: userData.put(key, data);
1366: }
1367:
1368: /*
1369: * @see com.sun.rave.designtime.DesignContext#getContextData(java.lang.String)
1370: */
1371: public Object getContextData(String key) {
1372: if (key.equals(Constants.ContextData.SCOPE)) {
1373: ManagedBean.Scope scope = model.getManagedBeanEntryScope();
1374: if (scope == null)
1375: return null;
1376: return scope.toString();
1377: } else if (key.equals(Constants.ContextData.CLASS_NAME)) {
1378: //Return the full class name (String) for the backing file
1379: return sourceUnit.getThisClass().getName();
1380: } else if (key.equals(Constants.ContextData.BASE_CLASS)) {
1381: //Return the base class (Class) object for the backing file
1382: return sourceUnit.getBaseBeanClass();
1383: } else if (key.equals(Constants.ContextData.PAGE_RESOURCE_URI)) {
1384: // return the page resource URI (java.net.URI) for the jsp file or null (web/Page1.jsp)
1385: return getModel().getMarkupResourceRelativeUri();
1386: } else if (key.equals(Constants.ContextData.JAVA_RESOURCE_URI)) {
1387: // return the backing bean resource URI (java.net.URI) for the backing source file (src/webapplication1/Page1.java)
1388: return getModel().getJavaResourceRelativeUri();
1389: } else if (key.equals(Constants.ContextData.INIT_METHOD)
1390: || key.equals(Constants.ContextData.PREPROCESS_METHOD)
1391: || key.equals(Constants.ContextData.PRERENDER_METHOD)
1392: || key.equals(Constants.ContextData.DESTROY_METHOD)) {
1393: //Extract the method name
1394: int index = key.lastIndexOf("Method");
1395: if (index > 0) {
1396: String methodName = key.substring(0, index);
1397: //Return the asked ContextMethod
1398: return contextMethodHelper.getContextMethod(methodName);
1399: }
1400: return null;
1401: } else if (key
1402: .equals(Constants.ContextData.CSS_STYLE_CLASS_DESCRIPTORS)) {
1403: MarkupUnit munit = model.getMarkupUnit();
1404: if (munit != null) {
1405: // return munit.getCssEngine().getStyleClasses().toString();
1406: // XXX Changed on Gregory's request to rather provide an array of Objects
1407: // then a String representing entire collection, however it is still
1408: // not according the API doc (see Constants.ConstextData.CSS_STYLE_CLASS_DESCRIPTORS).
1409: // Collection col = CssProvider.getEngineService().getCssStyleClassesForDocument(munit.getSourceDom());
1410: Collection col = CssProvider.getEngineService()
1411: .getCssStyleClassesForDocument(
1412: munit.getRenderedDom());
1413:
1414: List styleClasses = new ArrayList();
1415: for (Iterator it = col.iterator(); it.hasNext();) {
1416: // XXX There should be some known type (but not the batik's type).
1417: Object styleClass = it.next();
1418: if (styleClass != null) {
1419: styleClasses.add(styleClass);
1420: }
1421: }
1422: return styleClasses.toArray(new Object[styleClasses
1423: .size()]);
1424: }
1425: return null;
1426: } else if (Constants.ContextData.DATASOURCE_NAMES.equals(key)) {
1427: ArrayList beans = getBeansList();
1428: StringBuffer names = new StringBuffer();
1429: boolean doneFirst = false;
1430: for (int i = 0, n = beans.size(); i < n; i++) {
1431: DesignBean bean = (DesignBean) beans.get(i);
1432: Class beanClass = bean.getBeanInfo()
1433: .getBeanDescriptor().getBeanClass();
1434: if (javax.sql.RowSet.class.isAssignableFrom(beanClass)) {
1435: DesignProperty[] lps = bean.getProperties();
1436: for (int j = 0; j < lps.length; j++) {
1437: if (lps[j].getPropertyDescriptor().getName()
1438: .equals("dataSourceName")) { //NOI18N
1439: Object v = lps[j].getValue();
1440: if (v instanceof String) {
1441: if (doneFirst)
1442: names.append(",");
1443: else
1444: doneFirst = true;
1445: names.append((String) v);
1446: }
1447: }
1448: }
1449: }
1450: }
1451: return names.toString();
1452: } else {
1453: Object ud = userData.get(key);
1454: if (ud == null) {
1455: // PROJECTTODO2: cleanup - should I be using attributes on file ?
1456: ud = file.getAttribute(key);
1457: if (ud == null)
1458: ud = "";
1459: userData.put(key, ud);
1460: }
1461: return ud;
1462: }
1463: }
1464:
1465: /**
1466: * Flush our user data map to our underlying project item.
1467: */
1468: protected void flushContextData() {
1469: for (Iterator i = userData.entrySet().iterator(); i.hasNext();) {
1470: Map.Entry entry = (Map.Entry) i.next();
1471: Object data = entry.getValue();
1472: String string = data != null ? data.toString() : null;
1473: // PROJECTTODO2: Should I be storing data on the file object or not ?
1474: Util.updateItemProperty(file, (String) entry.getKey(),
1475: string);
1476: }
1477: // PROJECTTODO2: cleanup
1478: // How to fire off these events on data source names that are dynamically computed
1479: // Datasource is the only thing that MAY need this, AND should not needed once it uses the ModelSetListener stuff
1480: if (file == null)
1481: return;
1482: String key = Constants.ContextData.DATASOURCE_NAMES;
1483: String value = (String) getContextData(key);
1484: Util.updateItemProperty(file, key, value);
1485: }
1486:
1487: //------------------------------------------------------------------------ ContextMethod Methods
1488:
1489: /**
1490: * Returns a set of {@link ContextMethod} objects describing the public methods declared on this
1491: * DesignContext (source file).
1492: *
1493: * @return An array of {@link ContextMethod} objects, describing the public methods declared on
1494: * this DesignContext (source file)
1495: */
1496: public ContextMethod[] getContextMethods() {
1497: return contextMethodHelper.getContextMethods();
1498: }
1499:
1500: /*
1501: * Returns the owned beansunit
1502: */
1503: public BeansUnit getSourceUnit() {
1504: return sourceUnit;
1505: }
1506:
1507: /**
1508: * Returns a {@link ContextMethod} object describing the public method with the specified name
1509: * and parameter types. Returns <code>null</code> if no public method exists on this
1510: * DesignContext with the specified name and parameter types.
1511: *
1512: * @param methodName The method name of the desired context method
1513: * @param parameterTypes The parameter types of the desired context method
1514: * @return A ContextMethod object describing the requested method, or <code>null</code> if no
1515: * method exists with the specified name and parameter types
1516: */
1517: public ContextMethod getContextMethod(String methodName,
1518: Class[] parameterTypes) {
1519: return contextMethodHelper.getContextMethod(methodName,
1520: parameterTypes);
1521: }
1522:
1523: /**
1524: * <p>Creates a new public method in the source code for this DesignContext. The passed
1525: * ContextMethod <strong>must</strong> specify at least the designContext and methodName, and
1526: * <strong>must not</strong> describe a method that already exists in the DesignContext source.
1527: * To update an existing method, use the <code>updateContextMethod()</code> method. These
1528: * methods are separated to help prevent accidental method overwriting. The following table
1529: * details how the specified ContextMethod is used for this method:</p>
1530: *
1531: * <p><table border="1">
1532: * <tr><th>designContext <td><strong>REQUIRED.</strong> Must match the DesignContext that is
1533: * being called. This is essentially a safety precaution to help prevent accidental
1534: * method overwriting.
1535: * <tr><th>methodName <td><strong>REQUIRED.</strong> Defines the method name.
1536: * <tr><th>parameterTypes <td>Defines the parameter types. If <code>null</code> or an empty
1537: * array is specified, the created method will have no arguments.
1538: * <tr><th>parameterNames <td>Defines the parameter names. If <code>null</code> or an empty
1539: * array is specified (or an array shorter than the parameterTypes array), default
1540: * argument names will be used.
1541: * <tr><th>returnType <td>Defines the return type. If <code>null</code> is specified, the
1542: * created method will have a <code>void</code> return type.
1543: * <tr><th>throwsTypes <td>Defines the throws clause types. If <code>null</code> is specified,
1544: * the created method will have no throws clause.
1545: * <tr><th>bodySource <td>Defines the method body Java source code. If <code>null</code> is
1546: * specified, the method will have an empty body. If the value is non-null, this must
1547: * represent valid (compilable) Java source code.
1548: * <tr><th>commentText <td>Defines the comment text above the newly created method. If
1549: * <code>null</code> is specified, no comment text will be included.
1550: * </table></p>
1551: *
1552: * @param method A ContextMethod object representing the desired public method.
1553: * @return <code>true</code> if the method was created successfully, or <code>false</code> if
1554: * it was not.
1555: * @throws IllegalArgumentException If there was a syntax error in any of the ContextMethod
1556: * settings, or if the ContextMethod represents a method that already exists on this
1557: * DesignContext (<code>updateContextMethod()</code> must be used in this case to avoid
1558: * accidental method overwriting)
1559: */
1560: public boolean createContextMethod(ContextMethod method)
1561: throws IllegalArgumentException {
1562: return contextMethodHelper.createContextMethod(method);
1563: }
1564:
1565: /**
1566: * <p>Updates an existing public method in the source code for this DesignContext. The passed
1567: * ContextMethod will be used to locate the desired public method to update using the
1568: * designContext, methodName, and parameterTypes. This method may only be used to update the
1569: * parameterNames, returnType, throwsTypes, bodySource, or commentText. Any other changes
1570: * actually constitute the creation of a new method, as they alter the method signature. To
1571: * create a new method, the <code>createContextMethod()</code> method should be used. These
1572: * operations are separated to help prevent accidental method overwriting. The following table
1573: * details how the specified ContextMethod is used for this method:</p>
1574: *
1575: * <p><table border="1">
1576: * <tr><th>designContext <td><strong>REQUIRED.</strong> Must match the DesignContext that is
1577: * being called. This is essentially a safety precaution to help prevent accidental
1578: * method overwriting.
1579: * <tr><th>methodName <td><strong>REQUIRED.</strong> Specifies the desired method name.
1580: * <tr><th>parameterTypes <td><strong>REQUIRED.</strong> Specifies the desired method's
1581: * parameter types (if it has any). If <code>null</code> or an empty array is
1582: * specified, the desired method is assumed to have zero arguments.
1583: * <tr><th>parameterNames <td>Defines the parameter names. If <code>null</code> or an empty
1584: * array is specified (or an array shorter than the parameterTypes array), default
1585: * argument names will be used.
1586: * <tr><th>returnType <td>Defines the method's return type. If <code>null</code> is specified,
1587: * the method is assumed to have a <code>void</code> return type.
1588: * <tr><th>throwsTypes <td>Defines the throws clause types. If <code>null</code> is specified,
1589: * the resulting method will have no throws clause.
1590: * <tr><th>bodySource <td>Defines the method body Java source code. If <code>null</code> is
1591: * specified, the resulting method body will be empty. If the value is non-null, this
1592: * must represent valid (compilable) Java source code. Note that a method with a
1593: * non-void return type <strong>must</strong> return a value.
1594: * <tr><th>commentText <td>Defines the comment text above the newly created method. If
1595: * <code>null</code> is specified, no comment text will be included.
1596: * </table></p>
1597: *
1598: * @param method The desired ContextMethod representing the method to be updated
1599: * @return The resulting ContextMethod object (including any updates from the process)
1600: * @throws IllegalArgumentException If there was a syntax error in any of the ContextMethod
1601: * settings, or if the ContextMethod does not exist in this DesignContext.
1602: */
1603: public ContextMethod updateContextMethod(ContextMethod method)
1604: throws IllegalArgumentException {
1605: return contextMethodHelper.updateContextMethod(method);
1606: }
1607:
1608: /**
1609: * <p>Removes an existing method from the source code for this DesignContext. The passed
1610: * ContextMethod will be used to locate the desired method to remove using the designContext,
1611: * methodName, and parameterTypes. No other portions of the ContextMethod are used. The
1612: * following table details how the specified ContextMethod is used for this method:</p>
1613: *
1614: * <p><table border="1">
1615: * <tr><th>designContext <td><strong>REQUIRED.</strong> Must match the DesignContext that is
1616: * being called. This is essentially a safety precaution to help prevent accidental
1617: * method removal.
1618: * <tr><th>methodName <td><strong>REQUIRED.</strong> Specifies the desired method name.
1619: * <tr><th>parameterTypes <td><strong>REQUIRED.</strong> Specifies the desired method's
1620: * parameter types (if it has any). If <code>null</code> or an empty array is
1621: * specified, the desired method is assumed to have zero arguments.
1622: * <tr><th>parameterNames <td>Ignored.
1623: * <tr><th>returnType <td>Ignored.
1624: * <tr><th>throwsTypes <td>Ignored.
1625: * <tr><th>bodySource <td>Ignored.
1626: * <tr><th>commentText <td>Ignored.
1627: * </table></p>
1628: *
1629: * @param method A ContextMethod object defining the method to be removed
1630: * @return <code>true</code> if the method was successfully removed
1631: * @exception IllegalArgumentException if the specified ContextMethod does not exist or is not
1632: * public on this DesignContext
1633: */
1634: public boolean removeContextMethod(ContextMethod method) {
1635: return contextMethodHelper.removeContextMethod(method);
1636: }
1637:
1638: //-------------------------------------------------------------------------- MarkupDesignContext
1639:
1640: /*
1641: * @see com.sun.rave.designtime.markup.MarkupDesignContext#getCssPreviewImage
1642: */
1643: public Image getCssPreviewImage(String cssStyle,
1644: String[] cssStyleClasses,
1645: com.sun.rave.designtime.markup.MarkupDesignBean bean,
1646: int width, int height) {
1647: DesignerServiceHack designer = DesignerServiceHack.getDefault();
1648: if (designer != null) {
1649: return designer.getCssPreviewImage(cssStyle,
1650: cssStyleClasses, bean, width, height);
1651: }
1652: return null;
1653: }
1654:
1655: /*
1656: * @see com.sun.rave.designtime.markup.MarkupDesignContext#convertCssStyleToMap
1657: */
1658: public Map convertCssStyleToMap(String cssStyle) {
1659: // See if we have a MarkupUnit
1660: MarkupUnit munit = model.getMarkupUnit();
1661: // if (munit != null && munit.getCssEngine() != null) {
1662: // return munit.getCssEngine().styleToMap(cssStyle);
1663: // }
1664: // return new HashMap(0);
1665: // return CssProvider.getEngineService().getStyleMapFromStringForDocument(munit.getSourceDom(), cssStyle);
1666: return CssProvider.getEngineService()
1667: .getStyleMapFromStringForDocument(
1668: munit.getRenderedDom(), cssStyle);
1669: }
1670:
1671: /*
1672: * @see com.sun.rave.designtime.markup.MarkupDesignContext#convertMapToCssStyle
1673: */
1674: public String convertMapToCssStyle(Map cssStyleMap) {
1675: MarkupUnit munit = model.getMarkupUnit();
1676: // if (munit != null && munit.getCssEngine() != null) {
1677: // return munit.getCssEngine().mapToStyle(cssStyleMap);
1678: // }
1679: // return "";
1680: // return CssProvider.getEngineService().getStringFromStyleMapForDocument(munit.getSourceDom(), cssStyleMap);
1681: return CssProvider.getEngineService()
1682: .getStringFromStyleMapForDocument(
1683: munit.getRenderedDom(), cssStyleMap);
1684: }
1685:
1686: /*
1687: * @see com.sun.rave.designtime.faces.FacesDesignContext#getReferenceName()
1688: */
1689: public String getReferenceName() {
1690: return getModel().getBeanName();
1691: }
1692:
1693: /*
1694: * @see com.sun.rave.designtime.faces.FacesDesignContext#canCreateFacet(java.lang.String, java.lang.String, com.sun.rave.designtime.DesignBean)
1695: */
1696: public boolean canCreateFacet(String facet, String type,
1697: DesignBean parent) {
1698: return canCreateBean(type, parent, null); // , facet
1699: }
1700:
1701: /*
1702: * @see com.sun.rave.designtime.faces.FacesDesignContext#createFacet(java.lang.String, java.lang.String, com.sun.rave.designtime.DesignBean)
1703: */
1704: public DesignBean createFacet(String facet, String type,
1705: DesignBean parent) {
1706: return createBeanOrFacet(type, parent, facet, null);
1707: }
1708:
1709: /*
1710: * @see com.sun.rave.designtime.faces.FacesDesignContext#isValidBindingTarget(com.sun.rave.designtime.DesignBean)
1711: */
1712: public boolean isValidBindingTarget(DesignBean toBean) {
1713: if (!(toBean instanceof BeansDesignBean))
1714: return false;
1715:
1716: return ((BeansDesignBean) toBean).getBean().hasGetter();
1717: }
1718:
1719: /*
1720: * @see com.sun.rave.designtime.faces.FacesDesignContext#getBindingExpr(com.sun.rave.designtime.DesignBean, java.lang.String)
1721: */
1722: public String getBindingExpr(DesignBean toBean, String subExpr) {
1723: if (toBean == null)
1724: return null;
1725:
1726: // if toBean is an instance variable then the reference is just #{<this>.<toBean>}
1727: String ref = toBean.getInstanceName();
1728: if (toBean != rootContainer)
1729: ref = getReferenceName() + "." + ref;
1730: return "#{" + ref + subExpr + "}";
1731: }
1732:
1733: /*
1734: * @see com.sun.rave.designtime.faces.FacesDesignContext#getBindingExpr(com.sun.rave.designtime.DesignBean)
1735: */
1736: public String getBindingExpr(DesignBean toBean) {
1737: return getBindingExpr(toBean, "");
1738: }
1739:
1740: /*
1741: * @see com.sun.rave.designtime.faces.FacesDesignContext#resolveBindingExpr(java.lang.String)
1742: */
1743: public Object resolveBindingExpr(String expr) {
1744: ResolveResult result = resolveBindingExprToBean(expr);
1745: if (result.getRemainder() == null
1746: && result.getDesignBean() != null)
1747: return result.getDesignBean().getInstance();
1748: return null;
1749: }
1750:
1751: /*
1752: * @see com.sun.rave.designtime.faces.FacesDesignContext#resolveBindingExprToBean(java.lang.String)
1753: */
1754: public ResolveResult resolveBindingExprToBean(String expr) {
1755: if (expr.startsWith("#{") && expr.endsWith("}"))
1756: expr = expr.substring(2, expr.length() - 1);
1757:
1758: int lpos = 0; // last token position
1759: int pos = expr.indexOf('.', lpos); // delimiter position
1760: String name = pos >= 0 ? expr.substring(lpos, pos) : expr
1761: .substring(lpos);
1762:
1763: // match & gobble up the global bean reference for this root if there is one
1764: if (!name.equals(getReferenceName()))
1765: return new ResolveResult(null, expr.substring(lpos)); // last bean + remainder
1766:
1767: if (pos < 0)
1768: return new ResolveResult(rootContainer, null); // exact match
1769: lpos = pos + 1;
1770: pos = expr.indexOf('.', lpos);
1771: name = pos >= 0 ? expr.substring(lpos, pos) : expr
1772: .substring(lpos);
1773:
1774: // match & gobble up the instance bean reference if there is one
1775: DesignBean lbean = getBeanByName(name);
1776: if (lbean == null)
1777: return new ResolveResult(rootContainer, expr
1778: .substring(lpos)); // last bean + remainder
1779: if (pos < 0)
1780: return new ResolveResult(lbean, null); // exact match
1781: lpos = pos + 1;
1782: pos = expr.indexOf('.', 0); // delimiter position
1783: //name = pos >= 0 ? expr.substring(lpos, pos) : expr.substring(lpos);
1784:
1785: // return the most recent bean found + the remainder
1786: return new ResolveResult(lbean, expr.substring(lpos)); // last bean + remainder
1787: }
1788:
1789: /*
1790: * @see com.sun.rave.designtime.faces.FacesDesignContext#getFacesContext()
1791: */
1792: public FacesContext getFacesContext() {
1793: // !EAT TODO HACK ??? Should resurrect do something smarter ?
1794: // This most likely is appropriate as we should not cause a cast exception on out unit
1795: if (sourceUnit instanceof org.netbeans.modules.visualweb.insync.faces.FacesUnit)
1796: return ((org.netbeans.modules.visualweb.insync.faces.FacesUnit) sourceUnit)
1797: .getFacesContext();
1798: return null;
1799: }
1800:
1801: /*
1802: * @see com.sun.rave.designtime.DesignContext#getProject()
1803: */
1804: public DesignProject getProject() {
1805: // XXX Possible NPE when model is null, invalid state?
1806: if (model == null) {
1807: return null;
1808: }
1809: return (FacesModelSet) model.getOwner();
1810: }
1811:
1812: //--------------------------------------------------------------------------- DesignContext Events
1813:
1814: private List listeners = new ArrayList();
1815:
1816: /*
1817: * @see com.sun.rave.designtime.DesignContext#addDesignContextListener(com.sun.rave.designtime.DesignContextListener)
1818: */
1819: public void addDesignContextListener(DesignContextListener listener) {
1820: synchronized (listeners) {
1821: listeners.add(listener);
1822: }
1823: }
1824:
1825: /*
1826: * @see com.sun.rave.designtime.DesignContext#removeDesignContextListener(com.sun.rave.designtime.DesignContextListener)
1827: */
1828: public void removeDesignContextListener(
1829: DesignContextListener listener) {
1830: synchronized (listeners) {
1831: listeners.remove(listener);
1832: }
1833: }
1834:
1835: private List getDesignContextListenersList() {
1836: synchronized (listeners) {
1837: return new ArrayList(listeners);
1838: }
1839: }
1840:
1841: /*
1842: * @see com.sun.rave.designtime.DesignContext#getDesignContextListeners()
1843: */
1844: public DesignContextListener[] getDesignContextListeners() {
1845: List dcListeners = getDesignContextListenersList();
1846: return (DesignContextListener[]) dcListeners
1847: .toArray(new DesignContextListener[dcListeners.size()]);
1848: }
1849:
1850: /**
1851: * Fire a context changed event to all of our listeners.
1852: */
1853: void fireContextChanged() {
1854: generation++;
1855: List dcListeners = getDesignContextListenersList();
1856: for (Iterator li = dcListeners.iterator(); li.hasNext();)
1857: ((DesignContextListener) li.next()).contextChanged(this );
1858: getModel().fireModelChanged();
1859: }
1860:
1861: /**
1862: * Return the generation id for the current context.
1863: * Each contextChanged will create a new generation of
1864: * beans. ContextListeners can use this generation id
1865: * to coordinate changes; for example, two cooperating
1866: * views can tell each other about the contextChanged()
1867: * messages they receive to ensure that both have handled
1868: * this contextChange before doing some particular action. This
1869: * means that a listener may receive a contextChanged message
1870: * multiple times, and by looking at the generation (and remembering
1871: * which generation they most recently processed) they can avoid
1872: * processing the same update more than once.
1873: * @return The most recent generation we've notified ContextListeners
1874: * of via contextChanged(DesignContext).
1875: */
1876: public long getContextGeneration() {
1877: return generation;
1878: }
1879:
1880: private long generation = 0;
1881:
1882: /**
1883: * Fire a context activated event to all of our listeners.
1884: * This is public so that FacesModel can call this
1885: */
1886: public void fireContextActivated() {
1887: List dcListeners = getDesignContextListenersList();
1888: for (Iterator li = dcListeners.iterator(); li.hasNext();)
1889: ((DesignContextListener) li.next()).contextActivated(this );
1890: for (Iterator bi = liveBeanList.iterator(); bi.hasNext();) {
1891: DesignBean db = (DesignBean) bi.next();
1892: DesignInfo di = db.getDesignInfo();
1893: if (di != null) {
1894: di.beanContextActivated(db);
1895: }
1896: }
1897: }
1898:
1899: /**
1900: * Fire a context deactivated event to all of our listeners.
1901: * This is public so that FacesModel can call this
1902: */
1903: public void fireContextDeactivated() {
1904: List dcListeners = getDesignContextListenersList();
1905: for (Iterator li = dcListeners.iterator(); li.hasNext();)
1906: ((DesignContextListener) li.next())
1907: .contextDeactivated(this );
1908: for (Iterator bi = liveBeanList.iterator(); bi.hasNext();) {
1909: DesignBean db = (DesignBean) bi.next();
1910: DesignInfo di = db.getDesignInfo();
1911: if (di != null) {
1912: di.beanContextDeactivated(db);
1913: }
1914: }
1915: }
1916:
1917: /**
1918: * Fire a bean created event to all of our listeners.
1919: *
1920: * @param bean The newly created bean.
1921: */
1922: protected void fireBeanCreated(DesignBean bean) {
1923: itemAffected = true;
1924: SourceDesignBean slbean = (SourceDesignBean) bean;
1925: setReady(slbean, true);
1926: List dcListeners = getDesignContextListenersList();
1927: for (Iterator li = dcListeners.iterator(); li.hasNext();) {
1928: try {
1929: ((DesignContextListener) li.next()).beanCreated(slbean);
1930: } catch (Exception e) {
1931: e.printStackTrace();
1932: }
1933: }
1934: //Note: DI.beanCreatedSetup() is handled elsewhere...
1935: }
1936:
1937: /**
1938: * Fire a bean deleted event to all of our listeners.
1939: *
1940: * @param bean The recently deleted bean.
1941: */
1942: protected void fireBeanDeleted(DesignBean bean) {
1943: itemAffected = true;
1944: SourceDesignBean slbean = (SourceDesignBean) bean;
1945: if (slbean.ready) {
1946: List dcListeners = getDesignContextListenersList();
1947: for (Iterator li = dcListeners.iterator(); li.hasNext();) {
1948: try {
1949: ((DesignContextListener) li.next())
1950: .beanDeleted(bean);
1951: } catch (Exception e) {
1952: e.printStackTrace();
1953: }
1954: }
1955: // Recursively set the ready state
1956: setReady(slbean, false);
1957: }
1958: DesignInfo lbi = bean.getDesignInfo();
1959: if (lbi != null) {
1960: try {
1961: Result r = lbi.beanDeletedCleanup(bean);
1962: ResultHandler.handleResult(r, getModel());
1963: } catch (Exception e) {
1964: e.printStackTrace();
1965: }
1966: }
1967: model.removeAllBeanElReferences(model.getBeanName() + "."
1968: + bean.getInstanceName());
1969: }
1970:
1971: /**
1972: * Fire a bean instance name changed event to all of our listeners.
1973: *
1974: * @param bean The recently renamed bean.
1975: * @param oldName The prior name of the bean.
1976: */
1977: protected void fireBeanInstanceNameChanged(DesignBean bean,
1978: String oldName) {
1979: SourceDesignBean slbean = (SourceDesignBean) bean;
1980: if (slbean.ready) {
1981: List dcListeners = getDesignContextListenersList();
1982: for (Iterator li = dcListeners.iterator(); li.hasNext();) {
1983: try {
1984: ((DesignContextListener) li.next())
1985: .instanceNameChanged(bean, oldName);
1986: } catch (Exception e) {
1987: e.printStackTrace();
1988: }
1989: }
1990: }
1991: DesignInfo di = bean.getDesignInfo();
1992: if (di != null) {
1993: try {
1994: di.instanceNameChanged(bean, oldName);
1995: } catch (Exception e) {
1996: e.printStackTrace();
1997: }
1998: }
1999: }
2000:
2001: /**
2002: * Fire a bean changed event to all of our listeners.
2003: *
2004: * @param bean The recently changed bean.
2005: */
2006: protected void fireBeanChanged(DesignBean bean) {
2007: SourceDesignBean slbean = (SourceDesignBean) bean;
2008: if (slbean.ready) {
2009: List dcListeners = getDesignContextListenersList();
2010: for (Iterator li = dcListeners.iterator(); li.hasNext();) {
2011: try {
2012: ((DesignContextListener) li.next())
2013: .beanChanged(bean);
2014: } catch (Exception e) {
2015: e.printStackTrace();
2016: }
2017: }
2018: }
2019: DesignInfo lbi = bean.getDesignInfo();
2020: if (lbi != null) {
2021: try {
2022: lbi.beanChanged(bean);
2023: } catch (Exception e) {
2024: e.printStackTrace();
2025: }
2026: }
2027: }
2028:
2029: /**
2030: * Fire a bean moved event to all of our listeners.
2031: *
2032: * @param bean The recently moved bean.
2033: * @param oldParent The bean's old parent.
2034: * @param pos The new position of the bean.
2035: */
2036: protected void fireBeanMoved(DesignBean bean, DesignBean oldParent,
2037: Position pos) {
2038: List dcListeners = getDesignContextListenersList();
2039: for (Iterator li = dcListeners.iterator(); li.hasNext();) {
2040: try {
2041: ((DesignContextListener) li.next()).beanMoved(bean,
2042: oldParent, pos);
2043: } catch (Exception e) {
2044: e.printStackTrace();
2045: }
2046: }
2047: /*
2048: DesignInfo lbi = bean.getDesignInfo();
2049: if (lbi != null) {
2050: Result r = lbi.beanMoved(bean, oldParent, pos);
2051: ResultHandler.handleResult(r, getModel());
2052: }
2053: */
2054: }
2055:
2056: /**
2057: * Fire a property changed event to all of our listeners.
2058: *
2059: * @param prop The recently changed property.
2060: */
2061: protected void firePropertyChanged(DesignProperty prop,
2062: Object oldValue) {
2063: if (prop.getPropertyDescriptor().getName().equals(
2064: "dataSourceName")) //NOI18N
2065: itemAffected = true;
2066:
2067: SourceDesignBean slbean = (SourceDesignBean) prop
2068: .getDesignBean();
2069: if (slbean.ready) {
2070: List dcListeners = getDesignContextListenersList();
2071: for (Iterator li = dcListeners.iterator(); li.hasNext();) {
2072: DesignContextListener l = (DesignContextListener) li
2073: .next();
2074: assert Trace.trace("insync.live",
2075: "LU.fireDesignPropertyChanged prop:" + prop
2076: + " l:" + l);
2077: try {
2078: l.propertyChanged(prop, oldValue);
2079: } catch (Exception e) {
2080: e.printStackTrace();
2081: }
2082: }
2083: }
2084: DesignInfo lbi = prop.getDesignBean().getDesignInfo();
2085: if (lbi != null) {
2086: try {
2087: lbi.propertyChanged(prop, oldValue);
2088: } catch (Exception e) {
2089: e.printStackTrace();
2090: }
2091: }
2092: }
2093:
2094: /**
2095: * Fire a property changed event to all of our listeners.
2096: *
2097: * @param event The recently changed event.
2098: */
2099: protected void fireEventChanged(DesignEvent event) {
2100: SourceDesignBean slbean = (SourceDesignBean) event
2101: .getDesignBean();
2102: if (slbean.ready) {
2103: List dcListeners = getDesignContextListenersList();
2104: for (Iterator li = dcListeners.iterator(); li.hasNext();) {
2105: try {
2106: ((DesignContextListener) li.next())
2107: .eventChanged(event);
2108: } catch (Exception e) {
2109: e.printStackTrace();
2110: }
2111: }
2112: }
2113: DesignInfo lbi = event.getDesignBean().getDesignInfo();
2114: if (lbi != null) {
2115: try {
2116: lbi.eventChanged(event);
2117: } catch (Exception e) {
2118: e.printStackTrace();
2119: }
2120: }
2121: }
2122:
2123: //-------------------------------------------------------------------------------------- Utility
2124:
2125: // Recursively set the ready state
2126: private void setReady(SourceDesignBean bean, boolean ready) {
2127: bean.ready = ready;
2128: DesignBean[] childDesignBeans = bean.getChildBeans();
2129: if (childDesignBeans != null) {
2130: for (int i = 0; i < childDesignBeans.length; i++) {
2131: DesignBean childDesignBean = childDesignBeans[i];
2132: if (childDesignBean instanceof SourceDesignBean) {
2133: setReady((SourceDesignBean) childDesignBean, ready);
2134: }
2135: }
2136: }
2137: }
2138:
2139: /**
2140: * TODO Now that we cache DesignInfos that we instantiate, we need to see how we
2141: * clean up and get rid of dependencies that MAY have been added to it.
2142: */
2143: private static Map designInfoCache = Collections
2144: .synchronizedMap(new WeakHashMap());
2145:
2146: private final String DESIGNINFO_SUFFIX = "DesignInfo";
2147:
2148: private String[] searchPath = Introspector.getBeanInfoSearchPath();
2149:
2150: /**
2151: * Marker object used to indicate that an entry in designInfos is null, since we cannot store
2152: * null into a map.
2153: */
2154: protected static final Object nullDesignInfoMarker = new Object();
2155:
2156: /**
2157: * Flush our design info cache, as well as the Introspector one.
2158: * Care must be taken when this is done, as their are dependencies on
2159: * the getDesignInfo() call to always return the same instance.
2160: * There is a slight disconnect here, that if the Introspector cache is
2161: * flushed, we may not be :(
2162: */
2163: public static void flushCaches() {
2164: designInfoCache.clear();
2165: Introspector.flushCaches();
2166: }
2167:
2168: /**
2169: * @see #flushCaches
2170: *
2171: * @param clz Class object to be flushed.
2172: * @throws NullPointerException If the Class object is null.
2173: */
2174: public static void flushFromCaches(Class clz) {
2175: if (clz == null) {
2176: throw new NullPointerException();
2177: }
2178: designInfoCache.remove(clz);
2179: Introspector.flushFromCaches(clz);
2180: }
2181:
2182: /**
2183: * Get the DesignInfo for a bean, returning the same instance for the same class, with
2184: * the exception that if a flushCaches() or flushFromCache() occurs.
2185: * The code here is very similar to java.beans.Introspector
2186: */
2187: public DesignInfo getDesignInfo(Class beanClass,
2188: ClassLoader classLoder) {
2189: BeanInfo bi = BeansUnit.getBeanInfo(beanClass, classLoder);
2190: if (bi instanceof DesignInfo) {
2191: return (DesignInfo) bi;
2192: }
2193:
2194: ClassLoader oldContextClassLoader = Thread.currentThread()
2195: .getContextClassLoader();
2196: try {
2197: Thread.currentThread().setContextClassLoader(classLoder);
2198: String lbiClassName = beanClass.getName()
2199: + DESIGNINFO_SUFFIX;
2200: try {
2201: Object cacheEntry = designInfoCache.get(beanClass);
2202: if (cacheEntry == null) {
2203: DesignInfo designInfo = (DesignInfo) instantiate(
2204: beanClass, lbiClassName, classLoder);
2205: if (designInfo != null) {
2206: designInfoCache.put(beanClass, designInfo);
2207: return designInfo;
2208: } else {
2209: designInfoCache.put(beanClass,
2210: nullDesignInfoMarker);
2211: return null;
2212: }
2213: } else if (cacheEntry == nullDesignInfoMarker) {
2214: return null;
2215: } else {
2216: return (DesignInfo) cacheEntry;
2217: }
2218: } catch (Exception e) {
2219:
2220: // Now try looking for <searchPath>.fooDesignInfo
2221: lbiClassName = lbiClassName.substring(lbiClassName
2222: .lastIndexOf('.') + 1);
2223: for (int i = 0; i < searchPath.length; i++) {
2224:
2225: try {
2226: String fullName = searchPath[i] + "."
2227: + lbiClassName;
2228: DesignInfo designInfo = (DesignInfo) instantiate(
2229: beanClass, fullName, classLoder);
2230: if (designInfo != null) {
2231: if (designInfo.getBeanClass() == beanClass) {
2232: designInfoCache.put(beanClass,
2233: designInfo);
2234: return designInfo;
2235: }
2236: } else {
2237: designInfoCache.put(beanClass,
2238: nullDesignInfoMarker);
2239: return null;
2240: }
2241:
2242: } catch (Exception ex) {
2243: // Silently ignore, because we want to iterate over all path
2244: }
2245: }
2246: // It's normal to not find the DesignInfo and land in here
2247: designInfoCache.put(beanClass, nullDesignInfoMarker);
2248: return null;
2249: }
2250: } finally {
2251: Thread.currentThread().setContextClassLoader(
2252: oldContextClassLoader);
2253: }
2254: }
2255:
2256: /** Copied from java.beans.Introspector
2257: * Try to create an instance of a named class.
2258: * First try the classloader of "sibling", then try the system
2259: * classloader then the class loader of the current Thread.
2260: */
2261: private Object instantiate(Class sibling, String className,
2262: ClassLoader classLoader) throws InstantiationException,
2263: IllegalAccessException, ClassNotFoundException {
2264: // First check with sibling's classloader (if any).
2265: ClassLoader cl = sibling.getClassLoader();
2266: if (cl != null) {
2267: try {
2268: Class cls = cl.loadClass(className);
2269: return cls.newInstance();
2270: } catch (Exception ex) {
2271: // Just drop through and try the system classloader.
2272: }
2273: }
2274:
2275: // Now try the system classloader.
2276: try {
2277: cl = ClassLoader.getSystemClassLoader();
2278: if (cl != null) {
2279: Class cls = cl.loadClass(className);
2280: return cls.newInstance();
2281: }
2282: } catch (Exception ex) {
2283: // We're not allowed to access the system class loader or
2284: // the class creation failed.
2285: // Drop through.
2286: }
2287:
2288: // Use the classloader from the current Thread.
2289: cl = Thread.currentThread().getContextClassLoader();
2290: Class cls = cl.loadClass(className);
2291: return cls.newInstance();
2292: }
2293:
2294: /**
2295: * Return true iff the given component is visual. A nonvisual bean that is a UIComponent will
2296: * be still be rendered as part of the page (think of the stylesheet component for example),
2297: * but it will appear in the tray and can not be manipulated as a visual component in the
2298: * designer.
2299: *
2300: * @param bean The bean to be checked
2301: * @return true iff the bean is "visual"
2302: */
2303: public static boolean isVisualBean(DesignBean bean) {
2304: BeanInfo bi = bean.getBeanInfo();
2305: BeanDescriptor bd = null;
2306: if (bi != null) {
2307: bd = bi.getBeanDescriptor();
2308: }
2309:
2310: if (bd != null) {
2311: Object value = bd
2312: .getValue(Constants.BeanDescriptor.MARKUP_SECTION);
2313: if (value instanceof String) {
2314: String s = (String) value;
2315: if (s.equals("head")) //NOI18N
2316: return false;
2317: }
2318: }
2319:
2320: if (bean instanceof BeansDesignBean
2321: && ((BeansDesignBean) bean).getBean() instanceof HtmlBean)
2322: return true;
2323: if (!(bean.getInstance() instanceof UIComponent)
2324: || isTrayBean(bean))
2325: return false;
2326:
2327: if (bi == null)
2328: return false; // No BeanInfo: not a visible component
2329:
2330: if (bd == null)
2331: return false; // No BeanDescriptor: not a visible component
2332:
2333: // if the bean does not have a tag, then it can't be visual
2334: Object o = bd
2335: .getValue(com.sun.rave.designtime.Constants.BeanDescriptor.TAG_NAME);
2336: if (o == null)
2337: return false;
2338:
2339: return true;
2340: }
2341:
2342: /**
2343: * Return true iff the given component is positionable via CSS (e.g. using CSS2 CSS positioning
2344: * via a style attribute). If a component does not specify a positioning attribute, then it is
2345: * considered positionable iff it is a visual component (see isVisualBean());
2346: *
2347: * @see isVisualBean
2348: * @param bean The bean to be checked
2349: * @return true iff the bean is "positionable"
2350: */
2351: public static boolean isCssPositionable(DesignBean bean) {
2352: BeanInfo bi = bean.getBeanInfo();
2353: BeanDescriptor bd = null;
2354: if (bi != null) {
2355: bd = bi.getBeanDescriptor();
2356:
2357: if (bd != null) {
2358: // TODO: get constant for this, e.g.
2359: // Constants.BeanDescriptor.CSS_POSITIONING);
2360: Object value = bd.getValue("cssPositioning"); // NOI18N
2361: if (value instanceof String) {
2362: String s = (String) value;
2363: return !s.equals("none"); // NOI18N
2364: }
2365: }
2366: }
2367:
2368: return isVisualBean(bean);
2369: }
2370:
2371: /**
2372: * Return true iff the given component should be shown in the tray.
2373: *
2374: * @param bean The bean to be checked
2375: * @return true iff the bean declares that it is a "tray" component
2376: *
2377: * !!CQ TODO: need a better name. What the heck is a tray?
2378: */
2379: public static boolean isTrayBean(DesignBean bean) {
2380:
2381: // Components declare themselves as tray components by setting the "trayComponent" flag to
2382: // Boolean.TRUE
2383: BeanInfo bi = bean.getBeanInfo();
2384: if (bi == null)
2385: return false; // No BeanInfo: not a tray component
2386:
2387: BeanDescriptor bd = bi.getBeanDescriptor();
2388: if (bd == null)
2389: return false; // No BeanDescriptor: not a tray component
2390:
2391: Object o = bd
2392: .getValue(com.sun.rave.designtime.Constants.BeanDescriptor.TRAY_COMPONENT);
2393: if (o instanceof Boolean) {
2394: return ((Boolean) o).booleanValue();
2395: } else if (o instanceof String) {
2396: try {
2397: return Boolean.getBoolean((String) o);
2398: } catch (Exception x) {
2399: }
2400: }
2401:
2402: return false;
2403: }
2404:
2405: //---------------------------------------------------------------------------------- Customizers
2406:
2407: private static HashMap customizers = new HashMap();
2408:
2409: /**
2410: * @param classname
2411: * @param lc
2412: */
2413: public static void registerCustomizer(String classname,
2414: Customizer2 lc) {
2415: customizers.put(classname, lc);
2416: }
2417:
2418: /**
2419: * @param classname
2420: * @return
2421: */
2422: public static Customizer2 getCustomizer(String classname) {
2423: return (Customizer2) customizers.get(classname);
2424: }
2425:
2426: //--------------------------------------------------------------------------------------- Object
2427:
2428: public String toString() {
2429: StringBuffer sb = new StringBuffer();
2430: sb.append("[LU sourceUnit:" + sourceUnit);
2431: sb.append(" root:" + rootContainer);
2432: sb.append("]");
2433: return sb.toString();
2434: }
2435:
2436: public void resetFacesContextCurrentInstance() {
2437: /* TODONOW
2438: * We need to fix issue where we do not set design context properly, we assume it was
2439: * set by something else, this is not good. Reverting it back for now in order for me to
2440: * be able to commit and have sanity pass. Will work on issue with Deva, Tor, Craig.
2441: */
2442: // TODO
2443: // We should really set the faces context to null, but there does seem to be any API to do that
2444: // Talk to Craig about it
2445: RaveFacesContext facesContext = (RaveFacesContext) getFacesContext();
2446: // Is there an actual faces context related to me that I need to init ?
2447: if (facesContext != null) {
2448: // facesContext.setDesignContext(null);
2449: }
2450: }
2451:
2452: public void setFacesContextCurrentInstance() {
2453: // Make sure the faces context is initialized properly to allow resolvers to have access to the correct context
2454: RaveFacesContext facesContext = (RaveFacesContext) getFacesContext();
2455: // Is there an actual faces context related to me that I need to init ?
2456: if (facesContext != null) {
2457: facesContext.setCurrentInstance(); // make sure the context is available to components via thread lookup
2458: facesContext.setDesignContext(this ); //!CQ HACK? to have to point its state to each lc all the time
2459: }
2460: }
2461:
2462: }
|