001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.sql.project;
042:
043: import org.netbeans.modules.sql.project.spi.JbiArtifactProvider;
044: import org.netbeans.modules.compapp.projects.base.ui.IcanproCustomizerProvider;
045: import org.netbeans.modules.compapp.projects.base.ui.customizer.IcanproProjectProperties;
046: import org.netbeans.modules.compapp.projects.base.queries.IcanproProjectEncodingQueryImpl;
047: import org.netbeans.modules.sql.project.SQLproConstants;
048: import org.netbeans.modules.sql.project.ui.SQLproLogicalViewProvider;
049: import java.beans.PropertyChangeListener;
050: import java.beans.PropertyChangeSupport;
051: import java.io.File;
052: import java.io.IOException;
053: import javax.swing.Icon;
054: import javax.swing.ImageIcon;
055: import org.netbeans.api.java.project.JavaProjectConstants;
056: import org.netbeans.api.project.FileOwnerQuery;
057: import org.netbeans.api.project.Project;
058: import org.netbeans.api.project.ProjectInformation;
059: import org.netbeans.api.project.ProjectManager;
060: import org.netbeans.api.project.ant.AntArtifact;
061: import org.netbeans.spi.java.project.support.ui.BrokenReferencesSupport;
062: import org.netbeans.spi.project.AuxiliaryConfiguration;
063: import org.netbeans.spi.project.SubprojectProvider;
064: import org.netbeans.spi.project.support.ant.AntProjectEvent;
065: import org.netbeans.spi.project.support.ant.AntProjectHelper;
066: import org.netbeans.spi.project.support.ant.AntProjectListener;
067: import org.netbeans.spi.project.support.ant.EditableProperties;
068: import org.netbeans.spi.project.support.ant.GeneratedFilesHelper;
069: import org.netbeans.spi.project.support.ant.ProjectXmlSavedHook;
070: import org.netbeans.spi.project.support.ant.PropertyEvaluator;
071: import org.netbeans.spi.project.support.ant.ReferenceHelper;
072: import org.netbeans.spi.project.support.ant.SourcesHelper;
073: import org.netbeans.spi.project.ui.PrivilegedTemplates;
074: import org.netbeans.spi.project.ui.ProjectOpenedHook;
075: import org.netbeans.spi.project.ui.RecommendedTemplates;
076: import org.netbeans.spi.queries.FileBuiltQueryImplementation;
077: import org.openide.ErrorManager;
078: import org.openide.filesystems.FileObject;
079: import org.openide.modules.InstalledFileLocator;
080: import org.openide.util.Lookup;
081: import org.openide.util.Mutex;
082: import org.openide.util.Utilities;
083: import org.openide.util.lookup.Lookups;
084: import org.w3c.dom.Element;
085: import org.w3c.dom.Node;
086: import org.w3c.dom.NodeList;
087: import org.w3c.dom.Text;
088: import java.nio.charset.Charset;
089: import java.nio.charset.IllegalCharsetNameException;
090: import java.nio.charset.UnsupportedCharsetException;
091: import java.util.logging.Logger;
092: import org.netbeans.api.queries.FileEncodingQuery;
093:
094: /**
095: * Represents one sql module project
096: * @author Chris Webster
097: */
098: public final class SQLproProject implements Project, AntProjectListener {
099:
100: private static final Icon PROJECT_ICON = new ImageIcon(
101: Utilities
102: .loadImage("org/netbeans/modules/sql/project/ui/resources/sqlproProjectIcon.gif")); // NOI18N
103: public static final String SOURCES_TYPE_ICANPRO = "BIZPRO";
104: public static final String ARTIFACT_TYPE_JBI_ASA = "CAPS.asa";
105:
106: public static final String MODULE_INSTALL_NAME = "modules/org-netbeans-modules-sql-project.jar";
107: public static final String MODULE_INSTALL_CBN = "org.netbeans.modules.sql.project";
108: public static final String MODULE_INSTALL_DIR = "module.install.dir";
109: private static final Logger LOG = Logger
110: .getLogger(SQLproProject.class.getName());
111:
112: private final AntProjectHelper helper;
113: private final PropertyEvaluator eval;
114: private final ReferenceHelper refHelper;
115: private final GeneratedFilesHelper genFilesHelper;
116: private final Lookup lookup;
117:
118: public SQLproProject(final AntProjectHelper helper)
119: throws IOException {
120: this .helper = helper;
121: eval = createEvaluator();
122: AuxiliaryConfiguration aux = helper
123: .createAuxiliaryConfiguration();
124: refHelper = new ReferenceHelper(helper, aux, helper
125: .getStandardPropertyEvaluator());
126: genFilesHelper = new GeneratedFilesHelper(helper);
127: lookup = createLookup(aux);
128: helper.addAntProjectListener(this );
129: }
130:
131: public FileObject getProjectDirectory() {
132: return helper.getProjectDirectory();
133: }
134:
135: public String toString() {
136: return "SQLproProject[" + getProjectDirectory() + "]"; // NOI18N
137: }
138:
139: public ReferenceHelper getReferenceHelper() {
140: return this .refHelper;
141: }
142:
143: private PropertyEvaluator createEvaluator() {
144: // XXX might need to use a custom evaluator to handle active platform substitutions... TBD
145: return helper.getStandardPropertyEvaluator();
146: }
147:
148: PropertyEvaluator evaluator() {
149: return eval;
150: }
151:
152: public Lookup getLookup() {
153: return lookup;
154: }
155:
156: private Lookup createLookup(AuxiliaryConfiguration aux) {
157: SubprojectProvider spp = refHelper.createSubprojectProvider();
158: FileBuiltQueryImplementation fileBuilt = helper
159: .createGlobFileBuiltQuery(helper
160: .getStandardPropertyEvaluator(),
161: new String[] { "${src.dir}/*.java" }, // NOI18N
162: new String[] { "${build.classes.dir}/*.class" } // NOI18N
163: );
164: final SourcesHelper sourcesHelper = new SourcesHelper(helper,
165: evaluator());
166: String webModuleLabel = org.openide.util.NbBundle.getMessage(
167: IcanproCustomizerProvider.class, "LBL_Node_EJBModule"); //NOI18N
168: String srcJavaLabel = org.openide.util.NbBundle.getMessage(
169: IcanproCustomizerProvider.class, "LBL_Node_Sources"); //NOI18N
170:
171: sourcesHelper.addPrincipalSourceRoot("${"
172: + IcanproProjectProperties.SOURCE_ROOT + "}",
173: webModuleLabel, /*XXX*/null, null);
174: sourcesHelper.addPrincipalSourceRoot("${"
175: + IcanproProjectProperties.SRC_DIR + "}", srcJavaLabel, /*XXX*/
176: null, null);
177:
178: sourcesHelper.addTypedSourceRoot("${"
179: + IcanproProjectProperties.SRC_DIR + "}",
180: SOURCES_TYPE_ICANPRO, srcJavaLabel, /*XXX*/null, null);
181: sourcesHelper.addTypedSourceRoot("${"
182: + IcanproProjectProperties.SRC_DIR + "}",
183: JavaProjectConstants.SOURCES_TYPE_JAVA, srcJavaLabel, /*XXX*/
184: null, null);
185: ProjectManager.mutex().postWriteRequest(new Runnable() {
186: public void run() {
187: sourcesHelper
188: .registerExternalRoots(FileOwnerQuery.EXTERNAL_ALGORITHM_TRANSIENT);
189: }
190: });
191: return Lookups
192: .fixed(new Object[] {
193: new Info(),
194: aux,
195: helper.createCacheDirectoryProvider(),
196: //B new ProjectWebServicesSupportProvider(),
197: // XXX the helper should not be exposed
198: helper,
199: spp,
200: new SQLproActionProvider(this , helper,
201: refHelper),
202: new SQLproLogicalViewProvider(this , helper,
203: evaluator(), spp, refHelper),
204: new IcanproCustomizerProvider(this , helper,
205: refHelper),
206: new JbiArtifactProviderImpl(),
207: new ProjectXmlSavedHookImpl(),
208: new ProjectOpenedHookImpl(),
209: new SQLproProjectOperations(this ),
210: fileBuilt,
211: new RecommendedTemplatesImpl(),
212: refHelper,
213: new IcanproProjectEncodingQueryImpl(evaluator()),
214: sourcesHelper.createSources(),
215: helper
216: .createSharabilityQuery(
217: evaluator(),
218: new String[] { "${"
219: + IcanproProjectProperties.SOURCE_ROOT
220: + "}" },
221: new String[] {
222: "${"
223: + IcanproProjectProperties.BUILD_DIR
224: + "}",
225: "${"
226: + IcanproProjectProperties.DIST_DIR
227: + "}" }) });
228: }
229:
230: public void configurationXmlChanged(AntProjectEvent ev) {
231: if (ev.getPath().equals(AntProjectHelper.PROJECT_XML_PATH)) {
232: // Could be various kinds of changes, but name & displayName might have changed.
233: Info info = (Info) getLookup().lookup(
234: ProjectInformation.class);
235: info.firePropertyChange(ProjectInformation.PROP_NAME);
236: info
237: .firePropertyChange(ProjectInformation.PROP_DISPLAY_NAME);
238: }
239: }
240:
241: public void propertiesChanged(AntProjectEvent ev) {
242: // currently ignored
243: //TODO: should not be ignored!
244: }
245:
246: String getBuildXmlName() {
247: String storedName = helper.getStandardPropertyEvaluator()
248: .getProperty(IcanproProjectProperties.BUILD_FILE);
249: return storedName == null ? GeneratedFilesHelper.BUILD_XML_PATH
250: : storedName;
251: }
252:
253: // Package private methods -------------------------------------------------
254:
255: FileObject getSourceDirectory() {
256: String srcDir = helper.getStandardPropertyEvaluator()
257: .getProperty("src.dir"); // NOI18N
258: return helper.resolveFileObject(srcDir);
259: }
260:
261: /** Return configured project name. */
262: public String getName() {
263: return (String) ProjectManager.mutex().readAccess(
264: new Mutex.Action() {
265: public Object run() {
266: Element data = helper
267: .getPrimaryConfigurationData(true);
268: // XXX replace by XMLUtil when that has findElement, findText, etc.
269: NodeList nl = data
270: .getElementsByTagNameNS(
271: SQLproProjectType.PROJECT_CONFIGURATION_NAMESPACE,
272: "name");
273: if (nl.getLength() == 1) {
274: nl = nl.item(0).getChildNodes();
275: if (nl.getLength() == 1
276: && nl.item(0).getNodeType() == Node.TEXT_NODE) {
277: return ((Text) nl.item(0))
278: .getNodeValue();
279: }
280: }
281: return "???"; // NOI18N
282: }
283: });
284: }
285:
286: public AntProjectHelper getAntProjectHelper() {
287: return helper;
288: }
289:
290: /** Store configured project name. */
291: public void setName(final String name) {
292: ProjectManager.mutex().writeAccess(new Mutex.Action() {
293: public Object run() {
294: Element data = helper.getPrimaryConfigurationData(true);
295: // XXX replace by XMLUtil when that has findElement, findText, etc.
296: NodeList nl = data
297: .getElementsByTagNameNS(
298: SQLproProjectType.PROJECT_CONFIGURATION_NAMESPACE,
299: "name");
300: Element nameEl;
301: if (nl.getLength() == 1) {
302: nameEl = (Element) nl.item(0);
303: NodeList deadKids = nameEl.getChildNodes();
304: while (deadKids.getLength() > 0) {
305: nameEl.removeChild(deadKids.item(0));
306: }
307: } else {
308: nameEl = data
309: .getOwnerDocument()
310: .createElementNS(
311: SQLproProjectType.PROJECT_CONFIGURATION_NAMESPACE,
312: "name");
313: data.insertBefore(nameEl, /* OK if null */data
314: .getChildNodes().item(0));
315: }
316: nameEl.appendChild(data.getOwnerDocument()
317: .createTextNode(name));
318: helper.putPrimaryConfigurationData(data, true);
319: return null;
320: }
321: });
322: }
323:
324: // Private innerclasses ----------------------------------------------------
325:
326: private final class Info implements ProjectInformation {
327:
328: private final PropertyChangeSupport pcs = new PropertyChangeSupport(
329: this );
330:
331: Info() {
332: }
333:
334: void firePropertyChange(String prop) {
335: pcs.firePropertyChange(prop, null, null);
336: }
337:
338: public String getName() {
339: return SQLproProject.this .getName();
340: }
341:
342: public String getDisplayName() {
343: return SQLproProject.this .getName();
344: }
345:
346: public Icon getIcon() {
347: return PROJECT_ICON;
348: }
349:
350: public Project getProject() {
351: return SQLproProject.this ;
352: }
353:
354: public void addPropertyChangeListener(
355: PropertyChangeListener listener) {
356: pcs.addPropertyChangeListener(listener);
357: }
358:
359: public void removePropertyChangeListener(
360: PropertyChangeListener listener) {
361: pcs.removePropertyChangeListener(listener);
362: }
363:
364: }
365:
366: private final class ProjectXmlSavedHookImpl extends
367: ProjectXmlSavedHook {
368:
369: ProjectXmlSavedHookImpl() {
370: }
371:
372: protected void projectXmlSaved() throws IOException {
373: genFilesHelper.refreshBuildScript(
374: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
375: SQLproProject.class
376: .getResource("resources/build-impl.xsl"),
377: false);
378: genFilesHelper.refreshBuildScript(getBuildXmlName(),
379: SQLproProject.class
380: .getResource("resources/build.xsl"), false);
381: }
382:
383: }
384:
385: private final class ProjectOpenedHookImpl extends ProjectOpenedHook {
386:
387: ProjectOpenedHookImpl() {
388: }
389:
390: protected void projectOpened() {
391: try {
392: // Check up on build scripts.
393: genFilesHelper
394: .refreshBuildScript(
395: GeneratedFilesHelper.BUILD_IMPL_XML_PATH,
396: SQLproProject.class
397: .getResource("resources/build-impl.xsl"),
398: true);
399: genFilesHelper.refreshBuildScript(getBuildXmlName(),
400: SQLproProject.class
401: .getResource("resources/build.xsl"),
402: true);
403: } catch (IOException e) {
404: ErrorManager.getDefault().notify(
405: ErrorManager.INFORMATIONAL, e);
406: }
407:
408: // Make it easier to run headless builds on the same machine at least.
409: ProjectManager.mutex().writeAccess(new Mutex.Action() {
410: public Object run() {
411: EditableProperties ep = helper
412: .getProperties(AntProjectHelper.PRIVATE_PROPERTIES_PATH);
413: ep.setProperty("netbeans.user", System
414: .getProperty("netbeans.user"));
415:
416: File f = InstalledFileLocator.getDefault().locate(
417: MODULE_INSTALL_NAME, MODULE_INSTALL_CBN,
418: false);
419: if (f != null) {
420: ep.setProperty(MODULE_INSTALL_DIR, f
421: .getParentFile().getPath());
422: }
423:
424: helper.putProperties(
425: AntProjectHelper.PRIVATE_PROPERTIES_PATH,
426: ep);
427: EditableProperties projectEP = helper
428: .getProperties(AntProjectHelper.PROJECT_PROPERTIES_PATH);
429: if (projectEP
430: .getProperty(IcanproProjectProperties.SOURCE_ENCODING) == null) {
431: projectEP
432: .setProperty(
433: IcanproProjectProperties.SOURCE_ENCODING,
434: // FIXME: maybe we should use Charset.defaultCharset() instead?
435: // See comments in IcanproProjectEncodingQueryImpl.java
436: FileEncodingQuery
437: .getDefaultEncoding()
438: .name());
439: }
440: helper.putProperties(
441: AntProjectHelper.PROJECT_PROPERTIES_PATH,
442: projectEP);
443:
444: try {
445: ProjectManager.getDefault().saveProject(
446: SQLproProject.this );
447: } catch (IOException e) {
448: ErrorManager.getDefault().notify(e);
449: }
450: return null;
451: }
452: });
453: if (IcanproLogicalViewProvider.hasBrokenLinks(helper,
454: refHelper)) {
455: BrokenReferencesSupport.showAlert();
456: }
457: checkEncoding();
458: }
459:
460: private void checkEncoding() {
461: // TODO m
462: // Should we show ErrorManager dialog to inform user in case wrong encoding parameter ?
463: String prop = eval
464: .getProperty(IcanproProjectProperties.SOURCE_ENCODING);
465: if (prop != null) {
466: try {
467: Charset c = Charset.forName(prop);
468: } catch (IllegalCharsetNameException e) {
469: //Broken property, log & ignore
470: LOG.warning("Illegal charset: " + prop
471: + " in project: " + // NOI18N
472: getProjectDirectory());
473: } catch (UnsupportedCharsetException e) {
474: //todo: Needs UI notification like broken references.
475: LOG.warning("Unsupported charset: " + prop
476: + " in project: " + // NOI18N
477: getProjectDirectory());
478: }
479: }
480: }
481:
482: protected void projectClosed() {
483: // Probably unnecessary, but just in case:
484: try {
485: ProjectManager.getDefault().saveProject(
486: SQLproProject.this );
487: } catch (IOException e) {
488: ErrorManager.getDefault().notify(e);
489: }
490: }
491:
492: }
493:
494: /**
495: * Exports the main JAR as an official build product for use from other scripts.
496: * The type of the artifact will be {@link AntArtifact#TYPE_JAR}.
497: */
498: private final class JbiArtifactProviderImpl implements
499: JbiArtifactProvider {
500:
501: public AntArtifact[] getBuildArtifacts() {
502: return new AntArtifact[] {
503: helper
504: .createSimpleAntArtifact(
505: SQLproProject.ARTIFACT_TYPE_JBI_ASA
506: + ":"
507: + helper
508: .getStandardPropertyEvaluator()
509: .getProperty(
510: IcanproProjectProperties.JBI_SETYPE_PREFIX),
511: IcanproProjectProperties.SE_DEPLOYMENT_JAR,
512: helper
513: .getStandardPropertyEvaluator(),
514: "dist_se", "clean"), // NOI18N
515: helper.createSimpleAntArtifact(
516: JavaProjectConstants.ARTIFACT_TYPE_JAR,
517: IcanproProjectProperties.SE_DEPLOYMENT_JAR,
518: helper.getStandardPropertyEvaluator(),
519: "dist_se", "clean") // NOI18N
520: };
521: }
522:
523: public String getJbiServiceAssemblyType() {
524: return helper.getStandardPropertyEvaluator().getProperty(
525: IcanproProjectProperties.JBI_SETYPE_PREFIX);
526: }
527: }
528:
529: private static final class RecommendedTemplatesImpl implements
530: RecommendedTemplates, PrivilegedTemplates {
531:
532: // List of primarily supported templates
533:
534: private static final String[] TYPES = new String[] { "SOA_SQL", // NOI18N
535: "XML", // NOI18N
536: "simple-files" // NOI18N
537: };
538:
539: private static final String[] PRIVILEGED_NAMES = new String[] {
540: "Templates/SOA_SQL/SQLTemplate.sql",
541: "Templates/XML/stylesheet.xsl",
542: "Templates/CAPS/schema.xsd",
543: "Templates/CAPS/untitled.wsdl" };
544:
545: public String[] getRecommendedTypes() {
546: return TYPES;
547: }
548:
549: public String[] getPrivilegedTemplates() {
550: return PRIVILEGED_NAMES;
551: }
552:
553: }
554:
555: public IcanproProjectProperties getProjectProperties() {
556: return new IcanproProjectProperties(this, helper, refHelper);
557: }
558: }
|