1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
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 < web-app >
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
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 }