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.models;
0042:
0043: import java.beans.MethodDescriptor;
0044: import org.netbeans.modules.visualweb.api.designerapi.DesignerServiceHack;
0045: import org.netbeans.modules.visualweb.api.designer.cssengine.CssProvider;
0046: import org.netbeans.modules.visualweb.designer.html.HtmlTag;
0047: import org.netbeans.modules.visualweb.insync.InSyncServiceProvider;
0048: import org.netbeans.modules.visualweb.insync.java.JavaClass;
0049: import org.netbeans.modules.visualweb.insync.java.JavaUnit;
0050:
0051: import java.beans.BeanInfo;
0052: import java.beans.EventSetDescriptor;
0053: import java.lang.reflect.InvocationTargetException;
0054: import java.net.URI;
0055: import java.net.URLClassLoader;
0056: import java.util.ArrayList;
0057:
0058: import org.netbeans.api.project.Project;
0059: import org.netbeans.api.project.ProjectUtils;
0060: import org.netbeans.api.project.SourceGroup;
0061: import org.netbeans.api.project.Sources;
0062: import org.netbeans.modules.visualweb.insync.java.Method;
0063: import org.openide.ErrorManager;
0064: import org.openide.cookies.CloseCookie;
0065: import org.openide.filesystems.FileObject;
0066: import org.openide.filesystems.FileUtil;
0067: import org.openide.loaders.DataLoaderPool;
0068: import org.openide.loaders.DataObject;
0069: import org.openide.loaders.DataObjectNotFoundException;
0070: import org.openide.loaders.OperationEvent;
0071: import org.openide.loaders.OperationListener;
0072: import org.openide.util.Lookup;
0073: import org.openide.util.NbBundle;
0074: import org.netbeans.modules.visualweb.extension.openide.util.Trace;
0075: import org.w3c.dom.DocumentFragment;
0076: import org.w3c.dom.Element;
0077: import org.w3c.dom.Node;
0078: import org.w3c.dom.NodeList;
0079:
0080: import org.netbeans.modules.visualweb.api.insync.JsfJavaDataObjectMarker;
0081: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectConstants;
0082: import org.netbeans.modules.visualweb.project.jsf.api.JsfProjectUtils;
0083: import com.sun.rave.designtime.Result;
0084: import com.sun.rave.designtime.DesignBean;
0085: import com.sun.rave.designtime.DesignInfo;
0086: import com.sun.rave.designtime.DesignEvent;
0087: import com.sun.rave.designtime.DesignProperty;
0088: import org.netbeans.modules.visualweb.insync.Model;
0089: import org.netbeans.modules.visualweb.insync.ModelSet;
0090: import org.netbeans.modules.visualweb.insync.ParserAnnotation;
0091: import org.netbeans.modules.visualweb.insync.ResultHandler;
0092: import org.netbeans.modules.visualweb.insync.SourceUnit;
0093: import org.netbeans.modules.visualweb.insync.UndoEvent;
0094: import org.netbeans.modules.visualweb.insync.UndoManager;
0095: import org.netbeans.modules.visualweb.insync.Unit;
0096: import org.netbeans.modules.visualweb.insync.Util;
0097: import org.netbeans.modules.visualweb.insync.beans.BeanStructureScanner;
0098: import org.netbeans.modules.visualweb.insync.beans.BeansUnit;
0099: import org.netbeans.modules.visualweb.insync.faces.FacesPageUnit;
0100: import org.netbeans.modules.visualweb.insync.faces.FacesUnit;
0101: import org.netbeans.modules.visualweb.insync.faces.ReefFacesBeanStructureScanner;
0102: import org.netbeans.modules.visualweb.insync.faces.ThresherFacesApplicationBeanStructureScanner;
0103: import org.netbeans.modules.visualweb.insync.faces.ThresherFacesPageBeanStructureScanner;
0104: import org.netbeans.modules.visualweb.insync.faces.ThresherFacesRequestBeanStructureScanner;
0105: import org.netbeans.modules.visualweb.insync.faces.ThresherFacesSessionBeanStructureScanner;
0106: import org.netbeans.modules.visualweb.insync.faces.ThresherFacesFragmentBeanStructureScanner;
0107: import org.netbeans.modules.visualweb.insync.live.BeansDesignEvent;
0108: import org.netbeans.modules.visualweb.insync.live.LiveUnit;
0109: import org.netbeans.modules.visualweb.insync.live.LiveUnitWrapper;
0110: import org.netbeans.modules.visualweb.insync.markup.MarkupUnit;
0111: import java.io.File;
0112: import java.util.Collection;
0113: import java.util.Iterator;
0114:
0115: import java.util.logging.Level;
0116: import java.util.logging.LogRecord;
0117: import java.util.logging.Logger;
0118: import javax.swing.SwingUtilities;
0119:
0120: import org.netbeans.modules.web.jsf.api.facesmodel.ManagedBean;
0121: import org.openide.cookies.EditorCookie;
0122: import org.openide.cookies.LineCookie;
0123: import org.openide.text.Line;
0124:
0125: /**
0126: * Representation of a complete JSF design-time model, including the composited insync units and
0127: * netbeans wiring.
0128: *
0129: * @author Tor Norbye
0130: * @author Carl Quinn
0131: */
0132: public class FacesModel extends Model {
0133:
0134: public static final FacesModel[] EMPTY_ARRAY = {};
0135:
0136: //The following arrays are used to ensure we are working with the
0137: //managed beans insync understands. There is one-one relationship
0138: //between these three arrays
0139: public static String managedBeanNames[] = {
0140: "com.sun.jsfcl.app.AbstractPageBean", // NOI18N
0141: "com.sun.jsfcl.app.AbstractRequestBean", // NOI18N
0142: "com.sun.jsfcl.app.AbstractSessionBean", // NOI18N
0143: "com.sun.jsfcl.app.AbstractApplicationBean", // NOI18N
0144: //TODO: Refactor this array into specific to R1 and R2 page
0145: "com.sun.rave.web.ui.appbase.AbstractPageBean", // NOI18N
0146: "com.sun.rave.web.ui.appbase.AbstractRequestBean", // NOI18N
0147: "com.sun.rave.web.ui.appbase.AbstractSessionBean", // NOI18N
0148: "com.sun.rave.web.ui.appbase.AbstractApplicationBean", // NOI18N
0149: "com.sun.rave.web.ui.appbase.AbstractFragmentBean" // NOI18N
0150: };
0151:
0152: public static ManagedBean.Scope managedBeanScopes[] = {
0153: ManagedBean.Scope.REQUEST, ManagedBean.Scope.REQUEST,
0154: ManagedBean.Scope.SESSION,
0155: ManagedBean.Scope.APPLICATION,
0156: //TODO: Refactor this array into specific to R1 and R2 page
0157: ManagedBean.Scope.REQUEST, ManagedBean.Scope.REQUEST,
0158: ManagedBean.Scope.SESSION, ManagedBean.Scope.APPLICATION,
0159: ManagedBean.Scope.REQUEST };
0160:
0161: public static boolean managedBeanIsPage[] = { true, false, false,
0162: false,
0163: //TODO: Refactor this array into specific to R1 and R2 page
0164: true, false, false, false, true };
0165:
0166: public static Class managedBeanScannerTypes[] = {
0167: ReefFacesBeanStructureScanner.class, // com.sun.rave.web.ui.appbase.AbstractPageBean
0168: BeanStructureScanner.class, // com.sun.jsfcl.app.AbstractRequestBean
0169: BeanStructureScanner.class, // com.sun.jsfcl.app.AbstractSessionBean
0170: BeanStructureScanner.class, // com.sun.jsfcl.app.AbstractApplicationBean
0171: ThresherFacesPageBeanStructureScanner.class, // com.sun.rave.web.ui.appbase.AbstractPageBean
0172: ThresherFacesRequestBeanStructureScanner.class, // com.sun.rave.web.ui.appbase.AbstractRequestBean
0173: ThresherFacesSessionBeanStructureScanner.class, // com.sun.rave.web.ui.appbase.AbstractSessionBean
0174: ThresherFacesApplicationBeanStructureScanner.class, // com.sun.rave.web.ui.appbase.AbstractApplicationBean
0175: ThresherFacesFragmentBeanStructureScanner.class // com.sun.rave.web.ui.appbase.AbstractFragmentBean
0176: };
0177:
0178: public static FacesModel getInstance(FileObject file) {
0179: return (FacesModel) Model.getInstance(file,
0180: FacesModelSet.class, false);
0181: }
0182:
0183: public static FacesModel getInstance(FileObject file, Class ofType) {
0184: return (FacesModel) Model.getInstance(file, ofType, false);
0185: }
0186:
0187: public static FacesModel getFacesModel(FileObject file) {
0188: return (FacesModel) Model.getModel(file);
0189: }
0190:
0191: /*
0192: * Project JSP and JAVA file maping methods map between the following.
0193: * The java tree rooted at srcFolder + backingFolder mirrors the jsp tree rooted at webFolder
0194: *
0195: * Examples:
0196: * beanName JSP Java
0197: * ~~~~~~~~ ~~~ ~~~~
0198: * Page1 Page1.jsp webapplication1/Page1.java
0199: * foo/Page2 foo/Page2.jsp webapplication1/foo/Page2.java
0200: */
0201:
0202: /**
0203: * Return the project item for the jsp half of a jsp/java pair given a java file object
0204: */
0205: public static final FileObject getJspForJava(FileObject javaFile) {
0206: // !EAT TODO MOVE this back INTO InSync where it BELONGS :(
0207: return JsfProjectUtils.getJspForJava(javaFile);
0208: }
0209:
0210: /**
0211: * Return the relative path and filename base given a java project item
0212: */
0213: static final String getBasePathForJava(FileObject javaFile) {
0214: return JsfProjectUtils.getBasePathForJava(javaFile);
0215: }
0216:
0217: /**
0218: * Return the logical bean name of a jsp/java pair given a java project item
0219: */
0220: public static final String getBeanNameForJava(FileObject javaFile) {
0221: String path = getBasePathForJava(javaFile);
0222: if (path != null) {
0223: //Remove the path separator character if found at the beginning
0224: if (path.startsWith("/"))
0225: path = path.substring(1);
0226: return FacesUnit.fixPossiblyImplicitBeanName(path.replace(
0227: '/', '$'));
0228: }
0229: return null;
0230: }
0231:
0232: /**
0233: * Return the project item for the java half of a jsp/java pair given a jsp project item
0234: */
0235: public static FileObject getJavaForJsp(FileObject file) {
0236: // !EAT TODO MOVE this back INTO InSync where it BELONGS :(
0237: return JsfProjectUtils.getJavaForJsp(file);
0238: }
0239:
0240: /**
0241: * Return the relative path and filename base given a jsp project item
0242: */
0243: static final String getBasePathForJsp(FileObject jspFile) {
0244: return JsfProjectUtils.getBasePathForJsp(jspFile);
0245: }
0246:
0247: /**
0248: * Return the logical bean name of a jsp/java pair given a jsp project item
0249: */
0250: public static final String getBeanNameForJsp(FileObject jspFile) {
0251: String beanName = getBasePathForJsp(jspFile);
0252: if (beanName == null)
0253: return null;
0254: if (beanName.length() == 0)
0255: return beanName;
0256: if (beanName.charAt(0) == '/')
0257: beanName = beanName.substring(1);
0258: beanName = beanName.replace('/', '$');
0259: beanName = FacesUnit.fixPossiblyImplicitBeanName(beanName);
0260: return beanName;
0261: }
0262:
0263: //--------------------------------------------------------------------------------- FacesFactory
0264:
0265: /**
0266: * A Model.Factory that knows how and when to make faces page FacesModels from file objects.
0267: */
0268: public static class FacesFactory implements Model.Factory {
0269: // static final String[] mimes = DesignerService.getDefault().getMimeTypes();
0270: static final String[] mimes = InSyncServiceProvider.get()
0271: .getMimeTypes();
0272:
0273: static boolean isModelMime(String mime) {
0274: for (int i = 0; i < mimes.length; i++) {
0275: if (mimes[i].equals(mime))
0276: return true;
0277: }
0278: return false;
0279: }
0280:
0281: public Model newInstance(ModelSet set, FileObject file) {
0282: boolean create = false;
0283: String mime = file.getMIMEType();
0284: FileObject jspFile = null;
0285: if (isModelMime(mime)) {
0286: jspFile = file;
0287: if (FacesModel.getJavaForJsp(file) != null) {
0288: create = true;
0289: }
0290: } else if (BeansFactory.isModelMime(mime)) {
0291: //If .java file is in conflict during CVS update, the file gets
0292: //renamed and a new file by same name is created which has the
0293: //the merged changes. In this scenario, model is deleted when the
0294: //file is renamed and therefore when the new file gets created,
0295: //it is necessary to create the model by pairing the new .java
0296: //file with the already existing .jsp file
0297:
0298: //There is already logic in ModelCreateVisitor to check for the
0299: //existence of Model for a given .jsp file but not for a .java file
0300: jspFile = FacesModel.getJspForJava(file);
0301: if (jspFile != null && set.getModel(jspFile) == null) {
0302: create = true;
0303: }
0304: }
0305: if (create) {
0306: return new FacesModel((FacesModelSet) set, jspFile);
0307: }
0308:
0309: return null;
0310: }
0311: }
0312:
0313: //--------------------------------------------------------------------------------- BeansFactory
0314:
0315: /**
0316: * A Model.Factory that knows how and when to make simple bean FacesModels from file objects.
0317: */
0318: public static class BeansFactory implements Model.Factory {
0319: static final String[] mimes = { "text/x-java" };
0320:
0321: static boolean isModelMime(String mime) {
0322: for (int i = 0; i < mimes.length; i++) {
0323: if (mimes[i].equals(mime))
0324: return true;
0325: }
0326: return false;
0327: }
0328:
0329: public Model newInstance(ModelSet set, FileObject file) {
0330: String mime = file.getMIMEType();
0331: return isModelMime(mime)
0332: && FacesModel.getJspForJava(file) == null ? new FacesModel(
0333: (FacesModelSet) set, file)
0334: : null;
0335: }
0336: }
0337:
0338: //------------------------------------------------------------------------------ Instance Fields
0339:
0340: protected FacesModelSet facesModelSet; // Our down-casted containing model set
0341:
0342: /** Project item, FileObject representing the jsp markup iff this is a page model */
0343: private FileObject markupFile;
0344: /** Unit representing the jsp markup iff this is a page model */
0345: private MarkupUnit markupUnit;
0346:
0347: /** Project item and FileObject representing the bean java file */
0348: private FileObject javaFile;
0349: /** Unit representing the bean java file */
0350: private JavaUnit javaUnit;
0351:
0352: /** JavaBean synthetic layer unit--always at least a plain bean. */
0353: private BeansUnit beansUnit;
0354: /** JavaBean synthetic layer also downcasted when a faces page */
0355: private FacesPageUnit facesUnit;
0356:
0357: protected LiveUnitWrapper liveUnitWrapper;
0358:
0359: private OperationListener operationListener = new ModelOperationListener();
0360:
0361: private String beanName;
0362:
0363: // private final FacesDnDSupport dndSupport = new FacesDnDSupport(this);
0364:
0365: //--------------------------------------------------------------------------------- Construction
0366: private static final Logger TIMERS = Logger
0367: .getLogger("TIMER.visualweb"); // NOI18N
0368:
0369: /**
0370: * Creates a new instance of FacesModel
0371: *
0372: * @param owner The owning ModelSet for this Model.
0373: * @param file The FileObject for either a page.jsp or a bean.java that is being modeled
0374: */
0375: FacesModel(FacesModelSet owner, FileObject file) {
0376: super (owner, file);
0377: assert Trace.trace("insync.models", "LFM.FacesModel: file:"
0378: + file); //NOI18N
0379:
0380: if (TIMERS.isLoggable(Level.FINE)) {
0381: LogRecord rec = new LogRecord(Level.FINE, "FacesModel"); // NOI18N
0382: rec.setParameters(new Object[] { this });
0383: TIMERS.log(rec);
0384: }
0385:
0386: this .facesModelSet = owner;
0387:
0388: // Given a java file, grab all the java related info
0389: if (BeansFactory.isModelMime(file.getMIMEType())) {
0390: javaFile = file;
0391: }
0392: // Given a markup file, grab all the markup related info
0393: else if (FacesFactory.isModelMime(file.getMIMEType())) {
0394: markupFile = file;
0395: }
0396:
0397: DataLoaderPool.getDefault().addOperationListener(
0398: operationListener);
0399: //fireModelOpened(this);
0400: }
0401:
0402: /*
0403: * @see org.netbeans.modules.visualweb.insync.Model#destroy()
0404: */
0405: public void destroy() {
0406: // // Let the designer know that this model is being destroyed, so it can clean up.
0407: // // In the future, the designer should listen to the DesignProject property notification
0408: // // and react there instead.
0409: // if (markupFile != null) {
0410: // DesignerServiceHack.getDefault().destroyWebFormForFileObject(markupFile);
0411: // }
0412: if (operationListener != null) {
0413: DataLoaderPool.getDefault().removeOperationListener(
0414: operationListener);
0415: operationListener = null;
0416: }
0417: DataObject javaDataObject = javaUnit == null ? null : javaUnit
0418: .getDataObject();
0419:
0420: // invoke fireContextDeleted() to let viewers know our context is dead
0421: if (liveUnitWrapper != null) {
0422: if (facesModelSet != null
0423: && liveUnitWrapper.isLiveUnitInstantiated())
0424: facesModelSet.fireContextClosed(getLiveUnit());
0425: liveUnitWrapper.destroy();
0426: liveUnitWrapper = null;
0427: }
0428:
0429: if (facesUnit != null) {
0430: facesUnit.destroy();
0431: facesUnit = null;
0432: }
0433: if (beansUnit != null) {
0434: beansUnit.destroy();
0435: beansUnit = null;
0436: }
0437: if (javaUnit != null) {
0438: javaUnit.removeListener(this );
0439: javaUnit.destroy();
0440: javaUnit = null;
0441: }
0442: if (markupUnit != null) {
0443: markupUnit.removeListener(this );
0444: markupUnit.destroy();
0445: markupUnit = null;
0446: }
0447: if (facesModelSet != null) {
0448: facesModelSet.removeFromModelsToSync(this );
0449: facesModelSet = null;
0450: }
0451:
0452: // <separation of models>
0453: html = null;
0454: body = null;
0455: // </separation of models>
0456:
0457: // Keep javaFile so we can report properly on error of isModelledManagedBean
0458: // javaFile = null;
0459: super .destroy();
0460:
0461: // XXX #6478973, #6335072 Assuring there are no opened components left after
0462: // model destroyal.
0463: if (javaDataObject != null) {
0464: CloseCookie cc = (CloseCookie) javaDataObject
0465: .getCookie(CloseCookie.class);
0466: if (cc != null) {
0467: cc.close();
0468: }
0469: }
0470: }
0471:
0472: /**
0473: * Called from ModelSet to let us know when the project class loader changes. Pass the new
0474: * loader down to the java and bean units if we have them.
0475: * @param cl The new classloader.
0476: */
0477: void updateClassLoader(ClassLoader cl) {
0478: if (beansUnit != null)
0479: beansUnit.setClassLoader(cl);
0480: }
0481:
0482: //------------------------------------------------------------------------------------ Accessors
0483:
0484: /*
0485: * @see org.netbeans.modules.visualweb.insync.Model#getUndoManager()
0486: */
0487: public UndoManager getUndoManager() {
0488: return undoManager;
0489: }
0490:
0491: /**
0492: * Return the FacesModelSet associated with this Model. This is a typed
0493: * version of getOwner();
0494: */
0495: public FacesModelSet getFacesModelSet() {
0496: return facesModelSet;
0497: }
0498:
0499: /**
0500: * Retrieve the FileObject for the markup portion of this model.
0501: *
0502: * @return The FileObject for the markup portion of this model.
0503: */
0504: public FileObject getMarkupFile() {
0505: return markupFile;
0506: }
0507:
0508: /**
0509: * Get the markup source Unit for this model.
0510: * @return The markup source Unit for this model.
0511: */
0512: public MarkupUnit getMarkupUnit() {
0513: return markupUnit;
0514: }
0515:
0516: /**
0517: * Returns a URI object representing the project resource for the page I represent.
0518: * web/Page1.jsp
0519: */
0520: public URI getMarkupResourceRelativeUri() {
0521: if (getMarkupUnit() == null)
0522: return null;
0523: FileObject file = getMarkupFile();
0524: URI uri = ((FacesModelSet) getOwner()).relativize(file);
0525: return uri;
0526: }
0527:
0528: /**
0529: * Get the FileObject for the Java file corresponding to this model.
0530: *
0531: * @return The Java file's FileObject.
0532: */
0533: public FileObject getJavaFile() {
0534: return javaFile;
0535: }
0536:
0537: /**
0538: * Get the java Unit for this model.
0539: * @return The java Unit for this model.
0540: */
0541: public JavaUnit getJavaUnit() {
0542: return javaUnit;
0543: }
0544:
0545: /**
0546: * Returns a URI object representing the project resource for the page I represent.
0547: * web/Page1.jsp
0548: */
0549: public URI getJavaResourceRelativeUri() {
0550: if (getJavaFile() == null)
0551: return null;
0552: FileObject file = getJavaFile();
0553: URI uri = ((FacesModelSet) getOwner()).relativize(file);
0554: return uri;
0555: }
0556:
0557: /**
0558: * Get the logical bean name for this model.
0559: *
0560: * @return The logical bean name for this model.
0561: */
0562: public String getBeanName() {
0563: if (beanName == null) {
0564: beanName = getBeanNameForJava(javaFile);
0565: }
0566: return beanName;
0567: }
0568:
0569: /**
0570: * Get the beans Unit for this model.
0571: *
0572: * @return The beans Unit for this model.
0573: */
0574: public BeansUnit getBeansUnit() {
0575: return beansUnit;
0576: }
0577:
0578: /**
0579: * Get the faces Unit for this model.
0580: *
0581: * @return The faces Unit for this model.
0582: */
0583: public FacesPageUnit getFacesUnit() {
0584: return facesUnit;
0585: }
0586:
0587: /**
0588: * Get the live Unit for this model.
0589: *
0590: * @return The live Unit for this model.
0591: */
0592: public synchronized LiveUnit getLiveUnit() {
0593: if (liveUnitWrapper == null)
0594: return null;
0595: return liveUnitWrapper.getLiveUnit();
0596: }
0597:
0598: /**
0599: * Get the topmost Unit for this model
0600: *
0601: * @return
0602: */
0603: public Unit getTopmostUnit() {
0604: return liveUnitWrapper == null ? markupUnit
0605: : (Unit) liveUnitWrapper;
0606: }
0607:
0608: /**
0609: * Return whether or not this model has errors
0610: *
0611: * @return
0612: */
0613: public boolean isBusted() {
0614: // Catch a case whereby the refactoring is done, and a bunch of events are being fired off,
0615: // some of the callers of this get notified of changes/removal's of models that are in invalid
0616: // state. My units are put into states that are not in sync.
0617: if (!isValid())
0618: return true;
0619: if (reportMustBeAbstractPageSubclassError) {
0620: return true;
0621: }
0622: // isBusted needs to take into account the two source units that derive the live unit, as
0623: // well as any possible errors contained in the live unit itself
0624: MarkupUnit markup = getMarkupUnit();
0625: if (markup != null && markup.getState().isBusted())
0626: return true;
0627: JavaUnit java = getJavaUnit();
0628: if (java != null && java.getState().isBusted())
0629: return true;
0630: if (liveUnitWrapper != null
0631: && liveUnitWrapper.getState().isBusted())
0632: return true;
0633: // if neither of my units are not busted or neither is initialized, then I am not busted
0634: return false;
0635: }
0636:
0637: /**
0638: * Return the errors that are present on this model
0639: *
0640: * @return
0641: */
0642: public ParserAnnotation[] getErrors() {
0643: ParserAnnotation errors[];
0644: // if the live unit is initialized, it will incorporate the errors from my source files as well, so dont ask the source files
0645: // if I have a live unit
0646: if (liveUnitWrapper == null) {
0647: // Return the collection of errors from all my source units
0648: ParserAnnotation markupErrors[] = getMarkupUnit() == null ? ParserAnnotation.EMPTY_ARRAY
0649: : getMarkupUnit().getErrors();
0650: ParserAnnotation javaErrors[] = getJavaUnit() == null ? ParserAnnotation.EMPTY_ARRAY
0651: : getJavaUnit().getErrors();
0652: int errorCount = markupErrors.length + javaErrors.length
0653: + (reportMustBeAbstractPageSubclassError ? 1 : 0);
0654: if (errorCount == 0)
0655: return ParserAnnotation.EMPTY_ARRAY;
0656: errors = new ParserAnnotation[errorCount];
0657: int index = 0;
0658: System.arraycopy(markupErrors, 0, errors, 0,
0659: markupErrors.length);
0660: index += markupErrors.length;
0661: System.arraycopy(javaErrors, 0, errors, index,
0662: javaErrors.length);
0663: index += javaErrors.length;
0664: if (reportMustBeAbstractPageSubclassError) {
0665: StringBuffer buffer = new StringBuffer();
0666: boolean didFirst = false;
0667: // Only report page subclasses
0668: for (int i = 0; i < managedBeanNames.length; i++) {
0669: if (managedBeanIsPage[i]) {
0670: if (didFirst) {
0671: buffer.append(", "); // NOI18N
0672: } else {
0673: didFirst = true;
0674: }
0675: buffer.append(managedBeanNames[i]);
0676: }
0677: }
0678: ParserAnnotation annotation = new ParserAnnotation(
0679: NbBundle.getMessage(FacesModel.class,
0680: "ERR_JavaMustBeDirectDescendent",
0681: buffer.toString()), getJavaFile(), 1, 1); // NOI18N
0682: errors[index] = annotation;
0683: index++;
0684: }
0685: } else {
0686: errors = liveUnitWrapper.getErrors();
0687: }
0688: return errors;
0689: }
0690:
0691: /**
0692: * Retrieve the DesignBeanContainer that holds the non-visual "tray" beans
0693: *
0694: * @return
0695: */
0696: public DesignBean getRootBean() {
0697: if (liveUnitWrapper == null)
0698: return null;
0699: DesignBean rootbean = getLiveUnit().getRootContainer();
0700: //assert Trace.trace("insync.models", "LFM.getTrayRoot: rootbean:" + rootbean);
0701: return rootbean;
0702: }
0703:
0704: //------------------------------------------------------------------------------- Internal Setup
0705:
0706: /**
0707: * Open the insync unit for the given web page's markup source
0708: */
0709: private void openMarkupUnit() {
0710: if (markupFile == null) {
0711: return;
0712: }
0713: assert Trace.trace("insync.models", "LFM.openMarkupUnit("
0714: + markupFile + ")"); //NOI18N
0715:
0716: // Jsp/Markup file
0717: markupUnit = new MarkupUnit(markupFile, MarkupUnit.ALLOW_XML,
0718: true, undoManager);
0719: markupUnit.addListener(this );
0720: }
0721:
0722: /**
0723: * Scan a DOM tree looking for an element with a binding="#{Name.foo}" attr & return Name
0724: *
0725: * @param n
0726: * @return Variable name part of first binding attr found
0727: */
0728: private static String findBoundBeanName(org.w3c.dom.Node n) {
0729: if (n.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
0730: String binding = ((Element) n).getAttribute("binding"); //NOI18N
0731: if (binding != null && binding.length() > 0
0732: && binding.startsWith("#{")
0733: && binding.endsWith("}")) { //NOI18N
0734: int dot = binding.indexOf('.');
0735: int end = dot > 0 ? dot : binding.length() - 1;
0736: return binding.substring(2, end);
0737: }
0738: }
0739: if (n.hasChildNodes()) {
0740: NodeList nl = n.getChildNodes();
0741: int len = nl.getLength();
0742: for (int i = 0; i < len; i++) {
0743: String name = findBoundBeanName(nl.item(i));
0744: if (name != null)
0745: return name;
0746: }
0747: }
0748: return null;
0749: }
0750:
0751: protected boolean reportMustBeAbstractPageSubclassError = false;
0752:
0753: /**
0754: * Open the insync units for the given web page's java backing file.
0755: */
0756: private void openJavaUnits() {
0757: assert Trace.trace("insync.models", "LFM.openJavaUnits()"); //NOI18N
0758:
0759: FileObject sourceFolder = null;
0760: // Item is not part of the project - user probably browsed a mounted filesystem -> user is
0761: // probably a Rave developer....
0762: Project project = getProject();
0763: if (project == null)
0764: return;
0765:
0766: // figure out our logical bean name based on file name
0767: String beanName;
0768: String javaPackage = null;
0769:
0770: if (javaFile == null) {
0771: beanName = getBeanNameForJsp(markupFile);
0772: } else {
0773: beanName = getBeanNameForJava(javaFile);
0774: }
0775:
0776: // see if it is registered with MBM
0777: FacesConfigModel facesConfigModel = facesModelSet
0778: .getFacesConfigModel();
0779: ManagedBean mb = facesConfigModel.getManagedBean(beanName);
0780:
0781: // if so then get our package & classname from there if needed
0782: if (mb != null) {
0783: if (javaFile == null) {
0784: // PROJECTTODO2: cleanup
0785: // This ugly blob of code needs to go somewhere
0786: String javaFileName = mb.getManagedBeanClass().replace(
0787: '.', '/')
0788: + ".java"; //NOI18N;
0789: Sources sources = ProjectUtils.getSources(getProject());
0790: // !EAT TODO: replace "java" with org.netbeans.api.java.project.JavaProjectConstants.SOURCES_TYPE_JAVA
0791: SourceGroup groups[] = sources.getSourceGroups("java");
0792: for (int i = 0; i < groups.length; i++) {
0793: SourceGroup group = groups[i];
0794: sourceFolder = group.getRootFolder();
0795: javaFile = sourceFolder.getFileObject(javaFileName);
0796: if (javaFile != null)
0797: break;
0798: }
0799: sourceFolder = null;
0800: }
0801: if (javaPackage == null)
0802: javaPackage = FacesConfigModel.getPackageName(mb);
0803: }
0804: // if not then get it using the formula, & update MBM later below
0805: else {
0806: if (javaFile == null) {
0807: javaFile = getJavaForJsp(markupFile);
0808: }
0809: }
0810: // if no java file, then abort setting up the java units
0811: if (javaFile == null) {
0812: ErrorManager.getDefault().log(
0813: "No java file found for " + markupFile); //NOI18N
0814: return;
0815: }
0816:
0817: // Assemble complete unit tree
0818: URLClassLoader cl = facesModelSet.getProjectClassLoader();
0819: javaUnit = new JavaUnit(javaFile, cl, undoManager);
0820: javaUnit.addListener(this );
0821: // PROJECTTODO2: iffy
0822: if (sourceFolder == null)
0823: // getPageBeanRoot() includes the defaultPackage, ie the default package folder
0824: sourceFolder = JsfProjectUtils.getPageBeanRoot(project)
0825: .getParent();
0826: File sourceFolderFile = FileUtil.toFile(sourceFolder);
0827: if (!sourceFolderFile.exists()) {
0828: ErrorManager.getDefault().log(
0829: "Error - The Source folder does not exist!"); //NOI18N
0830: return;
0831: }
0832:
0833: //In case we are reacting to .java file creation but before the file is
0834: //well formed, we may not be able to get the public class
0835: JavaClass javaClass = javaUnit.getJavaClass();
0836: if (javaClass == null) {
0837: javaUnit.setBusted();
0838: return;
0839: }
0840:
0841: // TODO Handle case where the class specified is not defined or is missing
0842: //Check if we are working with our known managed beans
0843: boolean isModelledManagedBean = false;
0844: for (int i = 0; i < managedBeanNames.length; i++) {
0845: if (javaClass.isSubTypeOf(managedBeanNames[i])) {
0846: isModelledManagedBean = true;
0847: break;
0848: }
0849: }
0850: reportMustBeAbstractPageSubclassError = false;
0851: // Abort model creation if the class is not one of ours
0852: if (!isModelledManagedBean) {
0853: try {
0854: DataObject dataObject = DataObject.find(javaFile);
0855: if (dataObject instanceof JsfJavaDataObjectMarker) {
0856: reportMustBeAbstractPageSubclassError = true;
0857: }
0858: } catch (DataObjectNotFoundException e) {
0859: }
0860: return;
0861: }
0862:
0863: javaUnit.sync();
0864: if (javaUnit.getState() != Unit.State.CLEAN) {
0865: return;
0866: }
0867:
0868: if (javaPackage == null)
0869: javaPackage = javaClass.getPackageName();
0870:
0871: String rootPackage = JsfProjectUtils.getProjectProperty(
0872: project, JsfProjectConstants.PROP_JSF_PAGEBEAN_PACKAGE);
0873: if (markupUnit != null) {
0874: beansUnit = facesUnit = new FacesPageUnit(javaUnit, cl,
0875: javaPackage, this , rootPackage, facesModelSet
0876: .getFacesContainer(), markupUnit);
0877: liveUnitWrapper = new LiveUnitWrapper(this , facesUnit,
0878: markupFile);
0879:
0880: facesUnit.setDefaultSrcEncoding(JsfProjectUtils
0881: .getSourceEncoding(project));
0882: facesUnit.setDefaultEncoding(JsfProjectUtils
0883: .getDefaultEncoding(project));
0884: facesUnit.setDefaultLanguage(JsfProjectUtils
0885: .getDefaultLocale(project));
0886: } else {
0887: beansUnit = new FacesUnit(javaUnit, cl, javaPackage, this ,
0888: rootPackage, facesModelSet.getFacesContainer());
0889: facesUnit = null;
0890: liveUnitWrapper = new LiveUnitWrapper(this , beansUnit,
0891: javaFile);
0892: }
0893:
0894: // now do a sync to force an update of the missing MB entry in the MBM
0895: //if (mb == null)
0896: // sync();
0897:
0898: assert Trace
0899: .trace("insync.models", " markupObj:" + markupFile); //NOI18N
0900: assert Trace.trace("insync.models", " project:" + project); //NOI18N
0901: assert Trace.trace("insync.models", " javaObj:" + javaFile); //NOI18N
0902: assert Trace.trace("insync.models", " javaPackage:"
0903: + javaPackage); //NOI18N
0904: return;
0905: }
0906:
0907: /**
0908: * When the file is renamed, the java class and other things may have changed
0909: * in an unopened file. So it has to be synced when renamed. Needed when the
0910: * document is not opened.
0911: */
0912: public void fileRenamed(String oldName, String newName, String ext,
0913: FileObject fo, boolean remove) {
0914: //Remove the model if any of the it's file is marked non sharable
0915: //(for example if there are conflicts during CVS update)
0916: if (remove
0917: && ((javaUnit != null && javaUnit.getFileObject() == fo) || (markupUnit != null && markupUnit
0918: .getFileObject() == fo))) {
0919: facesModelSet.removeModel(this );
0920: return;
0921: }
0922:
0923: // The following computaion ensures that we react to a file rename only
0924: // after all files of a FacesModel are renamed e.g. .java and .jsp
0925: boolean doSync = false;
0926: if (markupUnit != null) {
0927: if (javaUnit.getFileObject() == fo
0928: && markupUnit.getFileObject().getName().equals(
0929: fo.getName())) {
0930: doSync = true;
0931: } else if (file == fo
0932: && javaUnit.getFileObject().getName().equals(
0933: fo.getName())) {
0934: doSync = true;
0935: }
0936: } else if (file == fo) {
0937: doSync = true;
0938: }
0939:
0940: if (doSync) {
0941: if (javaUnit != null) {
0942: javaUnit.setSourceDirty();
0943: }
0944: if (markupUnit != null) {
0945: markupUnit.setSourceDirty();
0946: }
0947: //bean name is not valid anymore
0948: beanName = null;
0949:
0950: // We could call syncAll here, since via setSourceDirty() we have added
0951: // only this model to ModelSet.modlesToSync. So sync happens only to
0952: // this model. However, I can not call syncAll() as it is protected
0953: //facesModelSet.syncAll();
0954:
0955: // This sync will reset the Source Dirty flag.
0956: sync();
0957:
0958: // Remove the model from the modlesToSync (set by setSourceDirty()),
0959: // as we have already synced.
0960: facesModelSet.removeFromModelsToSync(this );
0961: }
0962: }
0963:
0964: /**
0965: *
0966: */
0967: private void ensureManagedBeansEntry() {
0968: String beanName = getBeanName();
0969: // see if it is registered with MBM
0970: FacesConfigModel facesConfigModel = facesModelSet
0971: .getFacesConfigModel();
0972: if (facesConfigModel.isBusted()) {
0973: return;
0974: }
0975: ManagedBean mb = facesConfigModel.getManagedBean(beanName);
0976: // update the missing MB entry in the MBM, getting scope based on the superclass of the bean
0977: //!CQ consider fixing broken entry settings in some cases
0978: if (mb == null) {
0979: JavaClass javaClass = beansUnit.getThisClass();
0980: for (int i = 0; i < managedBeanNames.length; i++) {
0981: if (beansUnit.getBaseBeanClassName().equals(
0982: managedBeanNames[i])) {
0983: facesConfigModel.ensureManagedBean(beanName,
0984: javaClass.getName(), managedBeanScopes[i]);
0985: return;
0986: }
0987: }
0988: }
0989: }
0990:
0991: public ManagedBean.Scope getManagedBeanEntryScope() {
0992: FacesConfigModel facesConfigModel = getFacesModelSet()
0993: .getFacesConfigModel();
0994: ManagedBean mb = facesConfigModel.getManagedBean(getBeanName());
0995: if (mb != null)
0996: return mb.getManagedBeanScope();
0997: return null;
0998: }
0999:
1000: public ManagedBean.Scope getScope() {
1001: if (isBusted())
1002: return null;
1003: if (getBeansUnit() == null)
1004: return null;
1005: return getScope(getBeansUnit().getThisClass());
1006: }
1007:
1008: public ManagedBean.Scope getScope(JavaClass type) {
1009: if (type == null)
1010: return null;
1011: for (int i = 0; i < managedBeanNames.length; i++) {
1012: if (beansUnit.getBaseBeanClassName().equals(
1013: managedBeanNames[i])) {
1014: return managedBeanScopes[i];
1015: }
1016: }
1017: return null;
1018: }
1019:
1020: //----------------------------------------------------------------------------- Unit Interaction
1021:
1022: /*
1023: * @see org.netbeans.modules.visualweb.insync.Model#writeLock(java.lang.String)
1024: */
1025: public UndoEvent writeLock(String description) {
1026: UndoEvent event = null;
1027:
1028: if (!isWriteLocked()) {
1029: //make sure the source is not dirty before modifying the model
1030: sync();
1031: }
1032:
1033: if (liveUnitWrapper != null) {
1034: event = liveUnitWrapper.isWriteLocked() ? undoManager
1035: .getCurrentEvent() : undoManager.startUndoableTask(
1036: description, this );
1037:
1038: liveUnitWrapper.writeLock(event);
1039: } else if (markupUnit != null)
1040: markupUnit.writeLock(event); // no undo events without a LiveUnit
1041: return event;
1042: }
1043:
1044: /*
1045: * @see org.netbeans.modules.visualweb.insync.Model#isWriteLocked()
1046: */
1047: public boolean isWriteLocked() {
1048: if (liveUnitWrapper != null)
1049: return liveUnitWrapper.isWriteLocked();
1050: else if (markupUnit != null)
1051: return markupUnit.isWriteLocked();
1052: else
1053: return false;
1054: }
1055:
1056: /*
1057: * @see org.netbeans.modules.visualweb.insync.Model#writeUnlock(org.netbeans.modules.visualweb.insync.UndoEvent)
1058: */
1059: public void writeUnlock(UndoEvent event) {
1060: if (liveUnitWrapper != null)
1061: liveUnitWrapper.writeUnlock(event);
1062: else if (markupUnit != null)
1063: markupUnit.writeUnlock(event);
1064:
1065: // If still write locked we're not done with the task
1066: if (liveUnitWrapper != null && !liveUnitWrapper.isWriteLocked())
1067: undoManager.finishUndoableTask(event);
1068: }
1069:
1070: protected boolean firstSyncCompleted;
1071:
1072: /**
1073: * General, high-level synchronizing of this model with any potential changes in the document(s)
1074: * and updating related models.
1075: * @see org.netbeans.modules.visualweb.insync.Model#sync()
1076: */
1077: protected synchronized void syncImpl() {
1078: if (!needSyncing) {
1079: return;
1080: }
1081: needSyncing = false;
1082: assert Trace.trace("insync.models", "LFM.sync markupFile:"
1083: + markupFile); //NOI18N
1084:
1085: // Initial opening of units done on first sync
1086: boolean opened = false;
1087: // EAT: It used to do an &&, BUT it seems that if the files are added or moved
1088: // piece-meal, we will not get a complete picture. We should really do a better
1089: // job of this when items are added and removed from a ModelSet, which is
1090: // where this SHOULD be.
1091: // This DOES remove the need for the order of files added to project :)
1092: // TODO XXX
1093: if (liveUnitWrapper == null || markupUnit == null) {
1094: boolean hadLiveUnit = liveUnitWrapper != null;
1095: boolean hadMarkupUnit = markupUnit != null;
1096: if (!hadMarkupUnit)
1097: openMarkupUnit();
1098: if (!hadLiveUnit)
1099: openJavaUnits();
1100: opened = (!hadLiveUnit && liveUnitWrapper != null)
1101: || (!hadMarkupUnit && markupUnit != null);
1102: }
1103:
1104: Unit unit = getTopmostUnit();
1105: // abort creation if the units did not open
1106: if (unit == null) {
1107: //If errors are found in java/jsp source, mark if for syncing
1108: if (getErrors().length > 0) {
1109: needSyncing = true;
1110: return;
1111: } else {
1112: ErrorManager.getDefault().log(
1113: "insync unit would not open: skipping read"); //NOI18N
1114: destroy(); // set will remove this model after scan
1115: return;
1116: }
1117: }
1118:
1119: // XXX - this can happen when the project is closed while syncing is in progress.
1120: // Prevent NPE
1121: if (facesModelSet == null) {
1122: return;
1123: }
1124: // Prevent NPE
1125: if (facesModelSet.getFacesContainer() == null) {
1126: return;
1127: }
1128:
1129: // main unit synchronizing
1130: facesModelSet.getFacesContainer().getFacesContext(); // make sure the context is available to components via thread lookup
1131: boolean synced = unit.sync();
1132:
1133: if (liveUnitWrapper != null) {
1134: // Only do this if the unit was not busted on sync
1135: // update MBM as needed and add the xref accessors
1136: if (!unit.getState().isBusted() && synced) {
1137: ensureManagedBeansEntry();
1138: Object newProject = beansUnit.getModel().getProject()
1139: .getProjectDirectory().getAttribute(
1140: "NewProject"); //NOI18N
1141: if (!(newProject instanceof Boolean && (Boolean) newProject)) {
1142: Object newFile = getFile().getAttribute("NewFile"); //NOI18N
1143: if (newFile instanceof Boolean && (Boolean) newFile) {
1144: FacesModel model = (FacesModel) beansUnit
1145: .getModel();
1146: model.addXRefAccessors();
1147: }
1148: }
1149: }
1150:
1151: // on first open, invoke fireContextCreated() to let viewers know of our new context
1152: if (opened && facesModelSet.hasDesignProjectListeners())
1153: facesModelSet.fireContextOpened(getLiveUnit());
1154: } else {
1155: needSyncing = true;
1156: }
1157: if (synced)
1158: fireModelChanged();
1159: }
1160:
1161: /*
1162: * @see org.netbeans.modules.visualweb.insync.Model#flush()
1163: */
1164: public void flushImpl() {
1165: assert Trace.trace("insync.models", "LFM.flush(" + markupFile
1166: + ")"); //NOI18N
1167: // if necessary, flush model to document(s) by locking & unlocking top-most unit
1168: Unit unit = getTopmostUnit();
1169: if (unit != null && unit.getState() == Unit.State.MODELDIRTY) {
1170: unit.writeLock(null);
1171: unit.writeUnlock(null);
1172: }
1173: }
1174:
1175: /**
1176: * Should only be used if you are certain this will not cause a problem.
1177: * At moment this is only used by refactoring mechanism.
1178: * See the caller in ModelSet.plannedChange for more information.
1179: *
1180: */
1181: public void flushNonJavaUnitsImpl() {
1182: Unit unit = getMarkupUnit();
1183: if (unit != null && unit.getState() == Unit.State.MODELDIRTY) {
1184: unit.writeLock(null);
1185: unit.writeUnlock(null);
1186: }
1187: }
1188:
1189: public boolean isValid() {
1190: if (!super .isValid())
1191: return false;
1192: if (getMarkupFile() != null && !getMarkupFile().isValid())
1193: return false;
1194: if (getJavaFile() != null && !getJavaFile().isValid())
1195: return false;
1196: return true;
1197: }
1198:
1199: public void saveUnits() {
1200: /*
1201: * Start a transaction here to deal with the fact that during a refactoring, at the end a savaAll happens,
1202: * but we also perform a save on the same documents, with the tx we prevent from the two operating
1203: * at same time.
1204: * Now, there could be a problem where one writes a file and the other does as well, but they are both
1205: * working with the same document, and the modifications to the document are guarded in this fashion
1206: * as well, and therefore we should be safe.
1207: */
1208: beginMdrTransation();
1209: try {
1210: if (javaUnit != null)
1211: javaUnit.save();
1212: if (markupUnit != null)
1213: markupUnit.save();
1214: } finally {
1215: endMdrTransaction();
1216: }
1217: }
1218:
1219: /** TODO - move to DesignerUtils!
1220: * Give the bean's DesignInfo a chance to annotate the bean after it has been created. This
1221: * should be called after the user has added the component to the webform, such as upon a drag
1222: * and drop or double click gesture; it should not be called when code is creating beans such
1223: * as on a webform resurrect.
1224: *
1225: * @param lbean The recently created bean to be annotated
1226: */
1227: public void beanCreated(DesignBean dbean) {
1228: // Annotate creation - give components a chance to update the DOLFM. For example, when you
1229: // drop a data table, beanCreatedSetup will go and add some default columns as well.
1230: DesignInfo di = dbean.getDesignInfo();
1231: if (di != null) {
1232: Result r = di.beanCreatedSetup(dbean);
1233: ResultHandler.handleResult(r, this );
1234: }
1235: }
1236:
1237: /**
1238: * Give the bean's DesignInfo a chance to annotate the bean after it has been pasted. This
1239: * should be called after the user has pasted the component intto the webform.
1240: *
1241: * @param lbean The recently created bean to be annotated
1242: */
1243: public void beanPasted(DesignBean dbean) {
1244: // Annotate creation - give components a chance to update the DOLFM. For example, when you
1245: // drop a data table, beanCreatedSetup will go and add some default columns as well.
1246: DesignInfo di = dbean.getDesignInfo();
1247: if (di != null) {
1248: Result r = di.beanPastedSetup(dbean);
1249: ResultHandler.handleResult(r, this );
1250: }
1251: }
1252:
1253: /**
1254: * Link the given bean to the given target bean. It is assumed that the bean has agreed to the
1255: * link in advance via DesignInfo.canLink().
1256: *
1257: * @param target The bean to be linked to
1258: * @param bean The bean to link
1259: */
1260: public void linkBeans(DesignBean target, DesignBean bean) {
1261: DesignInfo dbi = target.getDesignInfo();
1262: if (dbi != null) {
1263: Result r = dbi.linkBeans(target, bean);
1264: ResultHandler.handleResult(r, this );
1265: }
1266: }
1267:
1268: /**
1269: * Return the event index for the first event in an eventSet identifed by name
1270: *
1271: * @param eventSets
1272: * @param eventSetName
1273: * @return
1274: */
1275: static int getEventIndex(EventSetDescriptor[] eventSets,
1276: String eventSetName) {
1277: int offset = 0;
1278: for (int i = 0; i < eventSets.length; i++) {
1279: if (eventSets[i].getName().equals(eventSetName))
1280: return offset;
1281: offset += eventSets[i].getListenerMethodDescriptors().length;
1282: }
1283: return -1;
1284: }
1285:
1286: static String[] defaultEventSetNames = { "action", "item",
1287: "valueChange", // event set names //NOI18N
1288: };
1289:
1290: /**
1291: * Return the default DesignEvent for the given bean
1292: *
1293: * @param lbean The bean to look up event handler names for
1294: * @return
1295: */
1296: public static DesignEvent getDefaultEvent(DesignBean lbean) {
1297: // get the bean info, descriptors & see if there are any events
1298: BeanInfo bi = lbean.getBeanInfo();
1299: EventSetDescriptor[] eventSets = bi.getEventSetDescriptors();
1300: if (eventSets.length == 0) { // Show bean's declaration if there are no events
1301: assert Trace.trace("insync.models",
1302: "TODO - show bean's declaration"); //NOI18N
1303: return null;
1304: }
1305:
1306: // get flat list of all events
1307: DesignEvent[] events = lbean.getEvents();
1308:
1309: // now figure out the best default event index to use
1310: // if defEvent is -1, then we need to scan for a reasonable event
1311: int defEvent = bi.getDefaultEventIndex();
1312: if (defEvent >= events.length)
1313: defEvent = -1;
1314:
1315: for (int i = 0; defEvent < 0 && i < defaultEventSetNames.length; i++) {
1316: defEvent = getEventIndex(eventSets, defaultEventSetNames[i]);
1317: if (defEvent != -1
1318: && (events[defEvent].getEventDescriptor()
1319: .isHidden() || events[defEvent]
1320: .getEventDescriptor()
1321: .getEventSetDescriptor().isHidden())) {
1322: defEvent = -1;
1323: }
1324: }
1325: if (defEvent < 0)
1326: defEvent = 0;
1327: if (events[defEvent].getEventDescriptor().isHidden()
1328: || events[defEvent].getEventDescriptor()
1329: .getEventSetDescriptor().isHidden()) {
1330: return null;
1331: } else {
1332: return events[defEvent];
1333: }
1334: }
1335:
1336: /**
1337: * Return an Array with intermixed DesignEvent, String entries.
1338: * Any hidden events will not be included.
1339: *
1340: * @param lbean The bean to look up event handler method names for
1341: * @return
1342: */
1343: public static ArrayList getVisibleEventsWithHandlerNames(
1344: DesignBean lbean) {
1345: assert Trace.trace("insync.models", "LFM.getEventHandlerNames("
1346: + lbean + ")"); //NOI18N
1347:
1348: // walk through all the events and get the best text string for each
1349: DesignEvent[] events = lbean.getEvents();
1350: ArrayList result = new ArrayList(events.length);
1351: for (int i = 0; i < events.length; i++) {
1352: DesignEvent e = events[i];
1353: if (e.getEventDescriptor().isHidden()
1354: || e.getEventDescriptor().getEventSetDescriptor()
1355: .isHidden()) {
1356: continue;
1357: }
1358: String dname = e.getEventDescriptor().getDisplayName();
1359: if (dname == null)
1360: dname = e.getEventDescriptor().getName();
1361: if (e.isHandled())
1362: dname += "=>" + e.getHandlerName() + "()";
1363: result.add(e);
1364: result.add(dname);
1365: }
1366: return result;
1367: }
1368:
1369: /**
1370: * Open the default "handler" for the unit itself. This is invoked for example when the user
1371: * double clicks on the document itself, not on any of the components on the page.
1372: **/
1373: public void openDefaultHandler() {
1374: Method m = facesUnit.getInitializerMethod();
1375: positionTheCursor(m, false);
1376: }
1377:
1378: /**
1379: * Open the default "handler" for a given bean. If no event handler is available for this bean,
1380: * it will open the default handler for a parent instead. If no such parent is found, it will
1381: * show the declaration for the given bean.
1382: *
1383: * @param lbean The bean to open a handler for
1384: */
1385: public void openDefaultHandler(DesignBean lbean) {
1386: assert Trace.trace("insync.models", "LFM.openDefaultHandler("
1387: + lbean + ")"); //NOI18N
1388: for (; lbean != null; lbean = lbean.getBeanParent()) {
1389: DesignEvent event = getDefaultEvent(lbean);
1390: if (event != null) {
1391: openEventHandler(event);
1392: return;
1393: }
1394: }
1395: assert Trace.trace("insync.models",
1396: "TODO - show bean's declaration"); //NOI18N
1397: }
1398:
1399: public void openEventHandler(DesignEvent event) {
1400: boolean inserted = createEventHandler(event);
1401: String handlerName = event.getHandlerName();
1402: MethodDescriptor md = event.getEventDescriptor()
1403: .getListenerMethodDescriptor();
1404:
1405: // now navigate the editor to the body of the newly created method
1406: Method m = beansUnit.getEventMethod(handlerName, md);
1407: positionTheCursor(m, inserted);
1408: }
1409:
1410: /**
1411: * Open the handler method for a given event in the editor, generating the default if needed.
1412: *
1413: * @param event
1414: */
1415: public boolean createEventHandler(DesignEvent event) {
1416: assert Trace.trace("insync.models", "LFM.openEventHandler("
1417: + event + ")"); //NOI18N
1418:
1419: if (getLiveUnit() == null || beansUnit == null) {
1420: ErrorManager
1421: .getDefault()
1422: .log(
1423: "openEventHandler: a Java unit was null--skipping insync"); //NOI18N
1424: return false;
1425: }
1426:
1427: int linedelta = 0;
1428: boolean inserted = false;
1429:
1430: if (!event.isHandled()) {
1431: UndoEvent undo = null;
1432: String staticnav = null;
1433: try {
1434: String eventName = event.getEventDescriptor().getName();
1435: String description = NbBundle
1436: .getMessage(FacesModel.class,
1437: "OpenEventHandler", eventName); // NOI18N
1438: undo = writeLock(description);
1439:
1440: // transfer static navigation string to return value of handler
1441: if (eventName.equals("action")) { //NOI18N
1442: DesignBean lbean = event.getDesignBean();
1443: DesignProperty lp = lbean.getProperty("action"); //NOI18N
1444: if (lp != null) {
1445: String source = lp.getValueSource();
1446: if (source != null && !source.startsWith("#{"))
1447: staticnav = source;
1448: }
1449: }
1450:
1451: event.setHandlerName(null); // let the live event generate its own name
1452:
1453: if (staticnav != null) {
1454: if (event instanceof BeansDesignEvent) {
1455: ((BeansDesignEvent) event).updateReturnStrings(
1456: null, staticnav);
1457: } else {
1458: event
1459: .setHandlerMethodSource("\n return \""
1460: + staticnav + "\";"); //NOI18N
1461: }
1462: }
1463: inserted = true;
1464: } finally {
1465: writeUnlock(undo);
1466: }
1467:
1468: // force a re-sync() (later) to get the model up to date with above source when
1469: if (staticnav instanceof String) {
1470: javaUnit.setSourceDirty();
1471: }
1472: }
1473: return inserted;
1474: }
1475:
1476: /**
1477: * Position the cursor in a blank line after the comment if the method is
1478: * newly inserted. Otherwise cursor is placed at the beginning of the first
1479: * statement
1480: *
1481: * @param Method
1482: * @param boolean indicates if the method is newly added
1483: */
1484: void positionTheCursor(Method m, boolean inserted) {
1485: try {
1486: int[] pos = m.getCursorPosition(inserted);
1487: int lineNo = pos[0];
1488: int col = pos[1];
1489:
1490: assert Trace.trace("insync.models", "lineno=" + lineNo
1491: + " col=" + col);
1492:
1493: // Make sure that lineno is showing and the caret is position at line+col
1494: LineCookie lc = (LineCookie) Util.getCookie(javaFile,
1495: LineCookie.class);
1496: if (lc != null) {
1497: Line.Set ls = lc.getLineSet();
1498: if (ls != null) {
1499: Line line = ls.getCurrent(lineNo);
1500: line.show(Line.SHOW_GOTO, col);
1501: }
1502: }
1503:
1504: // Explicitly open the editor pane and request focus
1505: EditorCookie editorCookie = (EditorCookie) Util.getCookie(
1506: javaFile, EditorCookie.class);
1507: if (editorCookie != null) {
1508: editorCookie.open();
1509: javax.swing.JEditorPane[] panes = editorCookie
1510: .getOpenedPanes();
1511:
1512: // Make sure that the editor has focus
1513: if (panes != null && panes.length > 0) {
1514: final javax.swing.JEditorPane editorPane = panes[0];
1515: javax.swing.SwingUtilities
1516: .invokeLater(new Runnable() {
1517: public void run() {
1518: editorPane.requestFocus();
1519: }
1520: });
1521: }
1522: }
1523: } catch (Exception e) {
1524: ErrorManager.getDefault().notify(
1525: ErrorManager.INFORMATIONAL, e);
1526: }
1527: }
1528:
1529: //--------------------------------------------------------------------------- ModelSet Utilities
1530:
1531: /**
1532: * @param oldname
1533: * @param newname
1534: */
1535: public void updateAllBeanElReferences(String oldname, String newname) {
1536: facesModelSet.updateBeanElReferences(oldname, newname);
1537: }
1538:
1539: /**
1540: * @param oldname
1541: */
1542: public void removeAllBeanElReferences(String oldname) {
1543: facesModelSet.removeBeanElReferences(oldname);
1544: }
1545:
1546: //--------------------------------------------------------------------------------- Model Events
1547:
1548: /* Unused
1549:
1550: public interface LifeListener {
1551: public void modelOpened(FacesModel model);
1552: public void modelClosed(FacesModel model);
1553: }
1554:
1555: private static ArrayList lifeListeners = new ArrayList();
1556:
1557: public static void addModelLifeListener(Listener listener) {
1558: lifeListeners.add(listener);
1559: }
1560:
1561: public static void removeModelLifeListener(Listener listener) {
1562: lifeListeners.remove(listener);
1563: }
1564:
1565: public static LifeListener[] getModelLifeListeners() {
1566: return (LifeListener[])lifeListeners.toArray(new LifeListener[lifeListeners.size()]);
1567: }
1568:
1569: protected static void fireModelOpened(FacesModel model) {
1570: int n = lifeListeners.size();
1571: for (int i = 0; i < n; i++) {
1572: ((LifeListener)lifeListeners.get(i)).modelOpened(model);
1573: }
1574: }
1575:
1576: protected static void fireModelClosed(FacesModel model) {
1577: int n = lifeListeners.size();
1578: for (int i = 0; i < n; i++) {
1579: ((LifeListener)lifeListeners.get(i)).modelClosed(model);
1580: }
1581: }
1582: */
1583:
1584: /** Activate/deactive the DesignContext for this faces model. */
1585: public void setActivated(boolean activated) {
1586: if (this .activated != activated) {
1587: this .activated = activated;
1588: if (liveUnitWrapper != null) {
1589: if (activated)
1590: getLiveUnit().fireContextActivated();
1591: else
1592: getLiveUnit().fireContextDeactivated();
1593: }
1594: }
1595: }
1596:
1597: /** Return whether the given unit is activated */
1598: public boolean isActivated() {
1599: return activated;
1600: }
1601:
1602: private boolean activated;
1603:
1604: public void sourceUnitSaved(final SourceUnit unit) {
1605: // TODO !EAT: need to remove this when we get notification of saving instead of saved
1606: // We MUST queue this up, since there Cookie is removed after, and we need to find
1607: // out if there is a cookie after the save is done
1608: /*
1609: SwingUtilities.invokeLater(new Runnable() {
1610: public void run() {
1611: // This is part of fact that this is a hack, getting notified of attribute changing
1612: // when file is being deleted
1613: if (getMarkupFile() != null && getMarkupFile().isValid()) {
1614: sync();
1615: DataObject dataObject = unit.getDataObject();
1616: SaveCookie cookie = (SaveCookie) dataObject.getCookie(SaveCookie.class);
1617: if (cookie != null)
1618: try {
1619: cookie.save();
1620: } catch (IOException e) {
1621: throw new RuntimeException(e);
1622: }
1623: }
1624: }
1625: });
1626: */
1627: }
1628:
1629: public boolean isInRequestScope() {
1630: return getScope() == ManagedBean.Scope.REQUEST;
1631: }
1632:
1633: public boolean isPageBean() {
1634: if (getBeansUnit() != null)
1635: return getBeansUnit().isPageBean();
1636: return false;
1637: }
1638:
1639: public void resetOwner() {
1640: // We need to keep owner and facesModelSet in lock step, since facesModelSet is intended to be a type safe rendition of owner
1641: super .resetOwner();
1642: facesModelSet = null;
1643: }
1644:
1645: // <separation of models> moved from designer/WebForm.
1646: /**
1647: * Get the document associated with this webform.
1648: */
1649: public org.w3c.dom.Document getJspDom() {
1650: MarkupUnit unit = getMarkupUnit();
1651:
1652: if (unit == null) { // possible when project has closed
1653: return null;
1654: }
1655:
1656: return unit.getSourceDom();
1657: }
1658:
1659: public org.w3c.dom.Document getHtmlDom() {
1660: MarkupUnit unit = getMarkupUnit();
1661:
1662: if (unit == null) { // possible when project has closed
1663: return null;
1664: }
1665:
1666: return unit.getRenderedDom();
1667: }
1668:
1669: private DocumentFragment html;
1670: private Element body;
1671:
1672: /**
1673: * Return the HTML DOM associated with the source JSPX DOM
1674: * returned by {@link getDom}.
1675: * @return A DocumentFragment which represents an HTML rendered,
1676: * JavaScript mutated, <f:verbatim>/<ui:tag> expanded
1677: * view of the source DOM.
1678: */
1679: public DocumentFragment getHtmlDomFragment() {
1680: if (html == null) {
1681: // // XXX TODO There is not needed webform here.
1682: // FileObject markupFile = this.getModel().getMarkupFile();
1683: //// html = FacesSupport.renderHtml(markupFile, null, !CssBox.noBoxPersistence);
1684: // html = InSyncService.getProvider().renderHtml(markupFile, null, !CssBox.noBoxPersistence);
1685: // // XXX FIXME Is this correct here?
1686: // FacesSupport.updateErrorsInComponent(this);
1687: html = FacesPageUnit.renderHtml(this , null);
1688: }
1689:
1690: return html;
1691: }
1692:
1693: /**
1694: * Return the <body> element associated with the rendered HTML
1695: * document
1696: */
1697: public Element getHtmlBody() {
1698: if (body == null) {
1699: body = findHtmlBody();
1700: }
1701:
1702: return body;
1703: }
1704:
1705: public void clearHtml() {
1706: this .html = null;
1707: this .body = null; // force new search
1708: }
1709:
1710: private Element findHtmlBody() {
1711: DocumentFragment htmlFragment = getHtmlDomFragment();
1712: Element bodyElement = null;
1713: if (htmlFragment != null) {
1714: // Is this a page fragment?
1715: FileObject markupFile = getMarkupFile();
1716: // XXX
1717: boolean isFragment = markupFile != null
1718: && "jspf".equals(markupFile.getExt()); // NOI18N
1719: boolean isPortlet = this .getFacesModelSet()
1720: .getFacesContainer().isPortletContainer();
1721: if (isFragment || isPortlet) {
1722: // Just use the first element
1723: NodeList nl = htmlFragment.getChildNodes();
1724: for (int i = 0, n = nl.getLength(); i < n; i++) {
1725: Node node = nl.item(i);
1726: if (node.getNodeType() == Node.ELEMENT_NODE) {
1727: bodyElement = (Element) node;
1728: // <removing set/getRoot from RaveDocument>
1729: // getJspDom().setRoot(bodyElement);
1730: // </removing set/getRoot from RaveDocument>
1731: break;
1732: }
1733: }
1734:
1735: // WebForm page = getContextPage();
1736: // XXX Get rid of this, why fragment keeps ref to one of the context pages??
1737: FileObject contextFile = DesignerServiceHack
1738: .getDefault().getContextFileForFragmentFile(
1739: markupFile);
1740: FacesModel page;
1741: if (contextFile == null) {
1742: page = null;
1743: } else {
1744: page = FacesModel.getInstance(contextFile);
1745: }
1746:
1747: if (page != null) {
1748: // XXX Force sync first??
1749: Element surroundingBody = page.getHtmlBody();
1750:
1751: if (surroundingBody != null) {
1752: // RaveElement.setStyleParent(bodyElement, surroundingBody);
1753: CssProvider.getEngineService()
1754: .setStyleParentForElement(bodyElement,
1755: surroundingBody);
1756:
1757: // Make sure styles inherit right into the included content
1758: // ((RaveDocument)getJspDom()).setCssEngine(page.getJspDom().getCssEngine());
1759: // CssProvider.getEngineService().reuseCssEngineForDocument(getJspDom(), page.getJspDom());
1760: CssProvider
1761: .getEngineService()
1762: .reuseCssEngineForDocument(
1763: getHtmlDom(), page.getHtmlDom());
1764:
1765: // XhtmlCssEngine engine = CssLookup.getCssEngine(bodyElement);
1766: // XhtmlCssEngine engine = (XhtmlCssEngine)((CSSStylableElement)bodyElement).getEngine();
1767: //
1768: // if (engine != null) {
1769: // engine.clearTransientStyleSheetNodes();
1770: // }
1771: CssProvider
1772: .getEngineService()
1773: .clearTransientStyleSheetNodesForDocument(
1774: getJspDom());
1775: }
1776: }
1777: } else {
1778: bodyElement = null;
1779: }
1780:
1781: if (bodyElement == null) {
1782: bodyElement = findBodyElement(htmlFragment);
1783:
1784: // <removing set/getRoot from RaveDocument>
1785: // //if (bodyElement == null) {
1786: // // // Insert one! Is this going to cause locking problems??? I
1787: // // // need to do this under a write lock...
1788: // //}
1789: // NodeList nl = html.getChildNodes();
1790: // for (int i = 0, n = nl.getLength(); i < n; i++) {
1791: // Node node = nl.item(i);
1792: // if (node.getNodeType() == Node.ELEMENT_NODE) {
1793: // getJspDom().setRoot((RaveElement)node);
1794: // break;
1795: // }
1796: // }
1797: // </removing set/getRoot from RaveDocument>
1798: }
1799: }
1800:
1801: return bodyElement;
1802: }
1803:
1804: private static Element findBodyElement(Node node) {
1805: Element bodyElement = Util.findDescendant(HtmlTag.BODY.name,
1806: node);
1807:
1808: if (bodyElement == null) {
1809: bodyElement = Util.findDescendant(HtmlTag.FRAMESET.name,
1810: node);
1811: }
1812:
1813: // TODO -- make sure body is lowercase tag. If not offer to tidy it!
1814: return bodyElement;
1815: }
1816:
1817: // </separation of models>
1818:
1819: // >>> JSF support (DnD, refresh etc.)
1820: // public FacesDnDSupport getDnDSupport() {
1821: // return dndSupport;
1822: // }
1823: public JsfSupport getJsfSupport() {
1824: JsfSupportProvider jsfSupportProvider = Lookup.getDefault()
1825: .lookup(JsfSupportProvider.class);
1826: if (jsfSupportProvider == null) {
1827: return new DummyJsfSupport();
1828: } else {
1829: return jsfSupportProvider.getDndSupport(this );
1830: }
1831: }
1832:
1833: public interface JsfSupport {
1834: public void moveBeans(DesignBean[] designBean,
1835: DesignBean liveBean);
1836:
1837: public void selectAndInlineEdit(DesignBean[] beans,
1838: DesignBean bean);
1839:
1840: public void refresh(boolean deep);
1841: } // End of JsfSupport.
1842:
1843: public interface JsfSupportProvider {
1844: public JsfSupport getDndSupport(FacesModel facesModel);
1845: } // End of JsfSupportProvider.
1846:
1847: public static class DummyJsfSupport implements JsfSupport {
1848: public void moveBeans(DesignBean[] designBean,
1849: DesignBean liveBean) {
1850: }
1851:
1852: public void selectAndInlineEdit(DesignBean[] beans,
1853: DesignBean bean) {
1854: }
1855:
1856: public void refresh(boolean deep) {
1857: }
1858: } // End of DummyJsfSupport.
1859:
1860: // <<< JSF support (DnD, refresh, etc.)
1861:
1862: /* Refresh and sync non page beans to update the outline
1863: * Workaround for bug#6468062
1864: */
1865: public void refreshAndSyncNonPageBeans(boolean deep) {
1866: // Bug Fix# 109681
1867: // Prevent NPE. No need to refresh if this is a deleted FacesModel
1868: if (facesModelSet != null) {
1869: refresh(deep);
1870: //The following call enables syncing of non page beans required
1871: //to refresh outline
1872: facesModelSet.findDesignContexts(new String[] { "request", //NOI18N
1873: "session", //NOI18N
1874: "application" //NOI18N
1875: });
1876: }
1877: }
1878:
1879: /** XXX Moved from designer/WebForm#refresh, the insync part.
1880: * Refreshes the model
1881: * @deep If true, go all the way down to the insync markup unit
1882: * and force a sync also
1883: */
1884: public void refresh(boolean deep) {
1885: if (deep) {
1886: MarkupUnit unit = getMarkupUnit();
1887: if (unit != null) {
1888: if (unit.getState() == Unit.State.MODELDIRTY) {
1889: flush();
1890: }
1891:
1892: if (unit.getState() == Unit.State.CLEAN) {
1893: unit.setSourceDirty();
1894: }
1895:
1896: if (unit.getState() == Unit.State.SOURCEDIRTY) {
1897: sync();
1898: }
1899: }
1900: }
1901:
1902: // XXX #118178 Clear also the transient stylesheets.
1903: CssProvider.getEngineService()
1904: .clearTransientStyleSheetNodesForDocument(getJspDom());
1905: CssProvider.getEngineService()
1906: .clearTransientStyleSheetNodesForDocument(getHtmlDom());
1907:
1908: // CssLookup.refreshEffectiveStyles(webform.getDom());
1909: CssProvider.getEngineService().refreshStylesForDocument(
1910: getJspDom());
1911: // XXX Should this be here too (or the above?).
1912: CssProvider.getEngineService().refreshStylesForDocument(
1913: getHtmlDom());
1914:
1915: // XXX
1916: // StyleSheetCache.getInstance().flush();
1917: CssProvider.getEngineService().flushStyleSheetCache();
1918:
1919: clearHtml();
1920: }
1921:
1922: void refreshUnits(boolean immediate) {
1923: SourceUnit mu = getMarkupUnit();
1924: SourceUnit ju = getJavaUnit();
1925:
1926: // flush
1927: if ((mu != null && mu.getState() == Unit.State.MODELDIRTY)
1928: || (ju != null && ju.getState() == Unit.State.MODELDIRTY)) {
1929: flush();
1930: }
1931:
1932: boolean doSync = false;
1933:
1934: // clean
1935: if (mu != null && mu.getState() == Unit.State.CLEAN) {
1936: mu.setSourceDirty();
1937: doSync = true;
1938: }
1939: if (ju != null && ju.getState() == Unit.State.CLEAN) {
1940: ju.setSourceDirty();
1941: doSync = true;
1942: }
1943:
1944: // sync
1945: if (doSync && immediate) {
1946: sync();
1947: }
1948: }
1949:
1950: private class ModelOperationListener implements OperationListener {
1951: public void operationPostCreate(OperationEvent ev) {
1952: }
1953:
1954: public void operationCopy(OperationEvent.Copy ev) {
1955: }
1956:
1957: public void operationMove(OperationEvent.Move ev) {
1958: FileObject fo = ev.getOriginalPrimaryFile();
1959:
1960: // The following computaion ensures that we react to a file rename only
1961: // after all files of a FacesModel are renamed e.g. .java and .jsp
1962: boolean doRemoveModel = false;
1963: if (markupUnit != null) {
1964: if (javaUnit.getFileObject() == fo
1965: && JsfProjectUtils.getJspForJava(ev.getObject()
1966: .getPrimaryFile()) != null) {
1967: doRemoveModel = true;
1968: } else if (file == fo
1969: && JsfProjectUtils.getJavaForJsp(ev.getObject()
1970: .getPrimaryFile()) != null) {
1971: doRemoveModel = true;
1972: }
1973: } else if (file == fo) {
1974: doRemoveModel = true;
1975: }
1976:
1977: if (doRemoveModel) {
1978: try {
1979: SwingUtilities.invokeAndWait(new Runnable() {
1980: public void run() {
1981: getFacesModelSet().removeModel(
1982: FacesModel.this );
1983: }
1984: });
1985: } catch (InterruptedException e) {
1986: } catch (InvocationTargetException e) {
1987: }
1988: }
1989: }
1990:
1991: public void operationDelete(OperationEvent ev) {
1992: }
1993:
1994: public void operationRename(OperationEvent.Rename ev) {
1995: }
1996:
1997: public void operationCreateShadow(OperationEvent.Copy ev) {
1998: }
1999:
2000: public void operationCreateFromTemplate(OperationEvent.Copy ev) {
2001: }
2002: } // End of ModelSetOperationListener.
2003:
2004: public void addXRefAccessors() {
2005: FacesModelSet modelSet = getFacesModelSet();
2006: FacesConfigModel facesConfigModel = modelSet
2007: .getFacesConfigModel();
2008: ManagedBean managedBean = facesConfigModel
2009: .getManagedBean(beansUnit.getBeanName());
2010: ManagedBean.Scope scope = null;
2011: if (managedBean != null) {
2012: scope = managedBean.getManagedBeanScope();
2013: }
2014: if (scope == null) {
2015: scope = getScope(beansUnit.getThisClass());
2016: }
2017: Collection names = modelSet.getBeanNamesToXRef(scope, this );
2018: for (Iterator iterator = names.iterator(); iterator.hasNext();) {
2019: String name = (String) iterator.next();
2020: // Ignore adding a xref to myself
2021: if (!name.equals(beansUnit.getBeanName())) {
2022: managedBean = facesConfigModel.getManagedBean(name);
2023: beansUnit.addXRefAccessor(name, managedBean
2024: .getManagedBeanClass());
2025: }
2026: }
2027: }
2028: }
|