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:
042: package org.netbeans.modules.web.freeform;
043:
044: import java.util.ArrayList;
045: import java.util.Iterator;
046: import java.util.List;
047: import org.netbeans.modules.ant.freeform.spi.support.Util;
048: import org.netbeans.modules.web.api.webmodule.WebProjectConstants;
049: import org.netbeans.spi.project.AuxiliaryConfiguration;
050: import org.netbeans.spi.project.support.ant.AntProjectHelper;
051: import org.openide.filesystems.FileObject;
052: import org.openide.util.NbBundle;
053: import org.w3c.dom.Document;
054: import org.w3c.dom.Element;
055: import org.w3c.dom.Node;
056:
057: /**
058: * Reads/writes project.xml.
059: * Handling of /1 vs. /2 namespace: either namespace can be read;
060: * when writing, attempts to keep existing namespace when possible, but
061: * will always write a /2 namespace when it is necessary (for <tt>web-inf</tt> elemennt).
062: *
063: * @author Jesse Glick, David Konecny, Pavel Buzek
064: */
065: public class WebProjectGenerator {
066:
067: // /** Keep root elements in the order specified by project's XML schema. */
068: private static final String[] rootElementsOrder = new String[] {
069: "name", "properties", "folders", "ide-actions", "export",
070: "view", "subprojects" }; // NOI18N
071: private static final String[] viewElementsOrder = new String[] {
072: "items", "context-menu" }; // NOI18N
073:
074: // // this order is not required by schema, but follow it to minimize randomness a bit
075: private static final String[] folderElementsOrder = new String[] {
076: "source-folder", "build-folder" }; // NOI18N
077: private static final String[] viewItemElementsOrder = new String[] {
078: "source-folder", "source-file" }; // NOI18N
079:
080: private WebProjectGenerator() {
081: }
082:
083: /**
084: * @param sources list of pairs[relative path, display name]
085: */
086: public static void putWebSourceFolder(AntProjectHelper helper,
087: List<String> sources) {
088: putFolder(WebProjectConstants.TYPE_DOC_ROOT, helper, sources);
089: }
090:
091: /**
092: * @param sources list of pairs[relative path, display name]
093: */
094: // TMYSIK handle this (version 1/2)
095: public static void putWebInfFolder(AntProjectHelper helper,
096: List<String> sources) {
097: putFolder(WebProjectConstants.TYPE_WEB_INF, helper, sources);
098: }
099:
100: // allowed folder types: WebProjectConstants.TYPE_DOC_ROOT, WebProjectConstants.TYPE_WEB_INF
101: private static void putFolder(String folderType,
102: AntProjectHelper helper, List<String> sources) {
103: String label = null;
104: if (WebProjectConstants.TYPE_DOC_ROOT.equals(folderType)) {
105: label = NbBundle.getMessage(WebProjectGenerator.class,
106: "LBL_WebPages");
107: } else if (WebProjectConstants.TYPE_WEB_INF.equals(folderType)) {
108: label = NbBundle.getMessage(WebProjectGenerator.class,
109: "LBL_WebInf");
110: } else {
111: assert false : "Unknown folder type: " + folderType;
112: }
113:
114: Element data = Util.getPrimaryConfigurationData(helper);
115: Document doc = data.getOwnerDocument();
116: Element foldersEl = Util.findElement(data, "folders",
117: Util.NAMESPACE); // NOI18N
118: if (foldersEl == null) {
119: foldersEl = doc.createElementNS(Util.NAMESPACE, "folders"); // NOI18N
120: Util.appendChildElement(data, foldersEl, rootElementsOrder);
121: } else {
122: List l = Util.findSubElements(foldersEl);
123: for (int i = 0; i < l.size(); i++) {
124: Element e = (Element) l.get(i);
125: Element te = Util
126: .findElement(e, "type", Util.NAMESPACE);
127: if (te != null && Util.findText(te).equals(folderType)) {
128: foldersEl.removeChild(e);
129: break;
130: }
131: }
132: }
133:
134: Element viewEl = Util.findElement(data, "view", Util.NAMESPACE); // NOI18N
135: if (viewEl == null) {
136: viewEl = doc.createElementNS(Util.NAMESPACE, "view"); // NOI18N
137: Util.appendChildElement(data, viewEl, rootElementsOrder);
138: }
139: Element itemsEl = Util.findElement(viewEl, "items",
140: Util.NAMESPACE); // NOI18N
141: if (itemsEl == null) {
142: itemsEl = doc.createElementNS(Util.NAMESPACE, "items"); // NOI18N
143: Util.appendChildElement(viewEl, itemsEl, viewElementsOrder);
144: } else {
145: List l = Util.findSubElements(itemsEl);
146: for (int i = 0; i < l.size(); i++) {
147: Element e = (Element) l.get(i);
148: if (e.hasAttribute("style")) {
149: if (e.getAttribute("style").equals("tree")) {
150: // #110173
151: Element labelElement = Util.findElement(e,
152: "label", Util.NAMESPACE);
153: if (labelElement != null
154: && label.equals(Util
155: .findText(labelElement))) {
156: itemsEl.removeChild(e);
157: break;
158: }
159: }
160: }
161: }
162: }
163:
164: Iterator<String> it1 = sources.iterator();
165: while (it1.hasNext()) {
166: String path = it1.next();
167: assert it1.hasNext();
168: String dispname = it1.next();
169: Element sourceFolderEl = doc.createElementNS(
170: Util.NAMESPACE, "source-folder"); // NOI18N
171: Element el = doc.createElementNS(Util.NAMESPACE, "label"); // NOI18N
172: el.appendChild(doc.createTextNode(dispname));
173: sourceFolderEl.appendChild(el);
174: el = doc.createElementNS(Util.NAMESPACE, "type"); // NOI18N
175: el.appendChild(doc.createTextNode(folderType));
176: sourceFolderEl.appendChild(el);
177: el = doc.createElementNS(Util.NAMESPACE, "location"); // NOI18N
178: el.appendChild(doc.createTextNode(path));
179: sourceFolderEl.appendChild(el);
180: Util.appendChildElement(foldersEl, sourceFolderEl,
181: folderElementsOrder);
182:
183: sourceFolderEl = doc.createElementNS(Util.NAMESPACE,
184: "source-folder"); // NOI18N
185: sourceFolderEl.setAttribute("style", "tree"); // NOI18N
186: el = doc.createElementNS(Util.NAMESPACE, "label"); // NOI18N
187: el.appendChild(doc.createTextNode(label));
188: sourceFolderEl.appendChild(el);
189: el = doc.createElementNS(Util.NAMESPACE, "location"); // NOI18N
190: el.appendChild(doc.createTextNode(path)); // NOI18N
191: sourceFolderEl.appendChild(el);
192: Node firstNode = itemsEl.getFirstChild();
193: if (firstNode != null) {
194: if (WebProjectConstants.TYPE_DOC_ROOT
195: .equals(folderType)) {
196: insertWebElement(itemsEl, firstNode, sourceFolderEl);
197: } else if (WebProjectConstants.TYPE_WEB_INF
198: .equals(folderType)) {
199: insertWebInfElement(itemsEl, firstNode,
200: sourceFolderEl);
201: }
202: } else {
203: Util.appendChildElement(itemsEl, sourceFolderEl,
204: viewItemElementsOrder);
205: }
206: }
207: Util.putPrimaryConfigurationData(helper, data);
208: }
209:
210: private static void insertWebElement(Element itemsEl,
211: Node firstNode, Element sourceFolderEl) {
212: itemsEl.insertBefore(sourceFolderEl, firstNode);
213: }
214:
215: private static void insertWebInfElement(Element itemsEl,
216: Node firstNode, Element sourceFolderEl) {
217: Node secondNode = firstNode.getNextSibling();
218: if (secondNode != null) {
219: itemsEl.insertBefore(sourceFolderEl, secondNode);
220: } else {
221: Util.appendChildElement(itemsEl, sourceFolderEl,
222: viewItemElementsOrder);
223: }
224: }
225:
226: /**
227: * Read web modules from the project.
228: * @param helper AntProjectHelper instance
229: * @param aux AuxiliaryConfiguration instance
230: * @return list of WebModule instances
231: */
232: public static List<WebModule> getWebmodules(
233: AntProjectHelper helper, AuxiliaryConfiguration aux) {
234: //assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess();
235: List<WebModule> list = new ArrayList<WebModule>();
236: Element data = aux.getConfigurationFragment(
237: WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_2,
238: true); // NOI18N
239: if (data == null) {
240: data = aux.getConfigurationFragment(
241: WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_1,
242: true); // NOI18N
243: if (data == null) {
244: return list;
245: }
246: }
247: List<Element> wms = Util.findSubElements(data);
248: Iterator<Element> it = wms.iterator();
249: while (it.hasNext()) {
250: Element wmEl = it.next();
251: WebModule wm = new WebModule();
252: Iterator it2 = Util.findSubElements(wmEl).iterator();
253: while (it2.hasNext()) {
254: Element el = (Element) it2.next();
255: if (el.getLocalName().equals("doc-root")) { // NOI18N
256: wm.docRoot = Util.findText(el);
257: continue;
258: }
259: if (el.getLocalName().equals("classpath")) { // NOI18N
260: wm.classpath = Util.findText(el);
261: continue;
262: }
263: if (el.getLocalName().equals("context-path")) { // NOI18N
264: wm.contextPath = Util.findText(el);
265: continue;
266: }
267: if (el.getLocalName().equals("j2ee-spec-level")) { // NOI18N
268: wm.j2eeSpecLevel = Util.findText(el);
269: continue;
270: }
271: if (el.getLocalName().equals("web-inf")) { // NOI18N
272: wm.webInf = Util.findText(el);
273: }
274: }
275: list.add(wm);
276: }
277: return list;
278: }
279:
280: /**
281: * Update web modules of the project. Project is left modified
282: * and you must save it explicitely.
283: * @param helper AntProjectHelper instance
284: * @param aux AuxiliaryConfiguration instance
285: * @param webModules list of WebModule instances
286: */
287: public static void putWebModules(AntProjectHelper helper,
288: AuxiliaryConfiguration aux, List<WebModule> webModules) {
289: //assert ProjectManager.mutex().isWriteAccess();
290: // do we need /2 data?
291: boolean need2 = false;
292: String namespace;
293: // Look for existing /2 data.
294: Element data = aux.getConfigurationFragment(
295: WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_2,
296: true);
297: if (data != null) {
298: // Fine, use it as is.
299: need2 = true;
300: namespace = WebProjectNature.NS_WEB_2;
301: } else {
302: // Or, for existing /1 data.
303:
304: // check whether we need /2 data.
305: for (WebModule webModule : webModules) {
306: String expected = webModule.docRoot + "/WEB-INF"; //NOI18N
307: String webInf = webModule.webInf;
308: if (webInf != null && !webInf.equals(expected)) {
309: need2 = true;
310: break;
311: }
312: }
313: namespace = need2 ? WebProjectNature.NS_WEB_2
314: : WebProjectNature.NS_WEB_1;
315: data = aux.getConfigurationFragment(
316: WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_1,
317: true);
318: if (data != null) {
319: if (need2) {
320: // Have to upgrade.
321: aux.removeConfigurationFragment(
322: WebProjectNature.EL_WEB,
323: WebProjectNature.NS_WEB_1, true);
324: data = Util.getPrimaryConfigurationData(helper)
325: .getOwnerDocument().createElementNS(
326: WebProjectNature.NS_WEB_2,
327: WebProjectNature.EL_WEB);
328: } // else can use it as is
329: } else {
330: // Create /1 or /2 data acc. to need.
331: data = Util.getPrimaryConfigurationData(helper)
332: .getOwnerDocument().createElementNS(namespace,
333: WebProjectNature.EL_WEB);
334: }
335: }
336:
337: Document doc = data.getOwnerDocument();
338: List<Element> wms = Util.findSubElements(data);
339: Iterator<Element> it = wms.iterator();
340: while (it.hasNext()) {
341: Element wmEl = it.next();
342: data.removeChild(wmEl);
343: }
344: Iterator<WebModule> it2 = webModules.iterator();
345: while (it2.hasNext()) {
346: Element wmEl = doc.createElementNS(namespace, "web-module"); // NOI18N
347: data.appendChild(wmEl);
348: WebModule wm = it2.next();
349: Element el;
350: if (wm.docRoot != null) {
351: el = doc.createElementNS(namespace, "doc-root"); // NOI18N
352: el.appendChild(doc.createTextNode(wm.docRoot));
353: wmEl.appendChild(el);
354: }
355: if (wm.classpath != null) {
356: el = doc.createElementNS(namespace, "classpath"); // NOI18N
357: el.appendChild(doc.createTextNode(wm.classpath));
358: wmEl.appendChild(el);
359: }
360: if (wm.contextPath != null) {
361: el = doc.createElementNS(namespace, "context-path"); // NOI18N
362: el.appendChild(doc.createTextNode(wm.contextPath));
363: wmEl.appendChild(el);
364: }
365: if (wm.j2eeSpecLevel != null) {
366: el = doc.createElementNS(namespace, "j2ee-spec-level"); // NOI18N
367: el.appendChild(doc.createTextNode(wm.j2eeSpecLevel));
368: wmEl.appendChild(el);
369: }
370: if (need2 && wm.webInf != null) {
371: assert namespace.equals(WebProjectNature.NS_WEB_2);
372: el = doc.createElementNS(namespace, "web-inf"); // NOI18N
373: el.appendChild(doc.createTextNode(wm.webInf));
374: wmEl.appendChild(el);
375: }
376: }
377: aux.putConfigurationFragment(data, true);
378: }
379:
380: /**
381: * Structure describing web module.
382: * Data in the struct are in the same format as they are stored in XML.
383: */
384: public static final class WebModule {
385: public String docRoot;
386: public String classpath;
387: public String contextPath;
388: public String j2eeSpecLevel;
389: public String webInf;
390: }
391:
392: }
|