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-2006 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:
042: package org.netbeans.spi.project.support.ant;
043:
044: import java.io.File;
045: import java.io.IOException;
046: import java.io.OutputStream;
047: import java.util.Iterator;
048: import org.netbeans.api.project.Project;
049: import org.netbeans.api.project.ProjectManager;
050: import org.netbeans.modules.project.ant.AntBasedProjectFactorySingleton;
051: import org.netbeans.modules.project.ant.ProjectLibraryProvider;
052: import org.openide.filesystems.FileLock;
053: import org.openide.filesystems.FileObject;
054: import org.openide.filesystems.FileUtil;
055: import org.openide.util.Lookup;
056: import org.openide.util.Mutex;
057: import org.openide.util.MutexException;
058: import org.openide.xml.XMLUtil;
059: import org.w3c.dom.Document;
060: import org.w3c.dom.Element;
061:
062: /**
063: * Utilities to create new Ant-based projects on disk.
064: * @author Jesse Glick
065: */
066: public class ProjectGenerator {
067:
068: private ProjectGenerator() {
069: }
070:
071: /**
072: * Create a new Ant-based project on disk.
073: * It will initially be only minimally configured - just a skeleton <code>project.xml</code>.
074: * It will be marked as modified.
075: * <p>In order to fill in various details of it, call normal methods on the returned
076: * helper object, then save the project when you are done.
077: * (You can use {@link ProjectManager} to find the project object to be saved.)
078: * <p>No <code>build-impl.xml</code> will be created immediately; once you save the project
079: * changes, it will be created. If you wish to create a top-level <code>build.xml</code>
080: * use {@link GeneratedFilesHelper#generateBuildScriptFromStylesheet} after
081: * (or while) saving the project.
082: * <p>Acquires write access. But you are advised to acquire a write lock for
083: * the entire operation of creating, configuring, and saving the new project,
084: * and creating its initial <code>build.xml</code>.
085: * @param directory the main project directory to create it in
086: * (see {@link AntProjectHelper#getProjectDirectory})
087: * @param type a unique project type identifier (see {@link AntBasedProjectType#getType})
088: * @return an associated helper object
089: * @throws IOException if there is a problem physically creating the project
090: * @throws IllegalArgumentException if the project type does not match a registered
091: * Ant-based project type factory or if the directory
092: * is already recognized as some kind of project or if the
093: * new project on disk is recognized by some other factory
094: */
095: public static AntProjectHelper createProject(
096: final FileObject directory, final String type)
097: throws IOException, IllegalArgumentException {
098: return createProject0(directory, type, null, null);
099: }
100:
101: /**
102: * See {@link #createProject(FileObject, String)} for more datails. This
103: * method in addition allows to setup shared libraries location
104: * @param directory the main project directory to create it in
105: * (see {@link AntProjectHelper#getProjectDirectory})
106: * @param type a unique project type identifier (see {@link AntBasedProjectType#getType})
107: * @param librariesDefinition relative or absolute OS path; can be null
108: */
109: public static AntProjectHelper createProject(
110: final FileObject directory, final String type,
111: final String librariesDefinition) throws IOException,
112: IllegalArgumentException {
113: return createProject0(directory, type, null,
114: librariesDefinition);
115: }
116:
117: private static AntProjectHelper createProject0(
118: final FileObject directory, final String type,
119: final String name, final String librariesDefinition)
120: throws IOException, IllegalArgumentException {
121: try {
122: return ProjectManager.mutex().writeAccess(
123: new Mutex.ExceptionAction<AntProjectHelper>() {
124: public AntProjectHelper run()
125: throws IOException {
126: if (ProjectManager.getDefault()
127: .findProject(directory) != null) {
128: throw new IllegalArgumentException(
129: "Already a project in "
130: + directory); // NOI18N
131: }
132: FileObject projectXml = directory
133: .getFileObject(AntProjectHelper.PROJECT_XML_PATH);
134: if (projectXml != null) {
135: throw new IllegalArgumentException(
136: "Already a " + projectXml); // NOI18N
137: }
138: projectXml = FileUtil.createData(directory,
139: AntProjectHelper.PROJECT_XML_PATH);
140: Document doc = XMLUtil.createDocument(
141: "project",
142: AntProjectHelper.PROJECT_NS, null,
143: null); // NOI18N
144: Element el = doc
145: .createElementNS(
146: AntProjectHelper.PROJECT_NS,
147: "type"); // NOI18N
148: el.appendChild(doc.createTextNode(type));
149: doc.getDocumentElement().appendChild(el);
150: if (name != null) {
151: el = doc.createElementNS(
152: AntProjectHelper.PROJECT_NS,
153: "name"); // NOI18N
154: el
155: .appendChild(doc
156: .createTextNode(name));
157: doc.getDocumentElement()
158: .appendChild(el);
159: }
160: el = doc.createElementNS(
161: AntProjectHelper.PROJECT_NS,
162: "configuration"); // NOI18N
163: doc.getDocumentElement().appendChild(el);
164: if (librariesDefinition != null) {
165: el.appendChild(ProjectLibraryProvider
166: .createLibrariesElement(doc,
167: librariesDefinition));
168: // create libraries property file if it does not exist:
169: File f = new File(librariesDefinition);
170: if (!f.isAbsolute()) {
171: f = new File(FileUtil
172: .toFile(directory),
173: librariesDefinition);
174: }
175: f = FileUtil.normalizeFile(f);
176: if (!f.exists()) {
177: FileUtil.createData(f);
178: }
179: }
180: FileLock lock = projectXml.lock();
181: try {
182: OutputStream os = projectXml
183: .getOutputStream(lock);
184: try {
185: XMLUtil.write(doc, os, "UTF-8"); // NOI18N
186: } finally {
187: os.close();
188: }
189: } finally {
190: lock.releaseLock();
191: }
192: // OK, disk file project.xml has been created.
193: // Load the project into memory and mark it as modified.
194: ProjectManager.getDefault()
195: .clearNonProjectCache();
196: Project p = ProjectManager.getDefault()
197: .findProject(directory);
198: if (p == null) {
199: // Something is wrong, it is not being recognized.
200: for (AntBasedProjectType abpt : Lookup
201: .getDefault()
202: .lookupAll(
203: AntBasedProjectType.class)) {
204: if (abpt.getType().equals(type)) {
205: // Well, the factory was there.
206: throw new IllegalArgumentException(
207: "For some reason the folder "
208: + directory
209: + " with a new project of type "
210: + type
211: + " is still not recognized"); // NOI18N
212: }
213: }
214: throw new IllegalArgumentException(
215: "No Ant-based project factory for type "
216: + type); // NOI18N
217: }
218: AntProjectHelper helper = AntBasedProjectFactorySingleton
219: .getHelperFor(p);
220: if (helper == null) {
221: throw new IllegalArgumentException(
222: "Project "
223: + p
224: + " was not recognized as an Ant-based project"); // NOI18N
225: }
226: helper.markModified();
227: return helper;
228: }
229: });
230: } catch (MutexException e) {
231: throw (IOException) e.getException();
232: }
233: }
234:
235: }
|