001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * The Original Software is NetBeans. The Initial Developer of the Original
016: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
017: * Microsystems, Inc. All Rights Reserved.
018: */
019: package org.netbeans.modules.xslt.project;
020:
021: import java.beans.PropertyChangeListener;
022: import java.beans.PropertyChangeSupport;
023: import java.io.File;
024: import java.io.IOException;
025: import java.lang.ref.WeakReference;
026: import java.nio.charset.Charset;
027: import java.nio.charset.IllegalCharsetNameException;
028: import java.nio.charset.UnsupportedCharsetException;
029: import java.util.logging.Logger;
030: import javax.swing.Icon;
031: import javax.swing.ImageIcon;
032: import org.netbeans.api.project.FileOwnerQuery;
033: import org.netbeans.api.project.Project;
034: import org.netbeans.api.project.ProjectInformation;
035: import org.netbeans.api.project.ProjectManager;
036: import org.netbeans.api.project.ant.AntArtifact;
037: import org.netbeans.api.project.ui.OpenProjects;
038: import org.netbeans.api.queries.FileEncodingQuery;
039: import org.netbeans.modules.xml.catalogsupport.ProjectConstants;
040:
041: import org.netbeans.modules.compapp.projects.base.spi.JbiArtifactProvider;
042: import org.netbeans.modules.compapp.projects.base.ui.customizer.IcanproProjectProperties;
043: import org.netbeans.modules.compapp.projects.base.IcanproConstants;
044: import org.netbeans.modules.compapp.projects.base.queries.IcanproProjectEncodingQueryImpl;
045: import org.netbeans.modules.compapp.projects.base.ui.IcanproXmlCustomizerProvider;
046:
047: import static org.netbeans.modules.xslt.project.XsltproConstants.*;
048: import org.netbeans.modules.xml.catalogsupport.DefaultProjectCatalogSupport;
049: import org.netbeans.modules.xslt.project.spi.ProjectsFilesChangeHandler;
050: import org.netbeans.modules.xslt.project.wizard.IcanproLogicalViewProvider;
051: import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport;
052: import org.netbeans.spi.project.AuxiliaryConfiguration;
053: import org.netbeans.spi.project.SubprojectProvider;
054: import org.netbeans.spi.project.support.ant.AntProjectEvent;
055: import org.netbeans.spi.project.support.ant.AntProjectHelper;
056: import org.netbeans.spi.project.support.ant.AntProjectListener;
057: import org.netbeans.spi.project.support.ant.EditableProperties;
058: import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
059: import org.netbeans.spi.project.support.ant.ProjectXmlSavedHook;
060: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
061: import org.netbeans.spi.project.support.ant.PropertyUtils;
062: import org.netbeans.spi.project.support.ant.ReferenceHelper;
063: import org.netbeans.spi.project.support.ant.SourcesHelper;
064: import org.netbeans.spi.project.ui.PrivilegedTemplates;
065: import org.netbeans.spi.project.ui.ProjectOpenedHook;
066: import org.netbeans.spi.project.ui.RecommendedTemplates;
067: import org.netbeans.spi.queries.FileBuiltQueryImplementation;
068: import org.openide.ErrorManager;
069: import org.openide.filesystems.FileObject;
070: import org.openide.filesystems.FileSystem;
071: import org.openide.modules.InstalledFileLocator;
072: import org.openide.util.Exceptions;
073: import org.openide.util.Lookup;
074: import org.openide.util.Mutex;
075: import org.openide.util.Utilities;
076: import org.openide.util.lookup.Lookups;
077: import org.w3c.dom.Element;
078: import org.w3c.dom.Node;
079: import org.w3c.dom.NodeList;
080: import org.w3c.dom.Text;
081:
082: /**
083: *
084: * @author Chris Webster
085: * @author Vitaly Bychkov
086: * @version 1.0
087: */
088: public class XsltproProject implements Project, AntProjectListener {
089:
090: private static final Icon PROJECT_ICON = new ImageIcon(Utilities
091: .loadImage(XSLT_PROJECT_ICON)); // NOI18N
092: public static final String SOURCES_TYPE_XSLTPRO = "BIZPRO";
093: public static final String ARTIFACT_TYPE_JBI_ASA = "CAPS.asa";
094:
095: public static final String MODULE_INSTALL_NAME = "modules/org-netbeans-modules-xslt-project.jar";
096: public static final String MODULE_INSTALL_CBN = "org.netbeans.modules.xslt.project";
097: public static final String MODULE_INSTALL_DIR = "module.install.dir";
098:
099: private static final Logger LOG = Logger
100: .getLogger(XsltproProject.class.getName());
101:
102: private final AntProjectHelper helper;
103: private Lookup lookup;
104: private PropertyEvaluator evaluator;
105: private ReferenceHelper refHelper;
106: private GeneratedFilesHelper genFilesHelper;
107: private ProjectsFilesChangeHandler myProjectsChangeHandler;
108:
109: public XsltproProject(AntProjectHelper helper) throws IOException {
110: this .helper = helper;
111:
112: this .evaluator = createEvaluator();
113: AuxiliaryConfiguration aux = helper
114: .createAuxiliaryConfiguration();
115: this .refHelper = new ReferenceHelper(helper, aux, helper
116: .getStandardPropertyEvaluator());
117: this .genFilesHelper = new GeneratedFilesHelper(helper);
118: myProjectsChangeHandler = new ProjectsFilesChangeHandler(this );
119: this .lookup = createLookup(aux);
120: helper.addAntProjectListener(this );
121: }
122:
123: public FileObject getProjectDirectory() {
124: return helper.getProjectDirectory();
125: }
126:
127: public AntProjectHelper getAntProjectHelper() {
128: return helper;
129: }
130:
131: public ReferenceHelper getReferenceHelper() {
132: return this .refHelper;
133: }
134:
135: @Override
136: public String toString() {
137: return "XsltproProject[" + getProjectDirectory() + "]"; // NOI18N
138: }
139:
140: public Lookup getLookup() {
141: return lookup;
142: }
143:
144: /** Return configured project name. */
145: public String getName() {
146: return ProjectManager.mutex().readAccess(
147: new Mutex.Action<String>() {
148: public String run() {
149: Element data = helper
150: .getPrimaryConfigurationData(true);
151: // XXX replace by XMLUtil when that has findElement, findText, etc.
152: NodeList nl = data
153: .getElementsByTagNameNS(
154: XsltproProjectType.PROJECT_CONFIGURATION_NAMESPACE,
155: "name");
156: if (nl.getLength() == 1) {
157: nl = nl.item(0).getChildNodes();
158: if (nl.getLength() == 1
159: && nl.item(0).getNodeType() == Node.TEXT_NODE) {
160: return ((Text) nl.item(0))
161: .getNodeValue();
162: }
163: }
164: return "???"; // NOI18N
165: }
166: });
167: }
168:
169: /** Store configured project name. */
170: public void setName(final String name) {
171: ProjectManager.mutex().writeAccess(new Mutex.Action<Object>() {
172: public Object run() {
173: Element data = helper.getPrimaryConfigurationData(true);
174: // XXX replace by XMLUtil when that has findElement, findText, etc.
175: NodeList nl = data
176: .getElementsByTagNameNS(
177: XsltproProjectType.PROJECT_CONFIGURATION_NAMESPACE,
178: "name");
179: Element nameEl;
180: if (nl.getLength() == 1) {
181: nameEl = (Element) nl.item(0);
182: NodeList deadKids = nameEl.getChildNodes();
183: while (deadKids.getLength() > 0) {
184: nameEl.removeChild(deadKids.item(0));
185: }
186: } else {
187: nameEl = data
188: .getOwnerDocument()
189: .createElementNS(
190: XsltproProjectType.PROJECT_CONFIGURATION_NAMESPACE,
191: "name");
192: data.insertBefore(nameEl, /* OK if null */data
193: .getChildNodes().item(0));
194: }
195: nameEl.appendChild(data.getOwnerDocument()
196: .createTextNode(name));
197: helper.putPrimaryConfigurationData(data, true);
198: return null;
199: }
200: });
201: }
202:
203: public void configurationXmlChanged(AntProjectEvent ev) {
204: // TODO m
205: if (ev.getPath().equals(AntProjectHelper.PROJECT_XML_PATH)) {
206: // Could be various kinds of changes, but name & displayName might have changed.
207: Info info = (Info) getLookup().lookup(
208: ProjectInformation.class);
209: info.firePropertyChange(ProjectInformation.PROP_NAME);
210: info
211: .firePropertyChange(ProjectInformation.PROP_DISPLAY_NAME);
212: }
213: }
214:
215: public void propertiesChanged(AntProjectEvent ev) {
216: }
217:
218: PropertyEvaluator evaluator() {
219: return evaluator;
220: }
221:
222: String getBuildXmlName() {
223: String storedName = helper.getStandardPropertyEvaluator()
224: .getProperty(IcanproProjectProperties.BUILD_FILE);
225: return storedName == null ? GeneratedFilesHelper.BUILD_XML_PATH
226: : storedName;
227: }
228:
229: FileObject getSourceDirectory() {
230: String srcDir = helper.getStandardPropertyEvaluator()
231: .getProperty("src.dir"); // NOI18N
232: return helper.resolveFileObject(srcDir);
233: }
234:
235: // TODO r
236: // /** Last time in ms when the Broken References alert was shown. */
237: // private static long brokenAlertLastTime = 0;
238: //
239: // /** Is Broken References alert shown now? */
240: // private static boolean brokenAlertShown = false;
241: //
242: // /** Timeout within which request to show alert will be ignored. */
243: // private static int BROKEN_ALERT_TIMEOUT = 1000;
244: //
245:
246: private PropertyEvaluator createEvaluator() {
247: // XXX might need to use a custom evaluator to handle active platform substitutions... TBD
248: return helper.getStandardPropertyEvaluator();
249: }
250:
251: private Lookup createLookup(AuxiliaryConfiguration aux) {
252: SubprojectProvider spp = refHelper.createSubprojectProvider();
253: FileBuiltQueryImplementation fileBuilt = helper
254: .createGlobFileBuiltQuery(helper
255: .getStandardPropertyEvaluator(),
256: new String[] { "${src.dir}/*.java" }, // NOI18N
257: new String[] { "${build.classes.dir}/*.class" } // NOI18N
258: );
259: final SourcesHelper sourcesHelper = new SourcesHelper(helper,
260: evaluator());
261: String webModuleLabel = org.openide.util.NbBundle.getMessage(
262: XsltproProject.class, "LBL_Node_EJBModule"); //NOI18N
263: String srcJavaLabel = org.openide.util.NbBundle.getMessage(
264: XsltproProject.class, "LBL_Node_Sources"); //NOI18N
265:
266: sourcesHelper.addPrincipalSourceRoot("${"
267: + IcanproProjectProperties.SOURCE_ROOT + "}",
268: webModuleLabel, /*XXX*/null, null);
269: sourcesHelper.addPrincipalSourceRoot("${"
270: + IcanproProjectProperties.SRC_DIR + "}", srcJavaLabel, /*XXX*/
271: null, null);
272:
273: sourcesHelper.addTypedSourceRoot("${"
274: + IcanproProjectProperties.SRC_DIR + "}",
275: SOURCES_TYPE_XSLTPRO, srcJavaLabel, /*XXX*/null, null);
276: // sourcesHelper.addTypedSourceRoot("${"+SRC_DIR+"}", JavaProjectConstants.SOURCES_TYPE_JAVA, srcJavaLabel, /*XXX*/null, null);
277: sourcesHelper.addTypedSourceRoot("${"
278: + IcanproProjectProperties.SRC_DIR + "}",
279: ProjectConstants.SOURCES_TYPE_XML, srcJavaLabel, /*XXX*/
280: null, null);
281:
282: ProjectManager.mutex().postWriteRequest(new Runnable() {
283: public void run() {
284: sourcesHelper
285: .registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT);
286: }
287: });
288:
289: return Lookups
290: .fixed(new Object[] {
291: new Info(),
292: aux,
293: helper.createCacheDirectoryProvider(),
294: //B new ProjectWebServicesSupportProvider(),
295: // XXX the helper should not be exposed
296: helper,
297: spp,
298: new XsltproActionProvider(this , helper,
299: refHelper),
300: new IcanproLogicalViewProvider(this , helper,
301: evaluator(), spp, refHelper),
302: // new XsltProjectCustomizerProvider(this),
303: new IcanproXmlCustomizerProvider(
304: this ,
305: helper,
306: refHelper,
307: XsltproProjectType.PROJECT_CONFIGURATION_NAMESPACE),
308: // provides information about added/removed schema and wsdl files
309: // forwards related model property change events
310: myProjectsChangeHandler,
311: new JbiArtifactProviderImpl(),
312: new ProjectXmlSavedHookImpl(),
313: //todo m
314: new ProjectOpenedHookImpl(this ),
315: new XsltProjectOperations(this ),
316: fileBuilt,
317: new RecommendedTemplatesImpl(),
318: refHelper,
319: new IcanproProjectEncodingQueryImpl(evaluator()),
320: sourcesHelper.createSources(),
321: helper
322: .createSharabilityQuery(
323: evaluator(),
324: new String[] { "${"
325: + IcanproProjectProperties.SOURCE_ROOT
326: + "}" },
327: new String[] {
328: "${"
329: + IcanproProjectProperties.BUILD_DIR
330: + "}",
331: "${"
332: + IcanproProjectProperties.DIST_DIR
333: + "}" }),
334: new DefaultProjectCatalogSupport(this , helper,
335: refHelper)
336:
337: });
338: }
339:
340: // private inner classes ---------------------------------------------------
341:
342: /**
343: * @see org.netbeans.api.project.ProjectInformation
344: */
345: private final class Info implements ProjectInformation {
346:
347: private final PropertyChangeSupport pcs = new PropertyChangeSupport(
348: this );
349: private WeakReference<String> cachedName = null;
350:
351: Info() {
352: }
353:
354: void firePropertyChange(String prop) {
355: pcs.firePropertyChange(prop, null, null);
356: synchronized (pcs) {
357: cachedName = null;
358: }
359: }
360:
361: public String getName() {
362: return PropertyUtils
363: .getUsablePropertyName(getDisplayName());
364: // return XsltproProject.this.getName();
365: }
366:
367: public String getDisplayName() {
368: synchronized (pcs) {
369: if (cachedName != null) {
370: String dn = cachedName.get();
371: if (dn != null) {
372: return dn;
373: }
374: }
375: }
376: String dn = XsltproProject.this .getName();
377: synchronized (pcs) {
378: cachedName = new WeakReference<String>(dn);
379: }
380: return dn;
381:
382: // return XsltproProject.this.getName();
383: }
384:
385: public Icon getIcon() {
386: return PROJECT_ICON;
387: }
388:
389: public Project getProject() {
390: return XsltproProject.this ;
391: }
392:
393: public void addPropertyChangeListener(
394: PropertyChangeListener listener) {
395: pcs.addPropertyChangeListener(listener);
396: }
397:
398: public void removePropertyChangeListener(
399: PropertyChangeListener listener) {
400: pcs.removePropertyChangeListener(listener);
401: }
402:
403: }
404:
405: /**
406: * @see org.netbeans.spi.project.support.ant.ProjectXmlSavedHook
407: */
408: private final class ProjectXmlSavedHookImpl extends
409: ProjectXmlSavedHook {
410:
411: ProjectXmlSavedHookImpl() {
412: }
413:
414: protected void projectXmlSaved() throws IOException {
415: genFilesHelper.refreshBuildScript(
416: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
417: XsltproProject.class
418: .getResource("resources/build-impl.xsl"),
419: false);
420: genFilesHelper.refreshBuildScript(getBuildXmlName(),
421: XsltproProject.class
422: .getResource("resources/build.xsl"), false);
423: }
424:
425: }
426:
427: /**
428: * @see org.netbeans.spi.project.ui.ProjectOpenedHook
429: */
430: private final class ProjectOpenedHookImpl extends ProjectOpenedHook {
431:
432: // TODO m
433: ProjectOpenedHookImpl(Project project) {
434: }
435:
436: protected void projectOpened() {
437:
438: Project[] openProjects = OpenProjects.getDefault()
439: .getOpenProjects();
440: int i = 0;
441: for (Project project : openProjects) {
442: i++;
443: System.out.println(i + ") currently open project: "
444: + project);
445: }
446:
447: try {
448: // Check up on build scripts.
449: genFilesHelper
450: .refreshBuildScript(
451: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
452: XsltproProject.class
453: .getResource("resources/build-impl.xsl"),
454: true);
455: genFilesHelper.refreshBuildScript(getBuildXmlName(),
456: XsltproProject.class
457: .getResource("resources/build.xsl"),
458: true);
459: } catch (IOException e) {
460: ErrorManager.getDefault().notify(
461: ErrorManager.INFORMATIONAL, e);
462: }
463:
464: // Make it easier to run headless builds on the same machine at least.
465: try {
466: getProjectDirectory().getFileSystem().runAtomicAction(
467: new FileSystem.AtomicAction() {
468:
469: public void run() throws IOException {
470: ProjectManager.mutex().writeAccess(
471: new Mutex.Action<Object>() {
472:
473: public Object run() {
474: EditableProperties ep = helper
475: .getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH);
476: ep
477: .setProperty(
478: "netbeans.user",
479: System
480: .getProperty("netbeans.user"));
481:
482: File f = InstalledFileLocator
483: .getDefault()
484: .locate(
485: MODULE_INSTALL_NAME,
486: MODULE_INSTALL_CBN,
487: false);
488: if (f != null) {
489: ep
490: .setProperty(
491: MODULE_INSTALL_DIR,
492: f
493: .getParentFile()
494: .getPath());
495: }
496:
497: helper
498: .putProperties(
499: AntProjectHelper.PRIVATE_PROPERTIES_PATH,
500: ep);
501:
502: // Add project encoding for old projects
503: EditableProperties projectEP = helper
504: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
505: if (projectEP
506: .getProperty(IcanproProjectProperties.SOURCE_ENCODING) == null) {
507: projectEP
508: .setProperty(
509: IcanproProjectProperties.SOURCE_ENCODING,
510: FileEncodingQuery
511: .getDefaultEncoding()
512: .name());
513: }
514: helper
515: .putProperties(
516: AntProjectHelper.PROJECT_PROPERTIES_PATH,
517: projectEP);
518:
519: try {
520: ProjectManager
521: .getDefault()
522: .saveProject(
523: XsltproProject.this );
524: } catch (IOException e) {
525: ErrorManager
526: .getDefault()
527: .notify(e);
528: }
529:
530: return null;
531: }
532: });
533: }
534: });
535: } catch (IOException e) {
536: Exceptions.printStackTrace(e);
537: }
538:
539: if (IcanproLogicalViewProvider.hasBrokenLinks(helper,
540: refHelper)) {
541: BrokenReferencesSupport.showAlert();
542: }
543:
544: checkEncoding();
545:
546: myProjectsChangeHandler.subscribes();
547: helper.removeAntProjectListener(XsltproProject.this );
548: }
549:
550: private void checkEncoding() {
551: // TODO m
552: // Should we show ErrorManager dialog to inform user in case wrong encoding parameter ?
553: String prop = evaluator
554: .getProperty(IcanproProjectProperties.SOURCE_ENCODING);
555: if (prop != null) {
556: try {
557: Charset c = Charset.forName(prop);
558: } catch (IllegalCharsetNameException e) {
559: //Broken property, log & ignore
560: LOG.warning("Illegal charset: " + prop
561: + " in project: " + // NOI18N
562: getProjectDirectory());
563: } catch (UnsupportedCharsetException e) {
564: //todo: Needs UI notification like broken references.
565: LOG.warning("Unsupported charset: " + prop
566: + " in project: " + // NOI18N
567: getProjectDirectory());
568: }
569: }
570: }
571:
572: protected void projectClosed() {
573: // Probably unnecessary, but just in case:
574: try {
575: ProjectManager.getDefault().saveProject(
576: XsltproProject.this );
577: } catch (IOException e) {
578: ErrorManager.getDefault().notify(e);
579: }
580: myProjectsChangeHandler.unsubscribes();
581: }
582:
583: }
584:
585: /**
586: * Exports the main JAR as an official build product for use from other scripts.
587: * The type of the artifact will be {@link AntArtifact#TYPE_JAR}.
588: *
589: * @see org.netbeans.spi.project.ant.AntArtifactProvider
590: */
591: private final class JbiArtifactProviderImpl implements
592: JbiArtifactProvider {
593:
594: public AntArtifact[] getBuildArtifacts() {
595: return new AntArtifact[] {
596: helper
597: .createSimpleAntArtifact(
598: XsltproProject.ARTIFACT_TYPE_JBI_ASA
599: + ":"
600: + helper
601: .getStandardPropertyEvaluator()
602: .getProperty(
603: IcanproProjectProperties.JBI_SE_TYPE),
604: IcanproProjectProperties.SE_DEPLOYMENT_JAR,
605: helper
606: .getStandardPropertyEvaluator(),
607: "dist_se", "clean"), // NOI18N
608:
609: helper.createSimpleAntArtifact(
610: IcanproConstants.ARTIFACT_TYPE_JAR,
611: IcanproProjectProperties.SE_DEPLOYMENT_JAR,
612: helper.getStandardPropertyEvaluator(),
613: "dist_se", "clean"), // NOI18N
614:
615: };
616: }
617:
618: public String getJbiServiceAssemblyType() {
619: return helper.getStandardPropertyEvaluator().getProperty(
620: IcanproProjectProperties.JBI_SE_TYPE);
621: }
622: }
623:
624: /**
625: * @see org.netbeans.spi.project.ui.RecommendedTemplates
626: * @see org.netbeans.spi.project.ui.PrivilegedTemplates
627: */
628: private static final class RecommendedTemplatesImpl implements
629: RecommendedTemplates, PrivilegedTemplates {
630:
631: // List of primarily supported templates
632:
633: private static final String[] TYPES = new String[] {
634: "SOA_XSLT", "XML", // NOI18N
635: "simple-files" // NOI18N
636: };
637:
638: private static final String[] PRIVILEGED_NAMES = new String[] {
639: "Templates/SOA_XSLT/xslt.service", // NOI18N
640: "Templates/XML/XmlSchema.xsd", // NOI18N
641: "Templates/XML/WSDL.wsdl" // NOI18N
642: };
643:
644: public String[] getRecommendedTypes() {
645: return TYPES;
646: }
647:
648: public String[] getPrivilegedTemplates() {
649: return PRIVILEGED_NAMES;
650: }
651:
652: }
653:
654: public IcanproProjectProperties getProjectProperties() {
655: return new IcanproProjectProperties(this, helper, refHelper,
656: XsltproProjectType.PROJECT_CONFIGURATION_NAMESPACE);
657: }
658: }
|