001: /*
002: * ========================================================================
003: *
004: * Copyright 2003-2005 The Apache Software Foundation.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: *
018: * ========================================================================
019: */
020: package org.apache.cactus.integration.ant.deployment.webapp;
021:
022: import java.util.Iterator;
023:
024: import org.apache.cactus.integration.ant.util.AntLog;
025: import org.apache.commons.logging.Log;
026: import org.w3c.dom.Element;
027:
028: /**
029: * Helper class that can merge two web deployment descriptors.
030: *
031: * @since Cactus 1.5
032: * @version $Id: WebXmlMerger.java 239137 2005-02-10 19:51:34Z vmassol $
033: */
034: public class WebXmlMerger {
035: // Instance Variables ------------------------------------------------------
036:
037: /**
038: * The original, authorative descriptor onto which the merges are performed.
039: */
040: private WebXml webXml;
041:
042: /**
043: * The log to use.
044: */
045: private Log log = AntLog.NULL;
046:
047: // Constructors ------------------------------------------------------------
048:
049: /**
050: * Constructor.
051: *
052: * @param theWebXml The original descriptor
053: */
054: public WebXmlMerger(WebXml theWebXml) {
055: this .webXml = theWebXml;
056: }
057:
058: // Public Methods ----------------------------------------------------------
059:
060: /**
061: * Merges the merge descriptor with the original descriptor.
062: *
063: * @param theMergeWebXml The descriptor to merge in
064: */
065: public final void merge(WebXml theMergeWebXml) {
066: checkServletVersions(theMergeWebXml);
067: mergeContextParams(theMergeWebXml);
068: if (WebXmlVersion.V2_3.compareTo(this .webXml.getVersion()) <= 0) {
069: mergeFilters(theMergeWebXml);
070: }
071: mergeServlets(theMergeWebXml);
072: if (WebXmlVersion.V2_3.compareTo(this .webXml.getVersion()) <= 0) {
073: mergeResourceEnvironmentReferences(theMergeWebXml);
074: }
075: mergeResourceReferences(theMergeWebXml);
076: mergeSecurityConstraints(theMergeWebXml);
077: mergeLoginConfig(theMergeWebXml);
078: mergeSecurityRoles(theMergeWebXml);
079: mergeEnvironmentEntries(theMergeWebXml);
080: mergeEjbRefs(theMergeWebXml);
081: if (WebXmlVersion.V2_3.compareTo(this .webXml.getVersion()) <= 0) {
082: mergeEjbLocalRefs(theMergeWebXml);
083: }
084: }
085:
086: /**
087: * Sets the log to which events should be written. This method must be
088: * called before any of the other methods, because the class will rely on
089: * being able to log.
090: *
091: * @param theLog The log to use
092: */
093: public final void setLog(Log theLog) {
094: this .log = theLog;
095: }
096:
097: // Protected Methods -------------------------------------------------------
098:
099: /**
100: * Checks the versions of the servlet API in each descriptor, and logs
101: * a warning if a mismatch might result in the loss of definitions.
102: *
103: * @param theWebXml The descriptor that will be merged with the original
104: */
105: protected final void checkServletVersions(WebXml theWebXml) {
106: if ((this .webXml.getVersion() != null)
107: && (this .webXml.getVersion().compareTo(
108: theWebXml.getVersion()) < 0)) {
109: this .log.warn("Merging elements from a version "
110: + theWebXml.getVersion()
111: + " descriptor into a version "
112: + this .webXml.getVersion()
113: + ", some elements may be skipped");
114: }
115: }
116:
117: /**
118: * Merges the context-param definitions from the specified descriptor into
119: * the original descriptor.
120: *
121: * @param theWebXml The descriptor that contains the context-params
122: * definitions that are to be merged into the original descriptor
123: */
124: protected final void mergeContextParams(WebXml theWebXml) {
125: Iterator contextParams = theWebXml
126: .getElements(WebXmlTag.CONTEXT_PARAM);
127: int count = 0;
128: while (contextParams.hasNext()) {
129: String paramName = theWebXml
130: .getContextParamName((Element) contextParams.next());
131: if (!webXml.hasContextParam(paramName)) {
132: webXml.addContextParam(theWebXml
133: .getContextParam(paramName));
134: }
135: count++;
136: }
137: this .log.trace("Merged " + count + " context-param definition"
138: + (count != 1 ? "s " : " ") + "into the descriptor");
139: }
140:
141: /**
142: * Merges the servlet definitions from the specified descriptor into the
143: * original descriptor.
144: *
145: * @param theWebXml The descriptor that contains the filter definitions
146: * that are to be merged into the original descriptor
147: */
148: protected final void mergeFilters(WebXml theWebXml) {
149: Iterator filterNames = theWebXml.getFilterNames();
150: int count = 0;
151: while (filterNames.hasNext()) {
152: String filterName = (String) filterNames.next();
153: if (!webXml.hasFilter(filterName)) {
154: webXml.addFilter(theWebXml.getFilter(filterName));
155: } else {
156: // merge the parameters
157: Iterator filterInitParamNames = theWebXml
158: .getFilterInitParamNames(filterName);
159: while (filterInitParamNames.hasNext()) {
160: String paramName = (String) filterInitParamNames
161: .next();
162: String paramValue = theWebXml.getFilterInitParam(
163: filterName, paramName);
164: webXml.addFilterInitParam(filterName, paramName,
165: paramValue);
166: }
167: }
168: // merge the mappings
169: Iterator filterMappings = theWebXml
170: .getFilterMappings(filterName);
171: while (filterMappings.hasNext()) {
172: String urlPattern = (String) filterMappings.next();
173: webXml.addFilterMapping(filterName, urlPattern);
174: }
175: count++;
176: }
177: this .log.trace("Merged " + count + " filter definition"
178: + (count != 1 ? "s " : " ") + "into the descriptor");
179: }
180:
181: /**
182: * Merges the servlet definitions from the specified descriptor into the
183: * original descriptor.
184: *
185: * @param theWebXml The descriptor that contains the servlet definitions
186: * that are to be merged into the original descriptor
187: */
188: protected final void mergeServlets(WebXml theWebXml) {
189: Iterator servletNames = theWebXml.getServletNames();
190: int count = 0;
191: while (servletNames.hasNext()) {
192: String servletName = (String) servletNames.next();
193: if (!webXml.hasServlet(servletName)) {
194: webXml.addServlet(theWebXml.getServlet(servletName));
195: } else {
196: // merge the parameters
197: Iterator servletInitParamNames = theWebXml
198: .getServletInitParamNames(servletName);
199: while (servletInitParamNames.hasNext()) {
200: String paramName = (String) servletInitParamNames
201: .next();
202: String paramValue = theWebXml.getServletInitParam(
203: servletName, paramName);
204: webXml.addServletInitParam(servletName, paramName,
205: paramValue);
206: }
207: String roleName = theWebXml
208: .getServletRunAsRoleName(servletName);
209: if (roleName != null) {
210: webXml.addServletRunAsRoleName(servletName,
211: roleName);
212: }
213: }
214: // merge the mappings
215: Iterator servletMappings = theWebXml
216: .getServletMappings(servletName);
217: while (servletMappings.hasNext()) {
218: String urlPattern = (String) servletMappings.next();
219: webXml.addServletMapping(servletName, urlPattern);
220: }
221: count++;
222: }
223: this .log.trace("Merged " + count + " servlet definition"
224: + (count != 1 ? "s " : " ") + "into the descriptor");
225: }
226:
227: /**
228: * Merges the resource environment references from the provided descriptor
229: * into the original descriptor.
230: *
231: * @param theWebXml The descriptor that contains the references that are to
232: * be merged into the original descriptor
233: */
234: protected final void mergeResourceEnvironmentReferences(
235: WebXml theWebXml) {
236: int count = insertElements(theWebXml,
237: WebXmlTag.RESOURCE_ENV_REF);
238: if (count > 0) {
239: this .log.trace("Merged " + count + " resource environment "
240: + "reference" + (count != 1 ? "s " : " ")
241: + "into the " + "descriptor");
242: }
243: }
244:
245: /**
246: * Merges the resource references from the provided descriptor into the
247: * original descriptor.
248: *
249: * @param theWebXml The descriptor that contains the resource refs that
250: * are to be merged into the original descriptor
251: */
252: protected final void mergeResourceReferences(WebXml theWebXml) {
253: int count = insertElements(theWebXml, WebXmlTag.RESOURCE_REF);
254: if (count > 0) {
255: this .log
256: .trace("Merged " + count + " resource reference"
257: + (count != 1 ? "s " : " ")
258: + "into the descriptor");
259: }
260: }
261:
262: /**
263: * Merges the
264: *
265: * @param theWebXml The descriptor that contains the security constraints
266: * that are to be merged into the original descriptor
267: */
268: protected final void mergeSecurityConstraints(WebXml theWebXml) {
269: int count = insertElements(theWebXml,
270: WebXmlTag.SECURITY_CONSTRAINT);
271: if (count > 0) {
272: this .log
273: .trace("Merged " + count + " security constraint"
274: + (count != 1 ? "s " : " ")
275: + "into the descriptor");
276: }
277: }
278:
279: /**
280: * Merges the login configuration from the provided descriptor into the
281: * original descriptor, thereby eventually replacing the existing login
282: * config.
283: *
284: * @param theWebXml The descriptor that contains the login config that
285: * is to be merged into the original descriptor
286: */
287: protected final void mergeLoginConfig(WebXml theWebXml) {
288: boolean replaced = replaceElement(theWebXml,
289: WebXmlTag.LOGIN_CONFIG);
290: if (replaced) {
291: this .log
292: .trace("Merged the login configuration into the descriptor");
293: }
294: }
295:
296: /**
297: * Merges the security roles from the provided descriptor into the original
298: * descriptor.
299: *
300: * @param theWebXml The descriptor that contains the security roles that
301: * are to be merged into the original descriptor
302: */
303: protected final void mergeSecurityRoles(WebXml theWebXml) {
304: Iterator securityRoleNames = theWebXml.getSecurityRoleNames();
305: int count = 0;
306: while (securityRoleNames.hasNext()) {
307: String securityRoleName = (String) securityRoleNames.next();
308: if (!this .webXml.hasSecurityRole(securityRoleName)) {
309: this .webXml.addSecurityRole(securityRoleName);
310: }
311: }
312: if (count > 0) {
313: this .log
314: .trace("Merged " + count + " security role"
315: + (count != 1 ? "s " : " ")
316: + "into the descriptor");
317: }
318: }
319:
320: /**
321: * Merges the environment entries from the provided descriptor into the
322: * original descriptor.
323: *
324: * @param theWebXml The descriptor that contains the environment entries
325: * that are to be merged into the original descriptor
326: */
327: protected final void mergeEnvironmentEntries(WebXml theWebXml) {
328: int count = insertElements(theWebXml, WebXmlTag.ENV_ENTRY);
329: if (count > 0) {
330: this .log.trace("Merged " + count + " environment entr"
331: + (count != 1 ? "ies " : "y ")
332: + "into the descriptor");
333: }
334: }
335:
336: /**
337: * Merges the EJB references from the provided descriptor into the original
338: * descriptor.
339: *
340: * @param theWebXml The descriptor that contains the EJB refs that are to be
341: * merged into the original descriptor
342: */
343: protected final void mergeEjbRefs(WebXml theWebXml) {
344: int count = insertElements(theWebXml, WebXmlTag.EJB_REF);
345: if (count > 0) {
346: this .log.trace("Merged " + count + " EJB reference"
347: + (count != 1 ? "s " : "y ")
348: + "into the descriptor");
349: }
350: }
351:
352: /**
353: * Merges the EJB local references from the provided descriptor into the
354: * original descriptor.
355: *
356: * @param theWebXml The descriptor that contains the EJB local refs that are
357: * to be merged into the original descriptor
358: */
359: protected final void mergeEjbLocalRefs(WebXml theWebXml) {
360: int count = insertElements(theWebXml, WebXmlTag.EJB_LOCAL_REF);
361: if (count > 0) {
362: this .log.trace("Merged " + count + " EJB local reference"
363: + (count != 1 ? "s " : "y ")
364: + "into the descriptor");
365: }
366: }
367:
368: // Private Methods ---------------------------------------------------------
369:
370: /**
371: * Insert all elements of the specified tag from the given descriptor into
372: * the original descriptor, and returns the number of elements that were
373: * added.
374: *
375: * @param theWebXml The descriptor that contains the elements that are to be
376: * merged into the original descriptor
377: * @param theTag Defines which elements will get merged
378: * @return The number of elements inserted into the original descriptor
379: */
380: private int insertElements(WebXml theWebXml, WebXmlTag theTag) {
381: Iterator elements = theWebXml.getElements(theTag);
382: int count = 0;
383: while (elements.hasNext()) {
384: Element element = (Element) elements.next();
385: webXml.addElement(theTag, element);
386: count++;
387: }
388: return count;
389: }
390:
391: /**
392: * Replaces the element of the specified tag in the original descriptor with
393: * the equivalent element in the specified descriptor.
394: *
395: * @param theWebXml The descriptor that contains the element that is to be
396: * added to the original descriptor, replacing the original
397: * definition
398: * @param theTag Defines which element will get replaced
399: * @return Whether the element was replaced
400: */
401: private boolean replaceElement(WebXml theWebXml, WebXmlTag theTag) {
402: Iterator elements = theWebXml.getElements(theTag);
403: if (elements.hasNext()) {
404: webXml.replaceElement(theTag, (Element) elements.next());
405: return true;
406: }
407: return false;
408: }
409:
410: }
|