View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.jetspeed.tools.deploy;
18  
19  import java.util.Arrays;
20  import java.util.List;
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.jdom.Document;
24  import org.jdom.Element;
25  import org.jdom.JDOMException;
26  import org.jdom.Namespace;
27  import org.jdom.Parent;
28  import org.jdom.xpath.XPath;
29  
30  /***
31   * Utilities for manipulating the web.xml deployment descriptor
32   * 
33   * @author <a href="mailto:sweaver@einnovation.com">Scott T. Weaver </a>
34   * @author <a href="mailto:mavery@einnovation.com">Matt Avery </a>
35   * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>
36   * @version $Id: WebDescriptorUtilities.java,v 1.2 2004/05/12 22:25:04 taylor
37   *                Exp $
38   */
39  public abstract class JetspeedWebApplicationRewriter
40  {
41      public static final String JETSPEED_CONTAINER = "JetspeedContainer";
42      public static final String JETSPEED_SERVLET_CLASS = "org.apache.jetspeed.container.JetspeedContainerServlet";
43      public static final String JETSPEED_SERVLET_DISPLAY_NAME = "Jetspeed Container";
44      public static final String JETSPEED_SERVLET_DESCRIPTION = "MVC Servlet for Jetspeed Portlet Applications";
45      public static final String NAMESPACE_PREFIX = "js";
46      protected static final String WEB_XML_PATH = "WEB-INF/web.xml";
47  
48      private Document document;
49      private String portletApplication;
50      private boolean changed = false;
51      private boolean portletTaglibAdded = false;
52      
53      public JetspeedWebApplicationRewriter(Document doc, String portletApplication)
54      {
55              this.document = doc;
56              this.portletApplication = portletApplication;
57      }
58  
59      public JetspeedWebApplicationRewriter(Document doc)
60      {
61              this.document = doc;
62      }
63      
64      /***
65       * 
66       * <p>
67       * processWebXML
68       * </p>
69       * 
70       * Infuses this PortletApplicationWar's web.xml file with
71       * <code>servlet</code> and a <code>servlet-mapping</code> element for
72       * the JetspeedContainer servlet. This is only done if the descriptor does
73       * not already contain these items.
74       * 
75       * @throws MetaDataException
76       *             if there is a problem infusing
77       */
78      public void processWebXML()
79      throws Exception
80      {
81          try
82          {
83              Element root = document.getRootElement();
84          
85              Object jetspeedServlet = getXPath(getJetspeedServletXPath()).selectSingleNode(document);
86              Object jetspeedServletMapping = getXPath(getJetspeedServletMappingXPath()).selectSingleNode(document);
87              Object portletTaglib = getXPath(getPortletTagLibXPath()).selectSingleNode(document);
88              
89              if (!document.hasRootElement())
90              {
91                  root = new Element("web-app");
92                  document.setRootElement(root);
93              }
94          
95              if (jetspeedServlet == null)
96              {
97                  insertJetspeedServlet(root);
98                  changed = true;
99              }
100             else
101             {
102                 // double check for register at Init
103                 if (jetspeedServlet instanceof Element)
104                 {
105                     Parent jetspeedServletElement =((Element)jetspeedServlet).getParent();
106                     if (null == getXPath("js:init-param/js:param-name[contains(child::text(), \"contextName\")]").selectSingleNode(jetspeedServletElement))
107                     {
108                       insertContextNameParam((Element)jetspeedServletElement);
109                     }
110                     if (null == getXPath("js:load-on-startup").selectSingleNode(jetspeedServletElement))
111                     {
112                         insertLoadOnStartup((Element) jetspeedServletElement);
113                     }
114                 }
115             }
116     
117             if (jetspeedServletMapping == null)
118             {
119                 insertJetspeedServletMapping(root);
120                 changed = true;
121             }
122             
123             if(portletTaglib == null)
124             {
125                 insertPortletTagLib(root);
126                 changed = true;
127                 portletTaglibAdded = true;
128             }
129         }
130         catch (Exception e)
131         {
132             throw new Exception("Unable to process web.xml for infusion " + e.toString(), e);
133         }
134     
135     }
136     
137     protected void insertContextNameParam(Element jetspeedServletElement)
138     {
139         Namespace namespace = jetspeedServletElement.getNamespace();
140         Element param2Name = new Element("param-name", namespace).addContent("contextName");
141         Element param2Value = new Element("param-value", namespace).addContent(portletApplication); 
142         Element init2Param = new Element("init-param", namespace);
143         init2Param.addContent(param2Name);
144         init2Param.addContent(param2Value);
145         jetspeedServletElement.addContent(init2Param);                    
146         
147     }
148     
149     protected void insertLoadOnStartup(Element jetspeedServletElement)
150     {
151         Namespace namespace = jetspeedServletElement.getNamespace();
152         Element loadOnStartup = new Element("load-on-startup", namespace).addContent("0");
153         jetspeedServletElement.addContent(loadOnStartup);        
154     }
155     
156     public boolean isChanged()
157     {
158         return changed;
159     }
160     
161     /***
162      * 
163      * <p>
164      * insertElementCorrectly
165      * </p>
166      * 
167      * @param root
168      *            JDom element representing the &lt; web-app &gt;
169      * @param toInsert
170      *            JDom element to insert into the web.xml hierarchy.
171      * @param elementsBefore
172      *            an array of web.xml elements that should be defined before the
173      *            element we want to insert. This order should be the order
174      *            defined by the web.xml's DTD type definition.
175      */
176     protected void insertElementCorrectly( Element root, Element toInsert, String[] elementsBefore )
177     throws Exception
178     {
179         List allChildren = root.getChildren();
180         List elementsBeforeList = Arrays.asList(elementsBefore);
181         toInsert.detach();
182         int insertAfter = 0;
183         int count = 0;
184         for (int i = 0; i < allChildren.size(); i++)
185         {
186             Element element = (Element) allChildren.get(i);
187             if (elementsBeforeList.contains(element.getName()))
188             {
189                 // determine the Content index of the element to insert after
190                 insertAfter = root.indexOf(element);
191             }
192             count++;
193         }
194     
195         insertAfter = (count == 0) ? 0 : insertAfter + 1;
196         
197         try
198         {
199             root.addContent(insertAfter, toInsert);
200         }
201         catch (ArrayIndexOutOfBoundsException e)
202         {
203             root.addContent(toInsert);
204         }
205     }
206     
207     /***
208      * @return Returns the portletTaglibAdded.
209      */
210     public boolean isPortletTaglibAdded()
211     {
212         return portletTaglibAdded;
213     }
214     
215     /***
216      * Returns the xpath containing the namespace prefix 'js' mapped to the document
217      * default namespace.
218      * 
219      * @param path
220      * @return XPath
221      * @throws JDOMException
222      */
223     protected XPath getXPath(String path) throws JDOMException
224     {
225         XPath xpath = XPath.newInstance(path);
226         Element root = document.getRootElement();
227         if(root != null)
228         {
229             if(StringUtils.isNotEmpty(root.getNamespaceURI()))
230             {
231                 xpath.addNamespace(NAMESPACE_PREFIX, root.getNamespaceURI());
232             }
233         }
234         return xpath;
235     }
236     
237     /***
238      * Returns the jetspeed servlet xpath.
239      * The returned path must contain the namespace prefix 'js'.
240      * 
241      * @return jetspeed servlet xpath
242      */
243     protected abstract String getJetspeedServletXPath();
244     
245     /***
246      * Returns the jetspeed servlet mapping xpath.
247      * The returned path must contain the namespace prefix 'js'.
248      * 
249      * @return jetspeed servlet mapping xpath
250      */
251     protected abstract String getJetspeedServletMappingXPath();
252     
253     /***
254      * Returns the portlet taglib xpath.
255      * The returned path must contain the namespace prefix 'js'.
256      * 
257      * @return portlet taglib xpath
258      */
259     protected abstract String getPortletTagLibXPath();
260     
261     /***
262      * Inserts the jetspeed servlet into web.xml
263      * 
264      * @param root
265      * @throws Exception
266      */
267     protected abstract void insertJetspeedServlet(Element root) throws Exception;
268     
269     /***
270      * Inserts the jetspeed servlet mapping into web.xml
271      * 
272      * @param root
273      * @throws Exception
274      */
275     protected abstract void insertJetspeedServletMapping(Element root) throws Exception;
276     
277     /***
278      * Inserts the portlet taglib into web.xml
279      * 
280      * @param root
281      * @throws Exception
282      */
283     protected abstract void insertPortletTagLib(Element root) throws Exception;
284 }