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: */
018:
019: package org.apache.tools.ant.taskdefs;
020:
021: import java.io.File;
022: import java.io.IOException;
023: import java.util.Locale;
024: import org.apache.tools.ant.BuildException;
025: import org.apache.tools.ant.Project;
026: import org.apache.tools.ant.types.ZipFileSet;
027: import org.apache.tools.ant.util.FileUtils;
028: import org.apache.tools.zip.ZipOutputStream;
029:
030: /**
031: * An extension of <jar> to create a WAR archive.
032: * Contains special treatment for files that should end up in the
033: * <code>WEB-INF/lib</code>, <code>WEB-INF/classes</code> or
034: * <code>WEB-INF</code> directories of the Web Application Archive.</p>
035: * <p>(The War task is a shortcut for specifying the particular layout of a WAR file.
036: * The same thing can be accomplished by using the <i>prefix</i> and <i>fullpath</i>
037: * attributes of zipfilesets in a Zip or Jar task.)</p>
038: * <p>The extended zipfileset element from the zip task
039: * (with attributes <i>prefix</i>, <i>fullpath</i>, and <i>src</i>)
040: * is available in the War task.</p>
041: *
042: * @since Ant 1.2
043: *
044: * @ant.task category="packaging"
045: * @see Jar
046: */
047: public class War extends Jar {
048:
049: /**
050: * our web.xml deployment descriptor
051: */
052: private File deploymentDescriptor;
053:
054: /**
055: * flag set if the descriptor is added
056: */
057: private boolean needxmlfile = true;
058: private File addedWebXmlFile;
059:
060: private static final FileUtils FILE_UTILS = FileUtils
061: .getFileUtils();
062: /** path to web.xml file */
063: private static final String XML_DESCRIPTOR_PATH = "WEB-INF/web.xml";
064: /** lower case version for comparisons */
065: private static final String XML_DESCRIPTOR_PATH_LC = XML_DESCRIPTOR_PATH
066: .toLowerCase(Locale.ENGLISH);
067:
068: /** Constructor for the War Task. */
069: public War() {
070: super ();
071: archiveType = "war";
072: emptyBehavior = "create";
073: }
074:
075: /**
076: * <i>Deprecated<i> name of the file to create
077: * -use <tt>destfile</tt> instead.
078: * @param warFile the destination file
079: * @deprecated since 1.5.x.
080: * Use setDestFile(File) instead
081: * @ant.attribute ignore="true"
082: */
083: public void setWarfile(File warFile) {
084: setDestFile(warFile);
085: }
086:
087: /**
088: * set the deployment descriptor to use (WEB-INF/web.xml);
089: * required unless <tt>update=true</tt>
090: * @param descr the deployment descriptor file
091: */
092: public void setWebxml(File descr) {
093: deploymentDescriptor = descr;
094: if (!deploymentDescriptor.exists()) {
095: throw new BuildException("Deployment descriptor: "
096: + deploymentDescriptor + " does not exist.");
097: }
098:
099: // Create a ZipFileSet for this file, and pass it up.
100: ZipFileSet fs = new ZipFileSet();
101: fs.setFile(deploymentDescriptor);
102: fs.setFullpath(XML_DESCRIPTOR_PATH);
103: super .addFileset(fs);
104: }
105:
106: /**
107: * Set the policy on the web.xml file, that is, whether or not it is needed
108: * @param needxmlfile whether a web.xml file is needed. Default: true
109: */
110: public void setNeedxmlfile(boolean needxmlfile) {
111: this .needxmlfile = needxmlfile;
112: }
113:
114: /**
115: * add files under WEB-INF/lib/
116: * @param fs the zip file set to add
117: */
118:
119: public void addLib(ZipFileSet fs) {
120: // We just set the prefix for this fileset, and pass it up.
121: fs.setPrefix("WEB-INF/lib/");
122: super .addFileset(fs);
123: }
124:
125: /**
126: * add files under WEB-INF/classes
127: * @param fs the zip file set to add
128: */
129: public void addClasses(ZipFileSet fs) {
130: // We just set the prefix for this fileset, and pass it up.
131: fs.setPrefix("WEB-INF/classes/");
132: super .addFileset(fs);
133: }
134:
135: /**
136: * files to add under WEB-INF;
137: * @param fs the zip file set to add
138: */
139: public void addWebinf(ZipFileSet fs) {
140: // We just set the prefix for this fileset, and pass it up.
141: fs.setPrefix("WEB-INF/");
142: super .addFileset(fs);
143: }
144:
145: /**
146: * override of parent; validates configuration
147: * before initializing the output stream.
148: * @param zOut the zip output stream
149: * @throws IOException on output error
150: * @throws BuildException if invalid configuration
151: */
152: protected void initZipOutputStream(ZipOutputStream zOut)
153: throws IOException, BuildException {
154: super .initZipOutputStream(zOut);
155: }
156:
157: /**
158: * Overridden from Zip class to deal with web.xml
159: *
160: * Here are cases that can arise
161: * -not a web.xml file : add
162: * -first web.xml : add, remember we added it
163: * -same web.xml again: skip
164: * -alternate web.xml : warn and skip
165: *
166: * @param file the file to add to the archive
167: * @param zOut the stream to write to
168: * @param vPath the name this entry shall have in the archive
169: * @param mode the Unix permissions to set.
170: * @throws IOException on output error
171: */
172: protected void zipFile(File file, ZipOutputStream zOut,
173: String vPath, int mode) throws IOException {
174: // If the file being added is WEB-INF/web.xml, we warn if it's
175: // not the one specified in the "webxml" attribute - or if
176: // it's being added twice, meaning the same file is specified
177: // by the "webxml" attribute and in a <fileset> element.
178: String vPathLowerCase = vPath.toLowerCase(Locale.ENGLISH);
179: //by default, we add the file.
180: boolean addFile = true;
181: if (XML_DESCRIPTOR_PATH_LC.equals(vPathLowerCase)) {
182: //a web.xml file was found. See if it is a duplicate or not
183: if (addedWebXmlFile != null) {
184: //a second web.xml file, so skip it
185: addFile = false;
186: //check to see if we warn or not
187: if (!FILE_UTILS.fileNameEquals(addedWebXmlFile, file)) {
188: log("Warning: selected " + archiveType
189: + " files include a second "
190: + XML_DESCRIPTOR_PATH
191: + " which will be ignored.\n"
192: + "The duplicate entry is at " + file
193: + '\n' + "The file that will be used is "
194: + addedWebXmlFile, Project.MSG_WARN);
195: }
196: } else {
197: //no added file, yet
198: addedWebXmlFile = file;
199: //there is no web.xml file, so add it
200: addFile = true;
201: //and remember that we did
202: deploymentDescriptor = file;
203: }
204: }
205: if (addFile) {
206: super .zipFile(file, zOut, vPath, mode);
207: }
208: }
209:
210: /**
211: * Make sure we don't think we already have a web.xml next time this task
212: * gets executed.
213: */
214: protected void cleanUp() {
215: if (addedWebXmlFile == null && deploymentDescriptor == null
216: && needxmlfile && !isInUpdateMode()) {
217: throw new BuildException(
218: "No WEB-INF/web.xml file was added.\n"
219: + "If this is your intent, set needxml='false' ");
220: }
221: addedWebXmlFile = null;
222: super.cleanUp();
223: }
224: }
|