001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.jetspeed.tools.deploy;
018:
019: import java.util.Arrays;
020: import java.util.List;
021:
022: import org.apache.commons.lang.StringUtils;
023: import org.jdom.Document;
024: import org.jdom.Element;
025: import org.jdom.JDOMException;
026: import org.jdom.Namespace;
027: import org.jdom.Parent;
028: import org.jdom.xpath.XPath;
029:
030: /**
031: * Utilities for manipulating the web.xml deployment descriptor
032: *
033: * @author <a href="mailto:sweaver@einnovation.com">Scott T. Weaver </a>
034: * @author <a href="mailto:mavery@einnovation.com">Matt Avery </a>
035: * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
036: * @version $Id: WebDescriptorUtilities.java,v 1.2 2004/05/12 22:25:04 taylor
037: * Exp $
038: */
039: public abstract class JetspeedWebApplicationRewriter {
040: public static final String JETSPEED_CONTAINER = "JetspeedContainer";
041: public static final String JETSPEED_SERVLET_CLASS = "org.apache.jetspeed.container.JetspeedContainerServlet";
042: public static final String JETSPEED_SERVLET_DISPLAY_NAME = "Jetspeed Container";
043: public static final String JETSPEED_SERVLET_DESCRIPTION = "MVC Servlet for Jetspeed Portlet Applications";
044: public static final String NAMESPACE_PREFIX = "js";
045: protected static final String WEB_XML_PATH = "WEB-INF/web.xml";
046:
047: private Document document;
048: private String portletApplication;
049: private boolean changed = false;
050: private boolean portletTaglibAdded = false;
051:
052: public JetspeedWebApplicationRewriter(Document doc,
053: String portletApplication) {
054: this .document = doc;
055: this .portletApplication = portletApplication;
056: }
057:
058: public JetspeedWebApplicationRewriter(Document doc) {
059: this .document = doc;
060: }
061:
062: /**
063: *
064: * <p>
065: * processWebXML
066: * </p>
067: *
068: * Infuses this PortletApplicationWar's web.xml file with
069: * <code>servlet</code> and a <code>servlet-mapping</code> element for
070: * the JetspeedContainer servlet. This is only done if the descriptor does
071: * not already contain these items.
072: *
073: * @throws MetaDataException
074: * if there is a problem infusing
075: */
076: public void processWebXML() throws Exception {
077: try {
078: Element root = document.getRootElement();
079:
080: Object jetspeedServlet = getXPath(getJetspeedServletXPath())
081: .selectSingleNode(document);
082: Object jetspeedServletMapping = getXPath(
083: getJetspeedServletMappingXPath()).selectSingleNode(
084: document);
085: Object portletTaglib = getXPath(getPortletTagLibXPath())
086: .selectSingleNode(document);
087:
088: if (!document.hasRootElement()) {
089: root = new Element("web-app");
090: document.setRootElement(root);
091: }
092:
093: if (jetspeedServlet == null) {
094: insertJetspeedServlet(root);
095: changed = true;
096: } else {
097: // double check for register at Init
098: if (jetspeedServlet instanceof Element) {
099: Parent jetspeedServletElement = ((Element) jetspeedServlet)
100: .getParent();
101: if (null == getXPath(
102: "js:init-param/js:param-name[contains(child::text(), \"contextName\")]")
103: .selectSingleNode(jetspeedServletElement)) {
104: insertContextNameParam((Element) jetspeedServletElement);
105: }
106: if (null == getXPath("js:load-on-startup")
107: .selectSingleNode(jetspeedServletElement)) {
108: insertLoadOnStartup((Element) jetspeedServletElement);
109: }
110: }
111: }
112:
113: if (jetspeedServletMapping == null) {
114: insertJetspeedServletMapping(root);
115: changed = true;
116: }
117:
118: if (portletTaglib == null) {
119: insertPortletTagLib(root);
120: changed = true;
121: portletTaglibAdded = true;
122: }
123: } catch (Exception e) {
124: throw new Exception(
125: "Unable to process web.xml for infusion "
126: + e.toString(), e);
127: }
128:
129: }
130:
131: protected void insertContextNameParam(Element jetspeedServletElement) {
132: Namespace namespace = jetspeedServletElement.getNamespace();
133: Element param2Name = new Element("param-name", namespace)
134: .addContent("contextName");
135: Element param2Value = new Element("param-value", namespace)
136: .addContent(portletApplication);
137: Element init2Param = new Element("init-param", namespace);
138: init2Param.addContent(param2Name);
139: init2Param.addContent(param2Value);
140: jetspeedServletElement.addContent(init2Param);
141:
142: }
143:
144: protected void insertLoadOnStartup(Element jetspeedServletElement) {
145: Namespace namespace = jetspeedServletElement.getNamespace();
146: Element loadOnStartup = new Element("load-on-startup",
147: namespace).addContent("0");
148: jetspeedServletElement.addContent(loadOnStartup);
149: }
150:
151: public boolean isChanged() {
152: return changed;
153: }
154:
155: /**
156: *
157: * <p>
158: * insertElementCorrectly
159: * </p>
160: *
161: * @param root
162: * JDom element representing the < web-app >
163: * @param toInsert
164: * JDom element to insert into the web.xml hierarchy.
165: * @param elementsBefore
166: * an array of web.xml elements that should be defined before the
167: * element we want to insert. This order should be the order
168: * defined by the web.xml's DTD type definition.
169: */
170: protected void insertElementCorrectly(Element root,
171: Element toInsert, String[] elementsBefore) throws Exception {
172: List allChildren = root.getChildren();
173: List elementsBeforeList = Arrays.asList(elementsBefore);
174: toInsert.detach();
175: int insertAfter = 0;
176: int count = 0;
177: for (int i = 0; i < allChildren.size(); i++) {
178: Element element = (Element) allChildren.get(i);
179: if (elementsBeforeList.contains(element.getName())) {
180: // determine the Content index of the element to insert after
181: insertAfter = root.indexOf(element);
182: }
183: count++;
184: }
185:
186: insertAfter = (count == 0) ? 0 : insertAfter + 1;
187:
188: try {
189: root.addContent(insertAfter, toInsert);
190: } catch (ArrayIndexOutOfBoundsException e) {
191: root.addContent(toInsert);
192: }
193: }
194:
195: /**
196: * @return Returns the portletTaglibAdded.
197: */
198: public boolean isPortletTaglibAdded() {
199: return portletTaglibAdded;
200: }
201:
202: /**
203: * Returns the xpath containing the namespace prefix 'js' mapped to the document
204: * default namespace.
205: *
206: * @param path
207: * @return XPath
208: * @throws JDOMException
209: */
210: protected XPath getXPath(String path) throws JDOMException {
211: XPath xpath = XPath.newInstance(path);
212: Element root = document.getRootElement();
213: if (root != null) {
214: if (StringUtils.isNotEmpty(root.getNamespaceURI())) {
215: xpath.addNamespace(NAMESPACE_PREFIX, root
216: .getNamespaceURI());
217: }
218: }
219: return xpath;
220: }
221:
222: /**
223: * Returns the jetspeed servlet xpath.
224: * The returned path must contain the namespace prefix 'js'.
225: *
226: * @return jetspeed servlet xpath
227: */
228: protected abstract String getJetspeedServletXPath();
229:
230: /**
231: * Returns the jetspeed servlet mapping xpath.
232: * The returned path must contain the namespace prefix 'js'.
233: *
234: * @return jetspeed servlet mapping xpath
235: */
236: protected abstract String getJetspeedServletMappingXPath();
237:
238: /**
239: * Returns the portlet taglib xpath.
240: * The returned path must contain the namespace prefix 'js'.
241: *
242: * @return portlet taglib xpath
243: */
244: protected abstract String getPortletTagLibXPath();
245:
246: /**
247: * Inserts the jetspeed servlet into web.xml
248: *
249: * @param root
250: * @throws Exception
251: */
252: protected abstract void insertJetspeedServlet(Element root)
253: throws Exception;
254:
255: /**
256: * Inserts the jetspeed servlet mapping into web.xml
257: *
258: * @param root
259: * @throws Exception
260: */
261: protected abstract void insertJetspeedServletMapping(Element root)
262: throws Exception;
263:
264: /**
265: * Inserts the portlet taglib into web.xml
266: *
267: * @param root
268: * @throws Exception
269: */
270: protected abstract void insertPortletTagLib(Element root)
271: throws Exception;
272: }
|