| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.netbeans.modules.web.freeform; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import org.netbeans.modules.ant.freeform.spi.support.Util; |
| import org.netbeans.modules.web.api.webmodule.WebProjectConstants; |
| import org.netbeans.spi.project.AuxiliaryConfiguration; |
| import org.netbeans.spi.project.support.ant.AntProjectHelper; |
| import org.openide.util.NbBundle; |
| import org.openide.xml.XMLUtil; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| |
| /** |
| * Reads/writes project.xml. |
| * Handling of /1 vs. /2 namespace: either namespace can be read; |
| * when writing, attempts to keep existing namespace when possible, but |
| * will always write a /2 namespace when it is necessary (for <tt>web-inf</tt> elemennt). |
| * |
| * @author Jesse Glick, David Konecny, Pavel Buzek |
| */ |
| public class WebProjectGenerator { |
| |
| // /** Keep root elements in the order specified by project's XML schema. */ |
| private static final String[] rootElementsOrder = new String[]{"name", "properties", "folders", "ide-actions", "export", "view", "subprojects"}; // NOI18N |
| private static final String[] viewElementsOrder = new String[]{"items", "context-menu"}; // NOI18N |
| |
| // // this order is not required by schema, but follow it to minimize randomness a bit |
| private static final String[] folderElementsOrder = new String[]{"source-folder", "build-folder"}; // NOI18N |
| private static final String[] viewItemElementsOrder = new String[]{"source-folder", "source-file"}; // NOI18N |
| |
| private WebProjectGenerator() {} |
| |
| /** |
| * @param sources list of pairs[relative path, display name] |
| */ |
| public static void putWebSourceFolder(AntProjectHelper helper, List<String> sources) { |
| putFolder(WebProjectConstants.TYPE_DOC_ROOT, helper, sources); |
| } |
| |
| /** |
| * @param sources list of pairs[relative path, display name] |
| */ |
| // TMYSIK handle this (version 1/2) |
| public static void putWebInfFolder(AntProjectHelper helper, List<String> sources) { |
| putFolder(WebProjectConstants.TYPE_WEB_INF, helper, sources); |
| } |
| |
| // allowed folder types: WebProjectConstants.TYPE_DOC_ROOT, WebProjectConstants.TYPE_WEB_INF |
| private static void putFolder(String folderType, AntProjectHelper helper, List<String> sources) { |
| String label = null; |
| if (WebProjectConstants.TYPE_DOC_ROOT.equals(folderType)) { |
| label = NbBundle.getMessage(WebProjectGenerator.class, "LBL_WebPages"); |
| } else if (WebProjectConstants.TYPE_WEB_INF.equals(folderType)) { |
| label = NbBundle.getMessage(WebProjectGenerator.class, "LBL_WebInf"); |
| } else { |
| assert false : "Unknown folder type: " + folderType; |
| } |
| |
| Element data = Util.getPrimaryConfigurationData(helper); |
| Document doc = data.getOwnerDocument(); |
| Element foldersEl = XMLUtil.findElement(data, "folders", Util.NAMESPACE); // NOI18N |
| if (foldersEl == null) { |
| foldersEl = doc.createElementNS(Util.NAMESPACE, "folders"); // NOI18N |
| XMLUtil.appendChildElement(data, foldersEl, rootElementsOrder); |
| } else { |
| List l = XMLUtil.findSubElements(foldersEl); |
| for (int i = 0; i < l.size(); i++) { |
| Element e = (Element) l.get(i); |
| Element te = XMLUtil.findElement(e, "type", Util.NAMESPACE); |
| if (te != null && XMLUtil.findText(te).equals(folderType)) { |
| foldersEl.removeChild(e); |
| break; |
| } |
| } |
| } |
| |
| Element viewEl = XMLUtil.findElement(data, "view", Util.NAMESPACE); // NOI18N |
| if (viewEl == null) { |
| viewEl = doc.createElementNS(Util.NAMESPACE, "view"); // NOI18N |
| XMLUtil.appendChildElement(data, viewEl, rootElementsOrder); |
| } |
| Element itemsEl = XMLUtil.findElement(viewEl, "items", Util.NAMESPACE); // NOI18N |
| if (itemsEl == null) { |
| itemsEl = doc.createElementNS(Util.NAMESPACE, "items"); // NOI18N |
| XMLUtil.appendChildElement(viewEl, itemsEl, viewElementsOrder); |
| } else { |
| List l = XMLUtil.findSubElements(itemsEl); |
| for (int i = 0; i < l.size(); i++) { |
| Element e = (Element) l.get(i); |
| if (e.hasAttribute("style")) { |
| if (e.getAttribute("style").equals("tree")) { |
| // #110173 |
| Element labelElement = XMLUtil.findElement(e, "label", Util.NAMESPACE); |
| if (labelElement != null && label.equals(XMLUtil.findText(labelElement))) { |
| itemsEl.removeChild(e); |
| break; |
| } |
| } |
| } |
| } |
| } |
| |
| Iterator<String> it1 = sources.iterator(); |
| while (it1.hasNext()) { |
| String path = it1.next(); |
| assert it1.hasNext(); |
| String dispname = it1.next(); |
| Element sourceFolderEl = doc.createElementNS(Util.NAMESPACE, "source-folder"); // NOI18N |
| Element el = doc.createElementNS(Util.NAMESPACE, "label"); // NOI18N |
| el.appendChild(doc.createTextNode(dispname)); |
| sourceFolderEl.appendChild(el); |
| el = doc.createElementNS(Util.NAMESPACE, "type"); // NOI18N |
| el.appendChild(doc.createTextNode(folderType)); |
| sourceFolderEl.appendChild(el); |
| el = doc.createElementNS(Util.NAMESPACE, "location"); // NOI18N |
| el.appendChild(doc.createTextNode(path)); |
| sourceFolderEl.appendChild(el); |
| XMLUtil.appendChildElement(foldersEl, sourceFolderEl, folderElementsOrder); |
| |
| sourceFolderEl = doc.createElementNS(Util.NAMESPACE, "source-folder"); // NOI18N |
| sourceFolderEl.setAttribute("style", "tree"); // NOI18N |
| el = doc.createElementNS(Util.NAMESPACE, "label"); // NOI18N |
| el.appendChild(doc.createTextNode(label)); |
| sourceFolderEl.appendChild(el); |
| el = doc.createElementNS(Util.NAMESPACE, "location"); // NOI18N |
| el.appendChild(doc.createTextNode(path)); // NOI18N |
| sourceFolderEl.appendChild(el); |
| Node firstNode = itemsEl.getFirstChild(); |
| if (firstNode != null) { |
| if (WebProjectConstants.TYPE_DOC_ROOT.equals(folderType)) { |
| insertWebElement(itemsEl, firstNode, sourceFolderEl); |
| } else if (WebProjectConstants.TYPE_WEB_INF.equals(folderType)) { |
| insertWebInfElement(itemsEl, firstNode, sourceFolderEl); |
| } |
| } else { |
| XMLUtil.appendChildElement(itemsEl, sourceFolderEl, viewItemElementsOrder); |
| } |
| } |
| Util.putPrimaryConfigurationData(helper, data); |
| } |
| |
| private static void insertWebElement(Element itemsEl, Node firstNode, Element sourceFolderEl) { |
| itemsEl.insertBefore(sourceFolderEl, firstNode); |
| } |
| |
| private static void insertWebInfElement(Element itemsEl, Node firstNode, Element sourceFolderEl) { |
| Node secondNode = firstNode.getNextSibling(); |
| if (secondNode != null) { |
| itemsEl.insertBefore(sourceFolderEl, secondNode); |
| } else { |
| XMLUtil.appendChildElement(itemsEl, sourceFolderEl, viewItemElementsOrder); |
| } |
| } |
| |
| /** |
| * Read web modules from the project. |
| * @param helper AntProjectHelper instance |
| * @param aux AuxiliaryConfiguration instance |
| * @return list of WebModule instances |
| */ |
| public static List<WebModule> getWebmodules ( |
| AntProjectHelper helper, AuxiliaryConfiguration aux) { |
| //assert ProjectManager.mutex().isReadAccess() || ProjectManager.mutex().isWriteAccess(); |
| List<WebModule> list = new ArrayList<WebModule>(); |
| Element data = aux.getConfigurationFragment(WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_2, true); // NOI18N |
| if (data == null) { |
| data = aux.getConfigurationFragment(WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_1, true); // NOI18N |
| if (data == null) { |
| return list; |
| } |
| } |
| List<Element> wms = XMLUtil.findSubElements(data); |
| Iterator<Element> it = wms.iterator(); |
| while (it.hasNext()) { |
| Element wmEl = it.next(); |
| WebModule wm = new WebModule(); |
| Iterator it2 = XMLUtil.findSubElements(wmEl).iterator(); |
| while (it2.hasNext()) { |
| Element el = (Element)it2.next(); |
| if (el.getLocalName().equals("doc-root")) { // NOI18N |
| wm.docRoot = XMLUtil.findText(el); |
| continue; |
| } |
| if (el.getLocalName().equals("classpath")) { // NOI18N |
| wm.classpath = XMLUtil.findText(el); |
| continue; |
| } |
| if (el.getLocalName().equals("context-path")) { // NOI18N |
| wm.contextPath = XMLUtil.findText(el); |
| continue; |
| } |
| if (el.getLocalName().equals("j2ee-spec-level")) { // NOI18N |
| wm.j2eeSpecLevel = XMLUtil.findText(el); |
| continue; |
| } |
| if (el.getLocalName().equals("web-inf")) { // NOI18N |
| wm.webInf = XMLUtil.findText(el); |
| } |
| } |
| list.add(wm); |
| } |
| return list; |
| } |
| |
| /** |
| * Update web modules of the project. Project is left modified |
| * and you must save it explicitely. |
| * @param helper AntProjectHelper instance |
| * @param aux AuxiliaryConfiguration instance |
| * @param webModules list of WebModule instances |
| */ |
| public static void putWebModules(AntProjectHelper helper, |
| AuxiliaryConfiguration aux, List<WebModule> webModules) { |
| //assert ProjectManager.mutex().isWriteAccess(); |
| // do we need /2 data? |
| boolean need2 = false; |
| String namespace; |
| // Look for existing /2 data. |
| Element data = aux.getConfigurationFragment(WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_2, true); |
| if (data != null) { |
| // Fine, use it as is. |
| need2 = true; |
| namespace = WebProjectNature.NS_WEB_2; |
| } else { |
| // Or, for existing /1 data. |
| |
| // check whether we need /2 data. |
| for (WebModule webModule : webModules) { |
| String expected = webModule.docRoot + "/WEB-INF"; //NOI18N |
| String webInf = webModule.webInf; |
| if (webInf != null |
| && !webInf.equals(expected)) { |
| need2 = true; |
| break; |
| } |
| } |
| namespace = need2 ? WebProjectNature.NS_WEB_2 : WebProjectNature.NS_WEB_1; |
| data = aux.getConfigurationFragment(WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_1, true); |
| if (data != null) { |
| if (need2) { |
| // Have to upgrade. |
| aux.removeConfigurationFragment(WebProjectNature.EL_WEB, WebProjectNature.NS_WEB_1, true); |
| data = Util.getPrimaryConfigurationData(helper).getOwnerDocument() |
| .createElementNS(WebProjectNature.NS_WEB_2, WebProjectNature.EL_WEB); |
| } // else can use it as is |
| } else { |
| // Create /1 or /2 data acc. to need. |
| data = Util.getPrimaryConfigurationData(helper).getOwnerDocument() |
| .createElementNS(namespace, WebProjectNature.EL_WEB); |
| } |
| } |
| |
| Document doc = data.getOwnerDocument(); |
| List<Element> wms = XMLUtil.findSubElements(data); |
| Iterator<Element> it = wms.iterator(); |
| while (it.hasNext()) { |
| Element wmEl = it.next(); |
| data.removeChild(wmEl); |
| } |
| Iterator<WebModule> it2 = webModules.iterator(); |
| while (it2.hasNext()) { |
| Element wmEl = doc.createElementNS(namespace, "web-module"); // NOI18N |
| data.appendChild(wmEl); |
| WebModule wm = it2.next(); |
| Element el; |
| if (wm.docRoot != null) { |
| el = doc.createElementNS(namespace, "doc-root"); // NOI18N |
| el.appendChild(doc.createTextNode(wm.docRoot)); |
| wmEl.appendChild(el); |
| } |
| if (wm.classpath != null) { |
| el = doc.createElementNS(namespace, "classpath"); // NOI18N |
| el.appendChild(doc.createTextNode(wm.classpath)); |
| wmEl.appendChild(el); |
| } |
| if (wm.contextPath != null) { |
| el = doc.createElementNS(namespace, "context-path"); // NOI18N |
| el.appendChild(doc.createTextNode(wm.contextPath)); |
| wmEl.appendChild(el); |
| } |
| if (wm.j2eeSpecLevel != null) { |
| el = doc.createElementNS(namespace, "j2ee-spec-level"); // NOI18N |
| el.appendChild(doc.createTextNode(wm.j2eeSpecLevel)); |
| wmEl.appendChild(el); |
| } |
| if (need2 && wm.webInf != null) { |
| assert namespace.equals(WebProjectNature.NS_WEB_2); |
| el = doc.createElementNS(namespace, "web-inf"); // NOI18N |
| el.appendChild(doc.createTextNode(wm.webInf)); |
| wmEl.appendChild(el); |
| } |
| } |
| aux.putConfigurationFragment(data, true); |
| } |
| |
| /** |
| * Structure describing web module. |
| * Data in the struct are in the same format as they are stored in XML. |
| */ |
| public static final class WebModule { |
| public String docRoot; |
| public String classpath; |
| public String contextPath; |
| public String j2eeSpecLevel; |
| public String webInf; |
| } |
| |
| } |