1 /*
2 * ========================================================================
3 *
4 * Copyright 2003-2005 The Apache Software Foundation.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * ========================================================================
19 */
20 package org.apache.cactus.integration.ant.deployment.webapp;
21
22 import java.util.Iterator;
23
24 import org.apache.cactus.integration.ant.util.AntLog;
25 import org.apache.commons.logging.Log;
26 import org.w3c.dom.Element;
27
28 /**
29 * Helper class that can merge two web deployment descriptors.
30 *
31 * @since Cactus 1.5
32 * @version $Id: WebXmlMerger.java,v 1.2 2005/02/10 19:51:34 vmassol Exp $
33 */
34 public class WebXmlMerger
35 {
36 // Instance Variables ------------------------------------------------------
37
38 /**
39 * The original, authorative descriptor onto which the merges are performed.
40 */
41 private WebXml webXml;
42
43 /**
44 * The log to use.
45 */
46 private Log log = AntLog.NULL;
47
48 // Constructors ------------------------------------------------------------
49
50 /**
51 * Constructor.
52 *
53 * @param theWebXml The original descriptor
54 */
55 public WebXmlMerger(WebXml theWebXml)
56 {
57 this.webXml = theWebXml;
58 }
59
60 // Public Methods ----------------------------------------------------------
61
62 /**
63 * Merges the merge descriptor with the original descriptor.
64 *
65 * @param theMergeWebXml The descriptor to merge in
66 */
67 public final void merge(WebXml theMergeWebXml)
68 {
69 checkServletVersions(theMergeWebXml);
70 mergeContextParams(theMergeWebXml);
71 if (WebXmlVersion.V2_3.compareTo(this.webXml.getVersion()) <= 0)
72 {
73 mergeFilters(theMergeWebXml);
74 }
75 mergeServlets(theMergeWebXml);
76 if (WebXmlVersion.V2_3.compareTo(this.webXml.getVersion()) <= 0)
77 {
78 mergeResourceEnvironmentReferences(theMergeWebXml);
79 }
80 mergeResourceReferences(theMergeWebXml);
81 mergeSecurityConstraints(theMergeWebXml);
82 mergeLoginConfig(theMergeWebXml);
83 mergeSecurityRoles(theMergeWebXml);
84 mergeEnvironmentEntries(theMergeWebXml);
85 mergeEjbRefs(theMergeWebXml);
86 if (WebXmlVersion.V2_3.compareTo(this.webXml.getVersion()) <= 0)
87 {
88 mergeEjbLocalRefs(theMergeWebXml);
89 }
90 }
91
92 /**
93 * Sets the log to which events should be written. This method must be
94 * called before any of the other methods, because the class will rely on
95 * being able to log.
96 *
97 * @param theLog The log to use
98 */
99 public final void setLog(Log theLog)
100 {
101 this.log = theLog;
102 }
103
104 // Protected Methods -------------------------------------------------------
105
106 /**
107 * Checks the versions of the servlet API in each descriptor, and logs
108 * a warning if a mismatch might result in the loss of definitions.
109 *
110 * @param theWebXml The descriptor that will be merged with the original
111 */
112 protected final void checkServletVersions(WebXml theWebXml)
113 {
114 if ((this.webXml.getVersion() != null)
115 && (this.webXml.getVersion().compareTo(theWebXml.getVersion()) < 0))
116 {
117 this.log.warn(
118 "Merging elements from a version " + theWebXml.getVersion()
119 + " descriptor into a version " + this.webXml.getVersion()
120 + ", some elements may be skipped");
121 }
122 }
123
124 /**
125 * Merges the context-param definitions from the specified descriptor into
126 * the original descriptor.
127 *
128 * @param theWebXml The descriptor that contains the context-params
129 * definitions that are to be merged into the original descriptor
130 */
131 protected final void mergeContextParams(WebXml theWebXml)
132 {
133 Iterator contextParams = theWebXml.getElements(WebXmlTag.CONTEXT_PARAM);
134 int count = 0;
135 while (contextParams.hasNext())
136 {
137 String paramName = theWebXml.getContextParamName(
138 (Element) contextParams.next());
139 if (!webXml.hasContextParam(paramName))
140 {
141 webXml.addContextParam(theWebXml.getContextParam(paramName));
142 }
143 count++;
144 }
145 this.log.trace("Merged " + count + " context-param definition"
146 + (count != 1 ? "s " : " ") + "into the descriptor");
147 }
148
149 /**
150 * Merges the servlet definitions from the specified descriptor into the
151 * original descriptor.
152 *
153 * @param theWebXml The descriptor that contains the filter definitions
154 * that are to be merged into the original descriptor
155 */
156 protected final void mergeFilters(WebXml theWebXml)
157 {
158 Iterator filterNames = theWebXml.getFilterNames();
159 int count = 0;
160 while (filterNames.hasNext())
161 {
162 String filterName = (String) filterNames.next();
163 if (!webXml.hasFilter(filterName))
164 {
165 webXml.addFilter(theWebXml.getFilter(filterName));
166 }
167 else
168 {
169 // merge the parameters
170 Iterator filterInitParamNames =
171 theWebXml.getFilterInitParamNames(filterName);
172 while (filterInitParamNames.hasNext())
173 {
174 String paramName = (String) filterInitParamNames.next();
175 String paramValue =
176 theWebXml.getFilterInitParam(filterName, paramName);
177 webXml.addFilterInitParam(
178 filterName, paramName, paramValue);
179 }
180 }
181 // merge the mappings
182 Iterator filterMappings = theWebXml.getFilterMappings(filterName);
183 while (filterMappings.hasNext())
184 {
185 String urlPattern = (String) filterMappings.next();
186 webXml.addFilterMapping(filterName, urlPattern);
187 }
188 count++;
189 }
190 this.log.trace("Merged " + count + " filter definition"
191 + (count != 1 ? "s " : " ") + "into the descriptor");
192 }
193
194 /**
195 * Merges the servlet definitions from the specified descriptor into the
196 * original descriptor.
197 *
198 * @param theWebXml The descriptor that contains the servlet definitions
199 * that are to be merged into the original descriptor
200 */
201 protected final void mergeServlets(WebXml theWebXml)
202 {
203 Iterator servletNames = theWebXml.getServletNames();
204 int count = 0;
205 while (servletNames.hasNext())
206 {
207 String servletName = (String) servletNames.next();
208 if (!webXml.hasServlet(servletName))
209 {
210 webXml.addServlet(theWebXml.getServlet(servletName));
211 }
212 else
213 {
214 // merge the parameters
215 Iterator servletInitParamNames =
216 theWebXml.getServletInitParamNames(servletName);
217 while (servletInitParamNames.hasNext())
218 {
219 String paramName = (String) servletInitParamNames.next();
220 String paramValue =
221 theWebXml.getServletInitParam(servletName, paramName);
222 webXml.addServletInitParam(
223 servletName, paramName, paramValue);
224 }
225 String roleName =
226 theWebXml.getServletRunAsRoleName(servletName);
227 if (roleName != null)
228 {
229 webXml.addServletRunAsRoleName(servletName, roleName);
230 }
231 }
232 // merge the mappings
233 Iterator servletMappings =
234 theWebXml.getServletMappings(servletName);
235 while (servletMappings.hasNext())
236 {
237 String urlPattern = (String) servletMappings.next();
238 webXml.addServletMapping(servletName, urlPattern);
239 }
240 count++;
241 }
242 this.log.trace("Merged " + count + " servlet definition"
243 + (count != 1 ? "s " : " ") + "into the descriptor");
244 }
245
246 /**
247 * Merges the resource environment references from the provided descriptor
248 * into the original descriptor.
249 *
250 * @param theWebXml The descriptor that contains the references that are to
251 * be merged into the original descriptor
252 */
253 protected final void mergeResourceEnvironmentReferences(WebXml theWebXml)
254 {
255 int count = insertElements(theWebXml, WebXmlTag.RESOURCE_ENV_REF);
256 if (count > 0)
257 {
258 this.log.trace("Merged " + count + " resource environment "
259 + "reference" + (count != 1 ? "s " : " ") + "into the "
260 + "descriptor");
261 }
262 }
263
264 /**
265 * Merges the resource references from the provided descriptor into the
266 * original descriptor.
267 *
268 * @param theWebXml The descriptor that contains the resource refs that
269 * are to be merged into the original descriptor
270 */
271 protected final void mergeResourceReferences(WebXml theWebXml)
272 {
273 int count = insertElements(theWebXml, WebXmlTag.RESOURCE_REF);
274 if (count > 0)
275 {
276 this.log.trace("Merged " + count + " resource reference"
277 + (count != 1 ? "s " : " ") + "into the descriptor");
278 }
279 }
280
281 /**
282 * Merges the
283 *
284 * @param theWebXml The descriptor that contains the security constraints
285 * that are to be merged into the original descriptor
286 */
287 protected final void mergeSecurityConstraints(WebXml theWebXml)
288 {
289 int count = insertElements(theWebXml, WebXmlTag.SECURITY_CONSTRAINT);
290 if (count > 0)
291 {
292 this.log.trace("Merged " + count + " security constraint"
293 + (count != 1 ? "s " : " ") + "into the descriptor");
294 }
295 }
296
297 /**
298 * Merges the login configuration from the provided descriptor into the
299 * original descriptor, thereby eventually replacing the existing login
300 * config.
301 *
302 * @param theWebXml The descriptor that contains the login config that
303 * is to be merged into the original descriptor
304 */
305 protected final void mergeLoginConfig(WebXml theWebXml)
306 {
307 boolean replaced = replaceElement(theWebXml, WebXmlTag.LOGIN_CONFIG);
308 if (replaced)
309 {
310 this.log.trace(
311 "Merged the login configuration into the descriptor");
312 }
313 }
314
315 /**
316 * Merges the security roles from the provided descriptor into the original
317 * descriptor.
318 *
319 * @param theWebXml The descriptor that contains the security roles that
320 * are to be merged into the original descriptor
321 */
322 protected final void mergeSecurityRoles(WebXml theWebXml)
323 {
324 Iterator securityRoleNames = theWebXml.getSecurityRoleNames();
325 int count = 0;
326 while (securityRoleNames.hasNext())
327 {
328 String securityRoleName = (String) securityRoleNames.next();
329 if (!this.webXml.hasSecurityRole(securityRoleName))
330 {
331 this.webXml.addSecurityRole(securityRoleName);
332 }
333 }
334 if (count > 0)
335 {
336 this.log.trace("Merged " + count + " security role"
337 + (count != 1 ? "s " : " ") + "into the descriptor");
338 }
339 }
340
341 /**
342 * Merges the environment entries from the provided descriptor into the
343 * original descriptor.
344 *
345 * @param theWebXml The descriptor that contains the environment entries
346 * that are to be merged into the original descriptor
347 */
348 protected final void mergeEnvironmentEntries(WebXml theWebXml)
349 {
350 int count = insertElements(theWebXml, WebXmlTag.ENV_ENTRY);
351 if (count > 0)
352 {
353 this.log.trace("Merged " + count + " environment entr"
354 + (count != 1 ? "ies " : "y ") + "into the descriptor");
355 }
356 }
357
358 /**
359 * Merges the EJB references from the provided descriptor into the original
360 * descriptor.
361 *
362 * @param theWebXml The descriptor that contains the EJB refs that are to be
363 * merged into the original descriptor
364 */
365 protected final void mergeEjbRefs(WebXml theWebXml)
366 {
367 int count = insertElements(theWebXml, WebXmlTag.EJB_REF);
368 if (count > 0)
369 {
370 this.log.trace("Merged " + count + " EJB reference"
371 + (count != 1 ? "s " : "y ") + "into the descriptor");
372 }
373 }
374
375 /**
376 * Merges the EJB local references from the provided descriptor into the
377 * original descriptor.
378 *
379 * @param theWebXml The descriptor that contains the EJB local refs that are
380 * to be merged into the original descriptor
381 */
382 protected final void mergeEjbLocalRefs(WebXml theWebXml)
383 {
384 int count = insertElements(theWebXml, WebXmlTag.EJB_LOCAL_REF);
385 if (count > 0)
386 {
387 this.log.trace("Merged " + count + " EJB local reference"
388 + (count != 1 ? "s " : "y ") + "into the descriptor");
389 }
390 }
391
392 // Private Methods ---------------------------------------------------------
393
394 /**
395 * Insert all elements of the specified tag from the given descriptor into
396 * the original descriptor, and returns the number of elements that were
397 * added.
398 *
399 * @param theWebXml The descriptor that contains the elements that are to be
400 * merged into the original descriptor
401 * @param theTag Defines which elements will get merged
402 * @return The number of elements inserted into the original descriptor
403 */
404 private int insertElements(WebXml theWebXml, WebXmlTag theTag)
405 {
406 Iterator elements = theWebXml.getElements(theTag);
407 int count = 0;
408 while (elements.hasNext())
409 {
410 Element element = (Element) elements.next();
411 webXml.addElement(theTag, element);
412 count++;
413 }
414 return count;
415 }
416
417 /**
418 * Replaces the element of the specified tag in the original descriptor with
419 * the equivalent element in the specified descriptor.
420 *
421 * @param theWebXml The descriptor that contains the element that is to be
422 * added to the original descriptor, replacing the original
423 * definition
424 * @param theTag Defines which element will get replaced
425 * @return Whether the element was replaced
426 */
427 private boolean replaceElement(WebXml theWebXml, WebXmlTag theTag)
428 {
429 Iterator elements = theWebXml.getElements(theTag);
430 if (elements.hasNext())
431 {
432 webXml.replaceElement(theTag, (Element) elements.next());
433 return true;
434 }
435 return false;
436 }
437
438 }