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:
0042: package org.netbeans.modules.web.project;
0043:
0044: import java.beans.PropertyChangeEvent;
0045: import java.beans.PropertyChangeListener;
0046: import java.beans.PropertyChangeSupport;
0047: import java.io.*;
0048: import java.lang.ref.WeakReference;
0049: import java.util.*;
0050: import java.util.logging.Level;
0051: import java.util.logging.LogRecord;
0052: import java.util.logging.Logger;
0053: import java.util.logging.Logger;
0054: import javax.swing.Icon;
0055: import javax.swing.ImageIcon;
0056: import javax.swing.JButton;
0057: import org.netbeans.api.java.classpath.ClassPath;
0058: import org.netbeans.api.java.classpath.GlobalPathRegistry;
0059: import org.netbeans.api.project.SourceGroup;
0060: import org.netbeans.api.project.ant.AntBuildExtender;
0061: import org.netbeans.modules.web.project.api.WebPropertyEvaluator;
0062: import org.netbeans.modules.web.project.jaxws.WebProjectJAXWSClientSupport;
0063: import org.netbeans.modules.web.project.jaxws.WebProjectJAXWSSupport;
0064: import org.netbeans.modules.websvc.api.jaxws.client.JAXWSClientSupport;
0065: import org.netbeans.modules.websvc.jaxws.api.JAXWSSupport;
0066: import org.netbeans.modules.websvc.jaxws.spi.JAXWSSupportFactory;
0067: import org.netbeans.modules.websvc.spi.client.WebServicesClientSupportFactory;
0068: import org.netbeans.modules.websvc.spi.jaxws.client.JAXWSClientSupportFactory;
0069: import org.openide.util.lookup.Lookups;
0070: import org.w3c.dom.Element;
0071: import org.w3c.dom.Node;
0072: import org.w3c.dom.NodeList;
0073: import org.w3c.dom.Text;
0074: import org.openide.filesystems.FileChangeAdapter;
0075: import org.openide.filesystems.FileChangeListener;
0076: import org.openide.filesystems.FileEvent;
0077: import org.openide.filesystems.FileRenameEvent;
0078: import org.openide.filesystems.FileObject;
0079: import org.openide.filesystems.FileStateInvalidException;
0080: import org.openide.filesystems.FileUtil;
0081: import org.openide.filesystems.FileAttributeEvent;
0082: import org.openide.util.Lookup;
0083: import org.openide.util.Mutex;
0084: import org.openide.util.Utilities;
0085: import org.openide.util.lookup.Lookups;
0086: import org.netbeans.modules.web.api.webmodule.WebModule;
0087: import org.netbeans.modules.web.spi.webmodule.WebModuleFactory;
0088: import org.netbeans.api.project.Project;
0089: import org.netbeans.api.project.ProjectManager;
0090: import org.netbeans.api.project.ant.AntArtifact;
0091: import org.netbeans.modules.web.project.classpath.ClassPathProviderImpl;
0092: import org.netbeans.modules.web.project.ui.WebLogicalViewProvider;
0093: import org.netbeans.modules.web.project.ui.customizer.WebProjectProperties;
0094: import org.netbeans.spi.project.AuxiliaryConfiguration;
0095: import org.netbeans.api.project.ProjectInformation;
0096: import org.netbeans.modules.j2ee.common.project.classpath.ClassPathExtender;
0097: import org.netbeans.modules.j2ee.common.project.classpath.ClassPathModifier;
0098: import org.netbeans.modules.j2ee.deployment.devmodules.api.J2eePlatform;
0099: import org.netbeans.modules.java.api.common.SourceRoots;
0100: import org.netbeans.modules.java.api.common.ant.UpdateHelper;
0101: import org.netbeans.modules.java.api.common.queries.QuerySupport;
0102: import org.netbeans.spi.project.SubprojectProvider;
0103: import org.netbeans.spi.project.ant.AntArtifactProvider;
0104: import org.netbeans.spi.project.ant.AntBuildExtenderFactory;
0105: import org.netbeans.spi.project.ant.AntBuildExtenderImplementation;
0106: import org.netbeans.spi.project.support.LookupProviderSupport;
0107: import org.netbeans.spi.project.support.ant.AntProjectEvent;
0108: import org.netbeans.spi.project.support.ant.AntProjectHelper;
0109: import org.netbeans.spi.project.support.ant.AntProjectListener;
0110: import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
0111: import org.netbeans.spi.project.support.ant.ProjectXmlSavedHook;
0112: import org.netbeans.spi.project.ui.PrivilegedTemplates;
0113: import org.netbeans.spi.project.ui.RecommendedTemplates;
0114: import org.netbeans.spi.project.ui.support.UILookupMergerSupport;
0115: import org.netbeans.spi.project.support.ant.ReferenceHelper;
0116: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
0117: import org.netbeans.spi.project.ui.ProjectOpenedHook;
0118: import org.netbeans.modules.j2ee.common.project.classpath.ClassPathSupport;
0119: import org.netbeans.modules.j2ee.common.project.classpath.LibrariesLocationUpdater;
0120: import org.netbeans.modules.j2ee.common.project.ui.ClassPathUiSupport;
0121: import org.netbeans.modules.j2ee.common.project.ui.ProjectProperties;
0122: import org.netbeans.modules.j2ee.common.ui.BrokenServerSupport;
0123: import org.netbeans.modules.j2ee.deployment.devmodules.api.Deployment;
0124: import org.netbeans.modules.j2ee.deployment.devmodules.api.J2eeModule;
0125: import org.netbeans.modules.web.api.webmodule.WebProjectConstants;
0126: import org.netbeans.modules.web.project.classpath.ClassPathSupportCallbackImpl;
0127: import org.netbeans.modules.web.project.classpath.WebProjectLibrariesModifierImpl;
0128: import org.netbeans.modules.web.project.jaxws.WebProjectJAXWSVersionProvider;
0129: import org.netbeans.modules.web.project.spi.BrokenLibraryRefFilter;
0130: import org.netbeans.modules.web.project.spi.BrokenLibraryRefFilterProvider;
0131: import org.netbeans.modules.web.project.ui.customizer.CustomizerProviderImpl;
0132: import org.netbeans.modules.web.spi.webmodule.WebPrivilegedTemplates;
0133: import org.netbeans.spi.project.support.ant.EditableProperties;
0134: import org.netbeans.modules.websvc.api.webservices.WebServicesSupport;
0135: import org.netbeans.modules.websvc.api.client.WebServicesClientSupport;
0136: import org.netbeans.modules.websvc.api.jaxws.project.WSUtils;
0137: import org.netbeans.modules.websvc.spi.webservices.WebServicesSupportFactory;
0138: import org.netbeans.spi.java.project.support.ExtraSourceJavadocSupport;
0139: import org.netbeans.spi.java.project.support.LookupMergerSupport;
0140: import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport;
0141: import org.openide.DialogDisplayer;
0142: import org.openide.NotifyDescriptor;
0143: import org.openide.filesystems.FileLock;
0144: import org.openide.filesystems.FileSystem.AtomicAction;
0145: import org.openide.loaders.DataObject;
0146: import org.openide.util.Exceptions;
0147: import org.openide.util.NbBundle;
0148: import org.openide.util.RequestProcessor;
0149:
0150: /**
0151: * Represents one plain Web project.
0152: * @author Jesse Glick, et al., Pavel Buzek
0153: */
0154: public final class WebProject implements Project, AntProjectListener {
0155:
0156: private static final Logger LOGGER = Logger
0157: .getLogger(WebProject.class.getName());
0158:
0159: private static final String UI_LOGGER_NAME = "org.netbeans.ui.web.project"; //NOI18N
0160:
0161: private static final Icon WEB_PROJECT_ICON = new ImageIcon(
0162: Utilities
0163: .loadImage("org/netbeans/modules/web/project/ui/resources/webProjectIcon.gif")); // NOI18
0164:
0165: private final AntProjectHelper helper;
0166: private final PropertyEvaluator eval;
0167: private final ReferenceHelper refHelper;
0168: private final GeneratedFilesHelper genFilesHelper;
0169: private final Lookup lookup;
0170: private final ProjectWebModule webModule;
0171: private CopyOnSaveSupport css;
0172: private WebModule apiWebModule;
0173: private WebServicesSupport apiWebServicesSupport;
0174: private JAXWSSupport apiJaxwsSupport;
0175: private WebServicesClientSupport apiWebServicesClientSupport;
0176: private JAXWSClientSupport apiJAXWSClientSupport;
0177: private WebContainerImpl enterpriseResourceSupport;
0178: private FileWatch webPagesFileWatch;
0179: private FileWatch webInfFileWatch;
0180: private PropertyChangeListener j2eePlatformListener;
0181: private SourceRoots sourceRoots;
0182: private SourceRoots testRoots;
0183: private final UpdateHelper updateHelper;
0184: private final UpdateProjectImpl updateProject;
0185: private final AuxiliaryConfiguration aux;
0186: private final ClassPathExtender classPathExtender;
0187: private final ClassPathModifier cpMod;
0188: private final WebProjectLibrariesModifierImpl libMod;
0189: private final ClassPathProviderImpl cpProvider;
0190: private LibrariesLocationUpdater librariesLocationUpdater;
0191: private ClassPathUiSupport.Callback classPathUiSupportCallback;
0192:
0193: private AntBuildExtender buildExtender;
0194:
0195: private class FileWatch implements AntProjectListener,
0196: FileChangeListener {
0197:
0198: private String propertyName;
0199:
0200: private FileObject fileObject = null;
0201: private boolean watchRename = false;
0202:
0203: public FileWatch(String property) {
0204: this .propertyName = property;
0205: }
0206:
0207: public void init() {
0208: helper.addAntProjectListener(this );
0209: updateFileChangeListener();
0210: }
0211:
0212: public void reset() {
0213: helper.removeAntProjectListener(this );
0214: setFileObject(null);
0215: }
0216:
0217: public void updateFileChangeListener() {
0218: File resolvedFile;
0219: FileObject fo = null;
0220: String propertyValue = helper
0221: .getStandardPropertyEvaluator().getProperty(
0222: propertyName);
0223: if (propertyValue != null) {
0224: String resolvedPath = helper.resolvePath(propertyValue);
0225: resolvedFile = new File(resolvedPath).getAbsoluteFile();
0226: if (resolvedFile != null) {
0227: File f = resolvedFile;
0228: while (f != null
0229: && (fo = FileUtil.toFileObject(f)) == null) {
0230: f = f.getParentFile();
0231: }
0232: watchRename = f == resolvedFile;
0233: } else {
0234: watchRename = false;
0235: }
0236: } else {
0237: resolvedFile = null;
0238: watchRename = false;
0239: }
0240: setFileObject(fo);
0241: }
0242:
0243: private void setFileObject(FileObject fo) {
0244: if (!isEqual(fo, fileObject)) {
0245: if (fileObject != null) {
0246: fileObject.removeFileChangeListener(this );
0247: }
0248: fileObject = fo;
0249: if (fileObject != null) {
0250: fileObject.addFileChangeListener(this );
0251: }
0252: }
0253: }
0254:
0255: private boolean isEqual(Object object1, Object object2) {
0256: if (object1 == object2) {
0257: return true;
0258: }
0259: if (object1 == null) {
0260: return false;
0261: }
0262: return object1.equals(object2);
0263: }
0264:
0265: // AntProjectListener
0266:
0267: public void configurationXmlChanged(AntProjectEvent ev) {
0268: updateFileChangeListener();
0269: }
0270:
0271: public void propertiesChanged(AntProjectEvent ev) {
0272: updateFileChangeListener();
0273: }
0274:
0275: // FileChangeListener
0276:
0277: public void fileFolderCreated(FileEvent fe) {
0278: updateFileChangeListener();
0279: }
0280:
0281: public void fileDataCreated(FileEvent fe) {
0282: updateFileChangeListener();
0283: }
0284:
0285: public void fileChanged(FileEvent fe) {
0286: updateFileChangeListener();
0287: }
0288:
0289: public void fileDeleted(FileEvent fe) {
0290: updateFileChangeListener();
0291: }
0292:
0293: public void fileRenamed(FileRenameEvent fe) {
0294: if (watchRename && fileObject.isValid()) {
0295: File f = new File(helper.getStandardPropertyEvaluator()
0296: .getProperty(propertyName));
0297: if (f.getName().equals(fe.getName())) {
0298: EditableProperties properties = new EditableProperties(
0299: true);
0300: properties.setProperty(propertyName, new File(f
0301: .getParentFile(), fe.getFile().getName())
0302: .getPath());
0303: Utils.updateProperties(helper,
0304: AntProjectHelper.PROJECT_PROPERTIES_PATH,
0305: properties);
0306: getWebProjectProperties().store();
0307: }
0308: }
0309: updateFileChangeListener();
0310: }
0311:
0312: public void fileAttributeChanged(FileAttributeEvent fe) {
0313: }
0314: };
0315:
0316: WebProject(final AntProjectHelper helper) throws IOException {
0317: this .helper = helper;
0318: eval = createEvaluator();
0319: aux = helper.createAuxiliaryConfiguration();
0320: refHelper = new ReferenceHelper(helper, aux, eval);
0321: buildExtender = AntBuildExtenderFactory
0322: .createAntExtender(new WebExtenderImplementation());
0323: genFilesHelper = new GeneratedFilesHelper(helper, buildExtender);
0324: updateProject = new UpdateProjectImpl(this , this .helper, aux);
0325: this .updateHelper = new UpdateHelper(updateProject, helper);
0326: updateProject.setUpdateHelper(updateHelper);
0327: this .cpProvider = new ClassPathProviderImpl(this .helper,
0328: evaluator(), getSourceRoots(), getTestSourceRoots());
0329: webModule = new ProjectWebModule(this , updateHelper, cpProvider);
0330: apiWebModule = WebModuleFactory.createWebModule(webModule);
0331: WebProjectWebServicesSupport webProjectWebServicesSupport = new WebProjectWebServicesSupport(
0332: this , helper, refHelper);
0333: WebProjectJAXWSSupport jaxwsSupport = new WebProjectJAXWSSupport(
0334: this , helper);
0335: WebProjectJAXWSClientSupport jaxWsClientSupport = new WebProjectJAXWSClientSupport(
0336: this );
0337: WebProjectWebServicesClientSupport webProjectWebServicesClientSupport = new WebProjectWebServicesClientSupport(
0338: this , helper, refHelper);
0339: apiWebServicesSupport = WebServicesSupportFactory
0340: .createWebServicesSupport(webProjectWebServicesSupport);
0341: apiJaxwsSupport = JAXWSSupportFactory
0342: .createJAXWSSupport(jaxwsSupport);
0343: apiWebServicesClientSupport = WebServicesClientSupportFactory
0344: .createWebServicesClientSupport(webProjectWebServicesClientSupport);
0345: apiJAXWSClientSupport = JAXWSClientSupportFactory
0346: .createJAXWSClientSupport(jaxWsClientSupport);
0347: enterpriseResourceSupport = new WebContainerImpl(this ,
0348: refHelper, helper);
0349: cpMod = new ClassPathModifier(this , this .updateHelper, eval,
0350: refHelper, new ClassPathSupportCallbackImpl(helper),
0351: createClassPathModifierCallback(),
0352: getClassPathUiSupportCallback(), new String[] {
0353: ProjectProperties.JAVAC_CLASSPATH,
0354: WebProjectProperties.WAR_CONTENT_ADDITIONAL });
0355: libMod = new WebProjectLibrariesModifierImpl(this ,
0356: this .updateHelper, eval, refHelper);
0357: classPathExtender = new ClassPathExtender(cpMod,
0358: ProjectProperties.JAVAC_CLASSPATH,
0359: ClassPathSupportCallbackImpl.TAG_WEB_MODULE_LIBRARIES);
0360: librariesLocationUpdater = new LibrariesLocationUpdater(
0361: this ,
0362: updateHelper,
0363: eval,
0364: cpMod.getClassPathSupport(),
0365: ProjectProperties.JAVAC_CLASSPATH,
0366: WebProjectProperties.TAG_WEB_MODULE_LIBRARIES,
0367: WebProjectProperties.WAR_CONTENT_ADDITIONAL,
0368: WebProjectProperties.TAG_WEB_MODULE__ADDITIONAL_LIBRARIES);
0369: lookup = createLookup(aux, cpProvider);
0370: helper.addAntProjectListener(this );
0371: css = new CopyOnSaveSupport();
0372: webPagesFileWatch = new FileWatch(
0373: WebProjectProperties.WEB_DOCBASE_DIR);
0374: webInfFileWatch = new FileWatch(WebProjectProperties.WEBINF_DIR);
0375: }
0376:
0377: private ClassPathModifier.Callback createClassPathModifierCallback() {
0378: return new ClassPathModifier.Callback() {
0379: public String getClassPathProperty(SourceGroup sg,
0380: String type) {
0381: assert sg != null : "SourceGroup cannot be null"; //NOI18N
0382: assert type != null : "Type cannot be null"; //NOI18N
0383: final String classPathProperty = getClassPathProvider()
0384: .getPropertyName(sg, type);
0385: if (classPathProperty == null) {
0386: throw new UnsupportedOperationException(
0387: "Modification of ["
0388: + sg.getRootFolder().getPath()
0389: + ", " + type
0390: + "] is not supported"); //NOI8N
0391: }
0392: return classPathProperty;
0393: }
0394:
0395: public String getElementName(String classpathProperty) {
0396: if (ProjectProperties.JAVAC_CLASSPATH
0397: .equals(classpathProperty)) {
0398: return ClassPathSupportCallbackImpl.TAG_WEB_MODULE_LIBRARIES;
0399: }
0400: return null;
0401: }
0402: };
0403: }
0404:
0405: public synchronized ClassPathUiSupport.Callback getClassPathUiSupportCallback() {
0406: if (classPathUiSupportCallback == null) {
0407: classPathUiSupportCallback = new ClassPathUiSupport.Callback() {
0408: public void initItem(ClassPathSupport.Item item) {
0409: switch (item.getType()) {
0410: case ClassPathSupport.Item.TYPE_JAR:
0411: item
0412: .setAdditionalProperty(
0413: ClassPathSupportCallbackImpl.PATH_IN_DEPLOYMENT,
0414: item.getResolvedFile()
0415: .isDirectory() ? ClassPathSupportCallbackImpl.PATH_IN_WAR_DIR
0416: : ClassPathSupportCallbackImpl.PATH_IN_WAR_LIB);
0417: break;
0418: case ClassPathSupport.Item.TYPE_LIBRARY:
0419: if (item.getLibrary().getType().equals(
0420: J2eePlatform.LIBRARY_TYPE)) {
0421: break;
0422: }
0423: default:
0424: item
0425: .setAdditionalProperty(
0426: ClassPathSupportCallbackImpl.PATH_IN_DEPLOYMENT,
0427: ClassPathSupportCallbackImpl.PATH_IN_WAR_LIB);
0428: }
0429: }
0430: };
0431:
0432: }
0433: return classPathUiSupportCallback;
0434: }
0435:
0436: public UpdateProjectImpl getUpdateImplementation() {
0437: return updateProject;
0438: }
0439:
0440: public FileObject getProjectDirectory() {
0441: return helper.getProjectDirectory();
0442: }
0443:
0444: public UpdateHelper getUpdateHelper() {
0445: return updateHelper;
0446: }
0447:
0448: public String toString() {
0449: return "WebProject[" + getProjectDirectory() + "]"; // NOI18N
0450: }
0451:
0452: private PropertyEvaluator createEvaluator() {
0453: // XXX might need to use a custom evaluator to handle active platform substitutions... TBD
0454: // It is currently safe to not use the UpdateHelper for PropertyEvaluator; UH.getProperties() delegates to APH
0455: return helper.getStandardPropertyEvaluator();
0456: }
0457:
0458: public PropertyEvaluator evaluator() {
0459: return eval;
0460: }
0461:
0462: public ReferenceHelper getReferenceHelper() {
0463: return this .refHelper;
0464: }
0465:
0466: public Lookup getLookup() {
0467: return lookup;
0468: }
0469:
0470: public AntProjectHelper getAntProjectHelper() {
0471: return helper;
0472: }
0473:
0474: private Lookup createLookup(AuxiliaryConfiguration aux,
0475: ClassPathProviderImpl cpProvider) {
0476: SubprojectProvider spp = refHelper.createSubprojectProvider();
0477: final WebSources webSources = new WebSources(this .helper,
0478: evaluator(), getSourceRoots(), getTestSourceRoots());
0479: Lookup base = Lookups
0480: .fixed(new Object[] {
0481: new Info(),
0482: aux,
0483: helper.createCacheDirectoryProvider(),
0484: spp,
0485: new ProjectWebModuleProvider(),
0486: new ProjectWebServicesSupportProvider(),
0487: webModule, //implements J2eeModuleProvider
0488: enterpriseResourceSupport,
0489: new WebActionProvider(this , this .updateHelper),
0490: new WebLogicalViewProvider(this ,
0491: this .updateHelper, evaluator(),
0492: refHelper),
0493: new CustomizerProviderImpl(this ,
0494: this .updateHelper, evaluator(),
0495: refHelper),
0496: new ClassPathProviderMerger(cpProvider),
0497: QuerySupport
0498: .createCompiledSourceForBinaryQuery(
0499: helper, evaluator(),
0500: getSourceRoots(),
0501: getTestSourceRoots()),
0502: QuerySupport.createJavadocForBinaryQuery(
0503: helper, evaluator()),
0504: new AntArtifactProviderImpl(),
0505: new ProjectXmlSavedHookImpl(),
0506: UILookupMergerSupport
0507: .createProjectOpenHookMerger(new ProjectOpenedHookImpl()),
0508: QuerySupport.createUnitTestForSourceQuery(
0509: getSourceRoots(), getTestSourceRoots()),
0510: QuerySupport
0511: .createSourceLevelQuery(evaluator()),
0512: webSources,
0513: new GsfClassPathProviderImpl(helper,
0514: evaluator(), webSources),
0515: QuerySupport.createSharabilityQuery(helper,
0516: evaluator(), getSourceRoots(),
0517: getTestSourceRoots(),
0518: WebProjectProperties.WEB_DOCBASE_DIR),
0519: new RecommendedTemplatesImpl(),
0520: QuerySupport.createFileBuiltQuery(helper,
0521: evaluator(), getSourceRoots(),
0522: getTestSourceRoots()),
0523: classPathExtender,
0524: buildExtender,
0525: cpMod,
0526: new WebProjectOperations(this ),
0527: new WebPersistenceProvider(this , evaluator(),
0528: cpProvider),
0529: new WebPersistenceProviderSupplier(this ),
0530: new WebEMGenStrategyResolver(),
0531: new WebJPADataSourceSupport(this ),
0532: new WebServerStatusProvider(this ),
0533: new WebJPAModuleInfo(this ),
0534: new WebProjectJAXWSVersionProvider(helper, this ),
0535: UILookupMergerSupport
0536: .createPrivilegedTemplatesMerger(),
0537: UILookupMergerSupport
0538: .createRecommendedTemplatesMerger(),
0539: LookupProviderSupport.createSourcesMerger(),
0540: new WebPropertyEvaluatorImpl(evaluator()),
0541: WebProject.this , // never cast an externally obtained Project to WebProject - use lookup instead
0542: libMod,
0543: QuerySupport.createFileEncodingQuery(
0544: evaluator(),
0545: WebProjectProperties.SOURCE_ENCODING),
0546: new WebTemplateAttributesProvider(this .helper),
0547: ExtraSourceJavadocSupport
0548: .createExtraSourceQueryImplementation(
0549: this , helper, eval),
0550: LookupMergerSupport.createSFBLookupMerger(),
0551: ExtraSourceJavadocSupport
0552: .createExtraJavadocQueryImplementation(
0553: this , helper, eval),
0554: LookupMergerSupport.createJFBLookupMerger(), });
0555: return LookupProviderSupport.createCompositeLookup(base,
0556: "Projects/org-netbeans-modules-web-project/Lookup"); //NOI18N
0557: }
0558:
0559: public ClassPathProviderImpl getClassPathProvider() {
0560: return this .cpProvider;
0561: }
0562:
0563: public void configurationXmlChanged(AntProjectEvent ev) {
0564: if (ev.getPath().equals(AntProjectHelper.PROJECT_XML_PATH)) {
0565: // Could be various kinds of changes, but name & displayName might have changed.
0566: Info info = (Info) getLookup().lookup(
0567: ProjectInformation.class);
0568: info.firePropertyChange(ProjectInformation.PROP_NAME);
0569: info
0570: .firePropertyChange(ProjectInformation.PROP_DISPLAY_NAME);
0571: }
0572: }
0573:
0574: public void propertiesChanged(AntProjectEvent ev) {
0575: // currently ignored (probably better to listen to evaluator() if you need to)
0576: }
0577:
0578: String getBuildXmlName() {
0579: String storedName = helper.getStandardPropertyEvaluator()
0580: .getProperty(WebProjectProperties.BUILD_FILE);
0581: return storedName == null ? GeneratedFilesHelper.BUILD_XML_PATH
0582: : storedName;
0583: }
0584:
0585: // Package private methods -------------------------------------------------
0586:
0587: /**
0588: * Returns the source roots of this project
0589: * @return project's source roots
0590: */
0591: public synchronized SourceRoots getSourceRoots() {
0592: if (this .sourceRoots == null) { //Local caching, no project metadata access
0593: this .sourceRoots = SourceRoots.create(updateHelper,
0594: evaluator(), getReferenceHelper(),
0595: WebProjectType.PROJECT_CONFIGURATION_NAMESPACE,
0596: "source-roots", false, "src.{0}{1}.dir"); //NOI18N
0597: }
0598: return this .sourceRoots;
0599: }
0600:
0601: public synchronized SourceRoots getTestSourceRoots() {
0602: if (this .testRoots == null) { //Local caching, no project metadata access
0603: this .testRoots = SourceRoots.create(this .updateHelper,
0604: evaluator(), getReferenceHelper(),
0605: WebProjectType.PROJECT_CONFIGURATION_NAMESPACE,
0606: "test-roots", true, "test.{0}{1}.dir"); //NOI18N
0607: }
0608: return this .testRoots;
0609: }
0610:
0611: File getTestClassesDirectory() {
0612: String testClassesDir = evaluator().getProperty(
0613: ProjectProperties.BUILD_TEST_CLASSES_DIR);
0614: if (testClassesDir == null) {
0615: return null;
0616: }
0617: return helper.resolveFile(testClassesDir);
0618: }
0619:
0620: public ProjectWebModule getWebModule() {
0621: return webModule;
0622: }
0623:
0624: public WebModule getAPIWebModule() {
0625: return apiWebModule;
0626: }
0627:
0628: WebServicesSupport getAPIWebServicesSupport() {
0629: return apiWebServicesSupport;
0630: }
0631:
0632: JAXWSSupport getAPIJAXWSSupport() {
0633: return apiJaxwsSupport;
0634: }
0635:
0636: WebServicesClientSupport getAPIWebServicesClientSupport() {
0637: return apiWebServicesClientSupport;
0638: }
0639:
0640: JAXWSClientSupport getAPIJAXWSClientSupport() {
0641: return apiJAXWSClientSupport;
0642: }
0643:
0644: public WebProjectProperties getWebProjectProperties() {
0645: return new WebProjectProperties(this , updateHelper, eval,
0646: refHelper);
0647: }
0648:
0649: /** Return configured project name. */
0650: public String getName() {
0651: return (String) ProjectManager.mutex().readAccess(
0652: new Mutex.Action() {
0653: public Object run() {
0654: Element data = helper
0655: .getPrimaryConfigurationData(true);
0656: // XXX replace by XMLUtil when that has findElement, findText, etc.
0657: NodeList nl = data
0658: .getElementsByTagNameNS(
0659: WebProjectType.PROJECT_CONFIGURATION_NAMESPACE,
0660: "name");
0661: if (nl.getLength() == 1) {
0662: nl = nl.item(0).getChildNodes();
0663: if (nl.getLength() == 1
0664: && nl.item(0).getNodeType() == Node.TEXT_NODE) {
0665: return ((Text) nl.item(0))
0666: .getNodeValue();
0667: }
0668: }
0669: return "???"; // NOI18N
0670: }
0671: });
0672: }
0673:
0674: /** Store configured project name. */
0675: public void setName(final String name) {
0676: ProjectManager.mutex().writeAccess(new Mutex.Action() {
0677: public Object run() {
0678: Element data = helper.getPrimaryConfigurationData(true);
0679: // XXX replace by XMLUtil when that has findElement, findText, etc.
0680: NodeList nl = data.getElementsByTagNameNS(
0681: WebProjectType.PROJECT_CONFIGURATION_NAMESPACE,
0682: "name");
0683: Element nameEl;
0684: if (nl.getLength() == 1) {
0685: nameEl = (Element) nl.item(0);
0686: NodeList deadKids = nameEl.getChildNodes();
0687: while (deadKids.getLength() > 0) {
0688: nameEl.removeChild(deadKids.item(0));
0689: }
0690: } else {
0691: nameEl = data
0692: .getOwnerDocument()
0693: .createElementNS(
0694: WebProjectType.PROJECT_CONFIGURATION_NAMESPACE,
0695: "name");
0696: data.insertBefore(nameEl, /* OK if null */data
0697: .getChildNodes().item(0));
0698: }
0699: nameEl.appendChild(data.getOwnerDocument()
0700: .createTextNode(name));
0701: helper.putPrimaryConfigurationData(data, true);
0702: return null;
0703: }
0704: });
0705: }
0706:
0707: public void registerJ2eePlatformListener(final J2eePlatform platform) {
0708: // listen to classpath changes
0709: j2eePlatformListener = new PropertyChangeListener() {
0710: public void propertyChange(PropertyChangeEvent evt) {
0711: if (evt.getPropertyName().equals(
0712: J2eePlatform.PROP_CLASSPATH)) {
0713: ProjectManager.mutex().writeAccess(
0714: new Mutex.Action() {
0715: public Object run() {
0716: EditableProperties ep = helper
0717: .getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH);
0718: EditableProperties projectProps = helper
0719: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
0720:
0721: if (!ProjectProperties
0722: .isUsingServerLibrary(
0723: projectProps,
0724: WebProjectProperties.J2EE_PLATFORM_CLASSPATH)) {
0725: String classpath = Utils
0726: .toClasspathString(platform
0727: .getClasspathEntries());
0728: ep
0729: .setProperty(
0730: WebProjectProperties.J2EE_PLATFORM_CLASSPATH,
0731: classpath);
0732: }
0733: helper
0734: .putProperties(
0735: AntProjectHelper.PRIVATE_PROPERTIES_PATH,
0736: ep);
0737: try {
0738: ProjectManager
0739: .getDefault()
0740: .saveProject(
0741: WebProject.this );
0742: } catch (IOException e) {
0743: Exceptions.printStackTrace(e);
0744: }
0745: return null;
0746: }
0747: });
0748: }
0749: }
0750: };
0751: platform.addPropertyChangeListener(j2eePlatformListener);
0752: }
0753:
0754: public void unregisterJ2eePlatformListener(J2eePlatform platform) {
0755: if (j2eePlatformListener != null) {
0756: platform.removePropertyChangeListener(j2eePlatformListener);
0757: }
0758: }
0759:
0760: // Private innerclasses ----------------------------------------------------
0761:
0762: //when #110886 gets implemented, this class is obsolete
0763: private final class Info implements ProjectInformation {
0764:
0765: private final PropertyChangeSupport pcs = new PropertyChangeSupport(
0766: this );
0767: private WeakReference<String> cachedName = null;
0768:
0769: Info() {
0770: }
0771:
0772: void firePropertyChange(String prop) {
0773: pcs.firePropertyChange(prop, null, null);
0774: synchronized (pcs) {
0775: cachedName = null;
0776: }
0777: }
0778:
0779: public String getName() {
0780: return WebProject.this .getName();
0781: }
0782:
0783: public String getDisplayName() {
0784: synchronized (pcs) {
0785: if (cachedName != null) {
0786: String dn = cachedName.get();
0787: if (dn != null) {
0788: return dn;
0789: }
0790: }
0791: }
0792: String dn = ProjectManager.mutex().readAccess(
0793: new Mutex.Action<String>() {
0794: public String run() {
0795: Element data = updateHelper
0796: .getPrimaryConfigurationData(true);
0797: // XXX replace by XMLUtil when that has findElement, findText, etc.
0798: NodeList nl = data
0799: .getElementsByTagNameNS(
0800: WebProjectType.PROJECT_CONFIGURATION_NAMESPACE,
0801: "name"); // NOI18N
0802: if (nl.getLength() == 1) {
0803: nl = nl.item(0).getChildNodes();
0804: if (nl.getLength() == 1
0805: && nl.item(0).getNodeType() == Node.TEXT_NODE) {
0806: return ((Text) nl.item(0))
0807: .getNodeValue();
0808: }
0809: }
0810: return "???"; // NOI18N
0811: }
0812: });
0813: synchronized (pcs) {
0814: cachedName = new WeakReference<String>(dn);
0815: }
0816: return dn;
0817: }
0818:
0819: public Icon getIcon() {
0820: return WEB_PROJECT_ICON;
0821: }
0822:
0823: public Project getProject() {
0824: return WebProject.this ;
0825: }
0826:
0827: public void addPropertyChangeListener(
0828: PropertyChangeListener listener) {
0829: pcs.addPropertyChangeListener(listener);
0830: }
0831:
0832: public void removePropertyChangeListener(
0833: PropertyChangeListener listener) {
0834: pcs.removePropertyChangeListener(listener);
0835: }
0836:
0837: }
0838:
0839: private final class ProjectXmlSavedHookImpl extends
0840: ProjectXmlSavedHook {
0841:
0842: ProjectXmlSavedHookImpl() {
0843: }
0844:
0845: protected void projectXmlSaved() throws IOException {
0846: int flags = genFilesHelper.getBuildScriptState(
0847: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
0848: WebProject.class
0849: .getResource("resources/build-impl.xsl"));
0850: if ((flags & GeneratedFilesHelper.FLAG_MODIFIED) != 0) {
0851: RequestProcessor.getDefault().post(new Runnable() {
0852: public void run() {
0853: JButton updateOption = new JButton(NbBundle
0854: .getMessage(WebProject.class,
0855: "CTL_Regenerate"));
0856: if (DialogDisplayer
0857: .getDefault()
0858: .notify(
0859: new NotifyDescriptor(
0860: NbBundle
0861: .getMessage(
0862: WebProject.class,
0863: "TXT_BuildImplRegenerate"),
0864: NbBundle
0865: .getMessage(
0866: WebProject.class,
0867: "TXT_BuildImplRegenerateTitle"),
0868: NotifyDescriptor.DEFAULT_OPTION,
0869: NotifyDescriptor.WARNING_MESSAGE,
0870: new Object[] {
0871: updateOption,
0872: NotifyDescriptor.CANCEL_OPTION },
0873: updateOption)) == updateOption) {
0874: try {
0875: genFilesHelper
0876: .generateBuildScriptFromStylesheet(
0877: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
0878: WebProject.class
0879: .getResource("resources/build-impl.xsl"));
0880: } catch (IOException e) {
0881: Exceptions.printStackTrace(e);
0882: } catch (IllegalStateException e) {
0883: Exceptions.printStackTrace(e);
0884: }
0885: }
0886: }
0887: });
0888: } else {
0889: genFilesHelper
0890: .refreshBuildScript(
0891: org.netbeans.modules.websvc.api.jaxws.project.GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
0892: org.netbeans.modules.web.project.WebProject.class
0893: .getResource("resources/build-impl.xsl"),
0894: false);
0895: }
0896: genFilesHelper
0897: .refreshBuildScript(
0898: getBuildXmlName(),
0899: WebProject.class
0900: .getResource("resources/build.xsl"),
0901: false);
0902: }
0903:
0904: }
0905:
0906: final class ProjectOpenedHookImpl extends ProjectOpenedHook {
0907:
0908: ProjectOpenedHookImpl() {
0909: }
0910:
0911: protected void projectOpened() {
0912: try {
0913: getProjectDirectory().getFileSystem().runAtomicAction(
0914: new AtomicAction() {
0915: public void run() throws IOException {
0916: ProjectManager.mutex().writeAccess(
0917: new Runnable() {
0918: public void run() {
0919: updateProject();
0920: }
0921: });
0922: }
0923: });
0924: } catch (IOException e) {
0925: Logger.getLogger("global").log(Level.INFO, null, e);
0926: }
0927:
0928: try {
0929: //DDDataObject initialization to be ready to listen on changes (#45771)
0930: try {
0931: FileObject ddFO = webModule
0932: .getDeploymentDescriptor();
0933: if (ddFO != null) {
0934: DataObject dobj = DataObject.find(ddFO);
0935: }
0936: } catch (org.openide.loaders.DataObjectNotFoundException ex) {
0937: //PENDING
0938: }
0939:
0940: // Register copy on save support
0941: css.initialize();
0942:
0943: // Check up on build scripts.
0944: if (updateHelper.isCurrent()) {
0945: int flags = genFilesHelper
0946: .getBuildScriptState(
0947: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
0948: WebProject.class
0949: .getResource("resources/build-impl.xsl"));
0950: if ((flags & GeneratedFilesHelper.FLAG_MODIFIED) != 0
0951: && (flags & GeneratedFilesHelper.FLAG_OLD_PROJECT_XML) != 0) {
0952: JButton updateOption = new JButton(NbBundle
0953: .getMessage(WebProject.class,
0954: "CTL_Regenerate"));
0955: if (DialogDisplayer
0956: .getDefault()
0957: .notify(
0958: new NotifyDescriptor(
0959: NbBundle
0960: .getMessage(
0961: WebProject.class,
0962: "TXT_BuildImplRegenerate"),
0963: NbBundle
0964: .getMessage(
0965: WebProject.class,
0966: "TXT_BuildImplRegenerateTitle"),
0967: NotifyDescriptor.DEFAULT_OPTION,
0968: NotifyDescriptor.WARNING_MESSAGE,
0969: new Object[] {
0970: updateOption,
0971: NotifyDescriptor.CANCEL_OPTION },
0972: updateOption)) == updateOption) {
0973: genFilesHelper
0974: .generateBuildScriptFromStylesheet(
0975: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
0976: WebProject.class
0977: .getResource("resources/build-impl.xsl"));
0978: }
0979: } else {
0980: genFilesHelper
0981: .refreshBuildScript(
0982: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
0983: WebProject.class
0984: .getResource("resources/build-impl.xsl"),
0985: true);
0986: }
0987: genFilesHelper
0988: .refreshBuildScript(
0989: getBuildXmlName(),
0990: WebProject.class
0991: .getResource("resources/build.xsl"),
0992: true);
0993:
0994: WebProjectProperties wpp = getWebProjectProperties();
0995: String servInstID = (String) wpp
0996: .get(WebProjectProperties.J2EE_SERVER_INSTANCE);
0997: String serverType = null;
0998: J2eePlatform platform = Deployment.getDefault()
0999: .getJ2eePlatform(servInstID);
1000: if (platform != null) {
1001: // updates j2ee.platform.cp & wscompile.cp & reg. j2ee platform listener
1002: WebProjectProperties.setServerInstance(
1003: WebProject.this ,
1004: WebProject.this .updateHelper,
1005: servInstID);
1006: } else {
1007: // if there is some server instance of the type which was used
1008: // previously do not ask and use it
1009: serverType = (String) wpp
1010: .get(WebProjectProperties.J2EE_SERVER_TYPE);
1011: if (serverType != null) {
1012: String[] servInstIDs = Deployment
1013: .getDefault().getInstancesOfServer(
1014: serverType);
1015: if (servInstIDs.length > 0) {
1016: WebProjectProperties.setServerInstance(
1017: WebProject.this ,
1018: WebProject.this .updateHelper,
1019: servInstIDs[0]);
1020: platform = Deployment
1021: .getDefault()
1022: .getJ2eePlatform(servInstIDs[0]);
1023: }
1024: }
1025: if (platform == null) {
1026: BrokenServerSupport.showAlert();
1027: }
1028: }
1029: // UI Logging
1030: LogRecord logRecord = new LogRecord(Level.INFO,
1031: "UI_WEB_PROJECT_OPENED"); //NOI18N
1032: logRecord.setLoggerName(UI_LOGGER_NAME); //NOI18N
1033: logRecord.setResourceBundle(NbBundle
1034: .getBundle(WebProject.class));
1035: logRecord.setParameters(new Object[] {
1036: (serverType != null ? serverType
1037: : Deployment.getDefault()
1038: .getServerID(servInstID)),
1039: servInstID });
1040: Logger.getLogger(UI_LOGGER_NAME).log(logRecord);
1041: }
1042:
1043: } catch (IOException e) {
1044: Logger.getLogger("global").log(Level.INFO, null, e);
1045: }
1046:
1047: // register project's classpaths to GlobalPathRegistry
1048: GlobalPathRegistry.getDefault().register(ClassPath.BOOT,
1049: cpProvider.getProjectClassPaths(ClassPath.BOOT));
1050: GlobalPathRegistry.getDefault().register(ClassPath.SOURCE,
1051: cpProvider.getProjectClassPaths(ClassPath.SOURCE));
1052: GlobalPathRegistry.getDefault().register(ClassPath.COMPILE,
1053: cpProvider.getProjectClassPaths(ClassPath.COMPILE));
1054:
1055: GsfClassPathProviderImpl gsfCpProvider = getLookup()
1056: .lookup(GsfClassPathProviderImpl.class);
1057: if (gsfCpProvider != null) {
1058: org.netbeans.modules.gsfpath.api.classpath.GlobalPathRegistry
1059: .getDefault()
1060: .register(
1061: org.netbeans.modules.gsfpath.api.classpath.ClassPath.BOOT,
1062: gsfCpProvider
1063: .getProjectClassPaths(org.netbeans.modules.gsfpath.api.classpath.ClassPath.BOOT));
1064: org.netbeans.modules.gsfpath.api.classpath.GlobalPathRegistry
1065: .getDefault()
1066: .register(
1067: org.netbeans.modules.gsfpath.api.classpath.ClassPath.SOURCE,
1068: gsfCpProvider
1069: .getProjectClassPaths(org.netbeans.modules.gsfpath.api.classpath.ClassPath.SOURCE));
1070: }
1071:
1072: // initialize the server configuration
1073: // it MUST BE called AFTER classpaths are registered to GlobalPathRegistry!
1074: // DDProvider (used here) needs classpath set correctly when resolving Java Extents for annotations
1075: webModule.getConfigSupport().ensureConfigurationReady();
1076:
1077: //check the config context path
1078: String ctxRoot = webModule.getContextPath();
1079: if (ctxRoot == null) {
1080: String sysName = getProjectDirectory().getName(); //NOI18N
1081: sysName = Utils.createDefaultContext(sysName); //NOI18N
1082: webModule.setContextPath(sysName);
1083: }
1084:
1085: WebLogicalViewProvider logicalViewProvider = (WebLogicalViewProvider) WebProject.this
1086: .getLookup().lookup(WebLogicalViewProvider.class);
1087: if (logicalViewProvider != null
1088: && logicalViewProvider.hasBrokenLinks()) {
1089: BrokenReferencesSupport.showAlert();
1090: }
1091: webPagesFileWatch.init();
1092: webInfFileWatch.init();
1093: }
1094:
1095: private void updateProject() {
1096: // Make it easier to run headless builds on the same machine at least.
1097: EditableProperties ep = updateHelper
1098: .getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH);
1099: File buildProperties = new File(System
1100: .getProperty("netbeans.user"), "build.properties"); // NOI18N
1101: ep.setProperty("user.properties.file", buildProperties
1102: .getAbsolutePath()); //NOI18N
1103:
1104: // set jaxws.endorsed.dir property (for endorsed mechanism to be used with wsimport, wsgen)
1105: WSUtils.setJaxWsEndorsedDirProperty(ep);
1106:
1107: filterBrokenLibraryRefs();
1108:
1109: EditableProperties props = updateHelper
1110: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH); //Reread the properties, PathParser changes them
1111:
1112: //update lib references in private properties
1113: ArrayList l = new ArrayList();
1114: l
1115: .addAll(cpMod
1116: .getClassPathSupport()
1117: .itemsList(
1118: props
1119: .getProperty(ProjectProperties.JAVAC_CLASSPATH),
1120: WebProjectProperties.TAG_WEB_MODULE_LIBRARIES));
1121: l
1122: .addAll(cpMod
1123: .getClassPathSupport()
1124: .itemsList(
1125: props
1126: .getProperty(WebProjectProperties.WAR_CONTENT_ADDITIONAL),
1127: WebProjectProperties.TAG_WEB_MODULE__ADDITIONAL_LIBRARIES));
1128: ProjectProperties.storeLibrariesLocations(l.iterator(),
1129: props, getProjectDirectory());
1130:
1131: //add webinf.dir required by 6.0 projects
1132: if (props.getProperty(WebProjectProperties.WEBINF_DIR) == null) {
1133: //we can do this because in previous versions WEB-INF was expected under docbase
1134: String web = props
1135: .get(WebProjectProperties.WEB_DOCBASE_DIR);
1136: props.setProperty(WebProjectProperties.WEBINF_DIR, web
1137: + "/WEB-INF"); //NOI18N
1138: }
1139:
1140: updateHelper.putProperties(
1141: AntProjectHelper.PRIVATE_PROPERTIES_PATH, ep);
1142:
1143: // update a dual build directory project to use a single directory
1144: if (updateHelper.isCurrent()) { // #113297, #118187
1145: // this operation should be safe in future as well - of course if properties with the same name weren't re-introduced
1146: props.remove("build.ear.web.dir"); // used to be WebProjectProperties.BUILD_EAR_WEB_DIR // NOI18N
1147: props.remove("build.ear.classes.dir"); // used to be WebProjectProperties.BUILD_EAR_CLASSES_DIR // NOI18N
1148: }
1149: // check debug.classpath - can be done every time, whenever
1150: String debugClassPath = props
1151: .getProperty(WebProjectProperties.DEBUG_CLASSPATH);
1152: props.setProperty(WebProjectProperties.DEBUG_CLASSPATH,
1153: Utils.correctDebugClassPath(debugClassPath));
1154:
1155: updateHelper.putProperties(
1156: AntProjectHelper.PROJECT_PROPERTIES_PATH, props);
1157:
1158: try {
1159: ProjectManager.getDefault()
1160: .saveProject(WebProject.this );
1161: } catch (IOException e) {
1162: Exceptions.printStackTrace(e);
1163: }
1164: }
1165:
1166: /**
1167: * Filters the broken library references (see issue 110040).
1168: */
1169: private void filterBrokenLibraryRefs() {
1170: // filter the compilation CP
1171: EditableProperties props = updateHelper
1172: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
1173: List<ClassPathSupport.Item> toRemove = filterBrokenLibraryItems(cpMod
1174: .getClassPathSupport()
1175: .itemsList(
1176: props
1177: .getProperty(ProjectProperties.JAVAC_CLASSPATH),
1178: WebProjectProperties.TAG_WEB_MODULE_LIBRARIES));
1179: if (!toRemove.isEmpty()) {
1180: LOGGER.log(Level.FINE,
1181: "Will remove broken classpath library references: "
1182: + toRemove);
1183: try {
1184: cpMod
1185: .handleLibraryClassPathItems(
1186: toRemove,
1187: ProjectProperties.JAVAC_CLASSPATH,
1188: WebProjectProperties.TAG_WEB_MODULE_LIBRARIES,
1189: ClassPathModifier.REMOVE, false);
1190: } catch (IOException e) {
1191: // should only occur when passing true as the saveProject parameter which we are not doing here
1192: Exceptions.printStackTrace(e);
1193: }
1194: }
1195: // filter the additional (packaged) items
1196: // need to re-read the properites as the handleLibraryClassPathItems() might have changed them
1197: props = updateHelper
1198: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
1199: toRemove = filterBrokenLibraryItems(libMod
1200: .getClassPathSupport()
1201: .itemsList(
1202: props
1203: .getProperty(WebProjectProperties.WAR_CONTENT_ADDITIONAL),
1204: WebProjectProperties.TAG_WEB_MODULE__ADDITIONAL_LIBRARIES));
1205: if (!toRemove.isEmpty()) {
1206: LOGGER.log(Level.FINE,
1207: "Will remove broken additional library references: "
1208: + toRemove);
1209: try {
1210: libMod.handlePackageLibraryClassPathItems(toRemove,
1211: WebProjectLibrariesModifierImpl.REMOVE,
1212: false);
1213: } catch (IOException e) {
1214: // should only occur when passing true as the saveProject parameter which we are not doing here
1215: Exceptions.printStackTrace(e);
1216: }
1217: }
1218: }
1219:
1220: private List<ClassPathSupport.Item> filterBrokenLibraryItems(
1221: List<ClassPathSupport.Item> items) {
1222: List<ClassPathSupport.Item> toRemove = new LinkedList<ClassPathSupport.Item>();
1223: Collection<? extends BrokenLibraryRefFilter> filters = null;
1224: for (ClassPathSupport.Item item : items) {
1225: if (!item.isBroken()
1226: || item.getType() != ClassPathSupport.Item.TYPE_LIBRARY) {
1227: continue;
1228: }
1229: String libraryName = ClassPathSupport
1230: .getLibraryNameFromReference(item
1231: .getReference());
1232: LOGGER.log(Level.FINE, "Broken reference to library: "
1233: + libraryName);
1234: if (filters == null) {
1235: // initializing the filters lazily because usually they will not be needed anyway
1236: // (most projects have no broken references)
1237: filters = createFilters(WebProject.this );
1238: }
1239: for (BrokenLibraryRefFilter filter : filters) {
1240: if (filter.removeLibraryReference(libraryName)) {
1241: LOGGER.log(Level.FINE,
1242: "Will remove broken reference to library "
1243: + libraryName
1244: + " because of filter "
1245: + filter.getClass().getName());
1246: toRemove.add(item);
1247: break;
1248: }
1249: }
1250: }
1251: return toRemove;
1252: }
1253:
1254: private List<BrokenLibraryRefFilter> createFilters(
1255: Project project) {
1256: List<BrokenLibraryRefFilter> filters = new LinkedList<BrokenLibraryRefFilter>();
1257: for (BrokenLibraryRefFilterProvider provider : Lookups
1258: .forPath(
1259: "Projects/org-netbeans-modules-web-project/BrokenLibraryRefFilterProviders")
1260: .lookupAll(BrokenLibraryRefFilterProvider.class)) { // NOI18N
1261: BrokenLibraryRefFilter filter = provider
1262: .createFilter(project);
1263: if (filter != null) {
1264: filters.add(filter);
1265: }
1266: }
1267: return filters;
1268: }
1269:
1270: protected void projectClosed() {
1271: // unregister project's classpaths to GlobalPathRegistry
1272: GsfClassPathProviderImpl gsfCpProvider = lookup
1273: .lookup(GsfClassPathProviderImpl.class);
1274: if (gsfCpProvider != null) {
1275: //org.netbeans.modules.gsfpath.api.classpath.GlobalPathRegistry.getDefault().unregister(org.netbeans.modules.gsfpath.api.classpath.ClassPath.BOOT, gsfCpProvider.getProjectClassPaths(org.netbeans.modules.gsfpath.api.classpath.ClassPath.BOOT));
1276: org.netbeans.modules.gsfpath.api.classpath.GlobalPathRegistry
1277: .getDefault()
1278: .unregister(
1279: org.netbeans.modules.gsfpath.api.classpath.ClassPath.SOURCE,
1280: gsfCpProvider
1281: .getProjectClassPaths(org.netbeans.modules.gsfpath.api.classpath.ClassPath.SOURCE));
1282: //org.netbeans.modules.gsfpath.api.classpath.GlobalPathRegistry.getDefault().unregister(org.netbeans.modules.gsfpath.api.classpath.ClassPath.COMPILE, gsfCpProvider.getProjectClassPaths(org.netbeans.modules.gsfpath.api.classpath.ClassPath.COMPILE));
1283: }
1284:
1285: webPagesFileWatch.reset();
1286: webInfFileWatch.reset();
1287:
1288: // listen to j2ee platform classpath changes
1289: WebProjectProperties wpp = getWebProjectProperties();
1290: String servInstID = (String) wpp
1291: .get(WebProjectProperties.J2EE_SERVER_INSTANCE);
1292: J2eePlatform platform = Deployment.getDefault()
1293: .getJ2eePlatform(servInstID);
1294: if (platform != null) {
1295: unregisterJ2eePlatformListener(platform);
1296: }
1297:
1298: // unregister the property change listener on the prop evaluator
1299: if (librariesLocationUpdater != null) {
1300: librariesLocationUpdater.destroy();
1301: }
1302:
1303: // remove ServiceListener from jaxWsModel
1304: //if (jaxWsModel!=null) jaxWsModel.removeServiceListener(jaxWsServiceListener);
1305:
1306: // Probably unnecessary, but just in case:
1307: try {
1308: ProjectManager.getDefault()
1309: .saveProject(WebProject.this );
1310: } catch (IOException e) {
1311: Exceptions.printStackTrace(e);
1312: }
1313:
1314: // Unregister copy on save support
1315: try {
1316: css.cleanup();
1317: } catch (FileStateInvalidException e) {
1318: Logger.getLogger("global").log(Level.INFO, null, e);
1319: }
1320:
1321: // unregister project's classpaths to GlobalPathRegistry
1322: GlobalPathRegistry.getDefault().unregister(ClassPath.BOOT,
1323: cpProvider.getProjectClassPaths(ClassPath.BOOT));
1324: GlobalPathRegistry.getDefault().unregister(
1325: ClassPath.SOURCE,
1326: cpProvider.getProjectClassPaths(ClassPath.SOURCE));
1327: GlobalPathRegistry.getDefault().unregister(
1328: ClassPath.COMPILE,
1329: cpProvider.getProjectClassPaths(ClassPath.COMPILE));
1330: }
1331:
1332: }
1333:
1334: /**
1335: * Exports the main JAR as an official build product for use from other scripts.
1336: * The type of the artifact will be {@link AntArtifact#TYPE_JAR}.
1337: */
1338: private final class AntArtifactProviderImpl implements
1339: AntArtifactProvider {
1340:
1341: public AntArtifact[] getBuildArtifacts() {
1342: return new AntArtifact[] {
1343: helper.createSimpleAntArtifact(
1344: WebProjectConstants.ARTIFACT_TYPE_WAR,
1345: "dist.war", evaluator(), "dist", "clean"), // NOI18N
1346: helper
1347: .createSimpleAntArtifact(
1348: WebProjectConstants.ARTIFACT_TYPE_WAR_EAR_ARCHIVE,
1349: "dist.ear.war", evaluator(),
1350: "dist-ear", "clean-ear") // NOI18N
1351: };
1352: }
1353:
1354: }
1355:
1356: // List of primarily supported templates
1357:
1358: private static final String[] TYPES = new String[] {
1359: "java-classes", // NOI18N
1360: "java-main-class", // NOI18N
1361: "java-beans", // NOI18N
1362: "persistence", // NOI18N
1363: "oasis-XML-catalogs", // NOI18N
1364: "XML", // NOI18N
1365: "ant-script", // NOI18N
1366: "ant-task", // NOI18N
1367: "servlet-types", // NOI18N
1368: "web-types", // NOI18N
1369: "web-types-server", // NOI18N
1370: "web-services", // NOI18N
1371: "web-service-clients", // NOI18N
1372: "wsdl", // NOI18N
1373: "junit", // NOI18N
1374: "simple-files" // NOI18N
1375: };
1376:
1377: private static final String[] TYPES_ARCHIVE = new String[] {
1378: "deployment-descriptor", // NOI18N
1379: "XML", // NOI18N
1380: };
1381:
1382: private static final String[] PRIVILEGED_NAMES = new String[] {
1383: "Templates/JSP_Servlet/JSP.jsp", // NOI18N
1384: "Templates/JSP_Servlet/Html.html", // NOI18N
1385: "Templates/JSP_Servlet/Servlet.java", // NOI18N
1386: "Templates/Classes/Class.java", // NOI18N
1387: "Templates/Classes/Package", // NOI18N
1388: "Templates/WebServices/WebService.java", // NOI18N
1389: "Templates/WebServices/WebServiceClient", // NOI18N
1390: "Templates/Other/Folder" // NOI18N
1391: };
1392:
1393: private static final String[] PRIVILEGED_NAMES_EE5 = new String[] {
1394: "Templates/JSP_Servlet/JSP.jsp", // NOI18N
1395: "Templates/JSP_Servlet/Html.html", // NOI18N
1396: "Templates/JSP_Servlet/Servlet.java", // NOI18N
1397: "Templates/Classes/Class.java", // NOI18N
1398: "Templates/Classes/Package", // NOI18N
1399: "Templates/Persistence/Entity.java", // NOI18N
1400: "Templates/Persistence/RelatedCMP", // NOI18N
1401: "Templates/Persistence/JsfFromDB", // NOI18N
1402: "Templates/WebServices/WebService.java", // NOI18N
1403: "Templates/WebServices/WebServiceFromWSDL.java", // NOI18N
1404: "Templates/WebServices/WebServiceClient", // NOI18N
1405: "Templates/Other/Folder", // NOI18N
1406: };
1407:
1408: private static final String[] PRIVILEGED_NAMES_ARCHIVE = new String[] { "Templates/JSP_Servlet/webXml", // NOI18N ---
1409: };
1410:
1411: // guarded by this, #115809
1412: private String[] privilegedTemplatesEE5 = null;
1413: private String[] privilegedTemplates = null;
1414:
1415: // Path where instances of privileged templates are registered
1416: private static final String WEBTEMPLATE_PATH = "j2ee/webtier/templates"; //NOI18N
1417:
1418: synchronized String[] getPrivilegedTemplates() {
1419: ensureTemplatesInitialized();
1420: return privilegedTemplates;
1421: }
1422:
1423: synchronized String[] getPrivilegedTemplatesEE5() {
1424: ensureTemplatesInitialized();
1425: return privilegedTemplatesEE5;
1426: }
1427:
1428: public synchronized void resetTemplates() {
1429: privilegedTemplates = null;
1430: privilegedTemplatesEE5 = null;
1431: }
1432:
1433: private void ensureTemplatesInitialized() {
1434: assert Thread.holdsLock(this );
1435: if (privilegedTemplates != null
1436: && privilegedTemplatesEE5 != null) {
1437: return;
1438: }
1439:
1440: ArrayList<String> templatesEE5 = new ArrayList(
1441: PRIVILEGED_NAMES_EE5.length + 1);
1442: ArrayList<String> templates = new ArrayList(
1443: PRIVILEGED_NAMES.length + 1);
1444:
1445: // how many templates are added
1446: int countTemplate = 0;
1447: Collection<WebPrivilegedTemplates> pfTemplates = (Collection<WebPrivilegedTemplates>) Lookups
1448: .forPath(WEBTEMPLATE_PATH).lookupAll(
1449: WebPrivilegedTemplates.class);
1450:
1451: for (WebPrivilegedTemplates webPrivililegedTemplates : pfTemplates) {
1452: String[] addedTemplates = webPrivililegedTemplates
1453: .getPrivilegedTemplates(apiWebModule);
1454: if (addedTemplates != null && addedTemplates.length > 0) {
1455: countTemplate = countTemplate + addedTemplates.length;
1456: List addedList = Arrays.asList(addedTemplates);
1457: templatesEE5.addAll(addedList);
1458: templates.addAll(addedList);
1459: }
1460: }
1461:
1462: if (countTemplate > 0) {
1463: templatesEE5.addAll(Arrays.asList(PRIVILEGED_NAMES_EE5));
1464: privilegedTemplatesEE5 = templatesEE5
1465: .toArray(new String[templatesEE5.size()]);
1466: templates.addAll(Arrays.asList(PRIVILEGED_NAMES));
1467: privilegedTemplates = templates
1468: .toArray(new String[templates.size()]);
1469: } else {
1470: privilegedTemplatesEE5 = PRIVILEGED_NAMES_EE5;
1471: privilegedTemplates = PRIVILEGED_NAMES;
1472: }
1473: }
1474:
1475: private final class RecommendedTemplatesImpl implements
1476: RecommendedTemplates, PrivilegedTemplates {
1477: RecommendedTemplatesImpl() {
1478: }
1479:
1480: private boolean isEE5 = false;
1481: private boolean checked = false;
1482: private boolean isArchive = false;
1483:
1484: public String[] getRecommendedTypes() {
1485: String[] retVal = null;
1486: checkEnvironment();
1487: if (isArchive) {
1488: retVal = TYPES_ARCHIVE;
1489: } else {
1490: retVal = TYPES;
1491: }
1492:
1493: return retVal;
1494: }
1495:
1496: public String[] getPrivilegedTemplates() {
1497: String[] retVal = null;
1498: checkEnvironment();
1499: if (isArchive) {
1500: retVal = PRIVILEGED_NAMES_ARCHIVE;
1501: } else {
1502: if (isEE5) {
1503: retVal = getPrivilegedTemplatesEE5();
1504: } else {
1505: retVal = WebProject.this .getPrivilegedTemplates();
1506: }
1507: }
1508: return retVal;
1509: }
1510:
1511: private void checkEnvironment() {
1512: if (!checked) {
1513: final Object srcType = helper
1514: .getStandardPropertyEvaluator().getProperty(
1515: WebProjectProperties.JAVA_SOURCE_BASED);
1516: if ("false".equals(srcType)) {
1517: isArchive = true;
1518: }
1519: isEE5 = J2eeModule.JAVA_EE_5.equals(getAPIWebModule()
1520: .getJ2eePlatformVersion());
1521: checked = true;
1522: }
1523: }
1524:
1525: }
1526:
1527: public class CopyOnSaveSupport extends FileChangeAdapter implements
1528: PropertyChangeListener {
1529: private FileObject docBase = null;
1530:
1531: /** Creates a new instance of CopyOnSaveSupport */
1532: public CopyOnSaveSupport() {
1533: }
1534:
1535: public void initialize() throws FileStateInvalidException {
1536: docBase = getWebModule().getDocumentBase();
1537: if (docBase != null) {
1538: docBase.getFileSystem().addFileChangeListener(this );
1539: }
1540: ProjectInformation info = (ProjectInformation) getLookup()
1541: .lookup(ProjectInformation.class);
1542: info.addPropertyChangeListener(this );
1543: }
1544:
1545: public void cleanup() throws FileStateInvalidException {
1546: if (docBase != null) {
1547: docBase.getFileSystem().removeFileChangeListener(this );
1548: }
1549: }
1550:
1551: public void propertyChange(PropertyChangeEvent evt) {
1552: if (evt.getPropertyName().equals(
1553: WebProjectProperties.WEB_DOCBASE_DIR)) {
1554: try {
1555: cleanup();
1556: initialize();
1557: } catch (org.openide.filesystems.FileStateInvalidException e) {
1558: Logger.getLogger("global").log(Level.INFO, null, e);
1559: }
1560: }
1561: }
1562:
1563: /** Fired when a file is changed.
1564: * @param fe the event describing context where action has taken place
1565: */
1566: public void fileChanged(FileEvent fe) {
1567: try {
1568: handleCopyFileToDestDir(fe.getFile());
1569: } catch (IOException e) {
1570: Logger.getLogger("global").log(Level.INFO, null, e);
1571: }
1572: }
1573:
1574: public void fileDataCreated(FileEvent fe) {
1575: try {
1576: handleCopyFileToDestDir(fe.getFile());
1577: } catch (IOException e) {
1578: Logger.getLogger("global").log(Level.INFO, null, e);
1579: }
1580: }
1581:
1582: public void fileRenamed(FileRenameEvent fe) {
1583: try {
1584: FileObject fo = fe.getFile();
1585: FileObject docBase = getWebModule().getDocumentBase();
1586: if (docBase != null && FileUtil.isParentOf(docBase, fo)) {
1587: // inside docbase
1588: handleCopyFileToDestDir(fo);
1589: FileObject parent = fo.getParent();
1590: String path;
1591: if (FileUtil.isParentOf(docBase, parent)) {
1592: path = FileUtil.getRelativePath(docBase, fo
1593: .getParent())
1594: + "/"
1595: + fe.getName()
1596: + "."
1597: + fe.getExt();
1598: } else {
1599: path = fe.getName() + "." + fe.getExt();
1600: }
1601: if (!isSynchronizationAppropriate(path))
1602: return;
1603: handleDeleteFileInDestDir(path);
1604: }
1605: } catch (IOException e) {
1606: Logger.getLogger("global").log(Level.INFO, null, e);
1607: }
1608: }
1609:
1610: public void fileDeleted(FileEvent fe) {
1611: try {
1612: FileObject fo = fe.getFile();
1613: FileObject docBase = getWebModule().getDocumentBase();
1614: if (docBase != null && FileUtil.isParentOf(docBase, fo)) {
1615: // inside docbase
1616: String path = FileUtil.getRelativePath(docBase, fo);
1617: if (!isSynchronizationAppropriate(path))
1618: return;
1619: handleDeleteFileInDestDir(path);
1620: }
1621: } catch (IOException e) {
1622: Logger.getLogger("global").log(Level.INFO, null, e);
1623: }
1624: }
1625:
1626: private boolean isSynchronizationAppropriate(String filePath) {
1627: if (filePath.startsWith("WEB-INF/classes")) {
1628: return false;
1629: }
1630: if (filePath.startsWith("WEB-INF/src")) {
1631: return false;
1632: }
1633: if (filePath.startsWith("WEB-INF/lib")) {
1634: return false;
1635: }
1636: return true;
1637: }
1638:
1639: private void handleDeleteFileInDestDir(String resourcePath)
1640: throws IOException {
1641: FileObject webBuildBase = getWebModule()
1642: .getContentDirectory();
1643: if (webBuildBase != null) {
1644: // project was built
1645: FileObject toDelete = webBuildBase
1646: .getFileObject(resourcePath);
1647: if (toDelete != null) {
1648: toDelete.delete();
1649: }
1650: }
1651: }
1652:
1653: /** Copies a content file to an appropriate destination directory,
1654: * if applicable and relevant.
1655: */
1656: private void handleCopyFileToDestDir(FileObject fo)
1657: throws IOException {
1658: if (!fo.isVirtual()) {
1659: FileObject docBase = getWebModule().getDocumentBase();
1660: if (docBase != null && FileUtil.isParentOf(docBase, fo)) {
1661: // inside docbase
1662: String path = FileUtil.getRelativePath(docBase, fo);
1663: if (!isSynchronizationAppropriate(path))
1664: return;
1665: FileObject webBuildBase = getWebModule()
1666: .getContentDirectory();
1667: if (webBuildBase != null) {
1668: // project was built
1669: if (FileUtil.isParentOf(docBase, webBuildBase)
1670: || FileUtil.isParentOf(webBuildBase,
1671: docBase)) {
1672: //cannot copy into self
1673: return;
1674: }
1675: FileObject destFile = ensureDestinationFileExists(
1676: webBuildBase, path, fo.isFolder());
1677: assert destFile != null : "webBuildBase: "
1678: + webBuildBase + ", path: " + path
1679: + ", isFolder: " + fo.isFolder();
1680: if (!fo.isFolder()) {
1681: InputStream is = null;
1682: OutputStream os = null;
1683: FileLock fl = null;
1684: try {
1685: is = fo.getInputStream();
1686: fl = destFile.lock();
1687: os = destFile.getOutputStream(fl);
1688: FileUtil.copy(is, os);
1689: } finally {
1690: if (is != null) {
1691: is.close();
1692: }
1693: if (os != null) {
1694: os.close();
1695: }
1696: if (fl != null) {
1697: fl.releaseLock();
1698: }
1699: }
1700: //System.out.println("copied + " + FileUtil.copy(fo.getInputStream(), destDir, fo.getName(), fo.getExt()));
1701: }
1702: }
1703: }
1704: }
1705: }
1706:
1707: /** Returns the destination (parent) directory needed to create file with relative path path under webBuilBase
1708: */
1709: private FileObject ensureDestinationFileExists(
1710: FileObject webBuildBase, String path, boolean isFolder)
1711: throws IOException {
1712: FileObject current = webBuildBase;
1713: StringTokenizer st = new StringTokenizer(path, "/");
1714: while (st.hasMoreTokens()) {
1715: String pathItem = st.nextToken();
1716: FileObject newCurrent = current.getFileObject(pathItem);
1717: if (newCurrent == null) {
1718: // need to create it
1719: if (isFolder || st.hasMoreTokens()) {
1720: // create a folder
1721: newCurrent = FileUtil.createFolder(current,
1722: pathItem);
1723: assert newCurrent != null : "webBuildBase: "
1724: + webBuildBase + ", path: " + path
1725: + ", isFolder: " + isFolder;
1726: } else {
1727: newCurrent = FileUtil.createData(current,
1728: pathItem);
1729: assert newCurrent != null : "webBuildBase: "
1730: + webBuildBase + ", path: " + path
1731: + ", isFolder: " + isFolder;
1732: }
1733: }
1734: assert newCurrent != null : "webBuildBase: "
1735: + webBuildBase + ", path: " + path
1736: + ", isFolder: " + isFolder;
1737: current = newCurrent;
1738: }
1739: assert current != null : "webBuildBase: " + webBuildBase
1740: + ", path: " + path + ", isFolder: " + isFolder;
1741: return current;
1742: }
1743: }
1744:
1745: public boolean isJavaEE5(Project project) {
1746: return J2eeModule.JAVA_EE_5.equals(getAPIWebModule()
1747: .getJ2eePlatformVersion());
1748: }
1749:
1750: private static final class WebPropertyEvaluatorImpl implements
1751: WebPropertyEvaluator {
1752: private PropertyEvaluator evaluator;
1753:
1754: public WebPropertyEvaluatorImpl(PropertyEvaluator eval) {
1755: evaluator = eval;
1756: }
1757:
1758: public PropertyEvaluator evaluator() {
1759: return evaluator;
1760: }
1761: }
1762:
1763: private class WebExtenderImplementation implements
1764: AntBuildExtenderImplementation {
1765: //add targets here as required by the external plugins..
1766: public List<String> getExtensibleTargets() {
1767: String[] targets = new String[] { "-do-init",
1768: "-init-check", "-post-clean", "jar",
1769: "-pre-pre-compile", "-do-ws-compile",
1770: "-do-compile", "-do-compile-single",
1771: "-post-compile", "-pre-dist", //NOI18N
1772: };
1773: return Arrays.asList(targets);
1774: }
1775:
1776: public Project getOwningProject() {
1777: return WebProject.this;
1778: }
1779:
1780: }
1781: }
|