2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

View Javadoc

1   /* 
2    * ========================================================================
3    * 
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   * 
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * 
19   * ========================================================================
20   */
21  package org.apache.cactus.eclipse.webapp.internal;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.util.Vector;
26  
27  import org.apache.cactus.eclipse.webapp.internal.ui.WebappMessages;
28  import org.apache.cactus.eclipse.webapp.internal.ui.WebappPlugin;
29  import org.apache.tools.ant.Project;
30  import org.apache.tools.ant.taskdefs.War;
31  import org.apache.tools.ant.taskdefs.Zip;
32  import org.apache.tools.ant.types.FileSet;
33  import org.apache.tools.ant.types.ZipFileSet;
34  import org.eclipse.core.resources.IFile;
35  import org.eclipse.core.resources.ResourcesPlugin;
36  import org.eclipse.core.runtime.CoreException;
37  import org.eclipse.core.runtime.IPath;
38  import org.eclipse.core.runtime.IProgressMonitor;
39  import org.eclipse.core.runtime.IStatus;
40  import org.eclipse.core.runtime.NullProgressMonitor;
41  import org.eclipse.core.runtime.Path;
42  import org.eclipse.core.runtime.Status;
43  import org.eclipse.jdt.core.IClasspathEntry;
44  import org.eclipse.jdt.core.IJavaProject;
45  import org.eclipse.jdt.core.JavaCore;
46  import org.eclipse.jdt.core.JavaModelException;
47  import org.eclipse.jdt.internal.core.JavaModel;
48  
49  /**
50   * Helper class for creating War files.
51   * 
52   * @version $Id: WarBuilder.java 238816 2004-02-29 16:36:46Z vmassol $
53   */
54  public class WarBuilder
55  {
56      /**
57       * The Java project to build the war from
58       */
59      private IJavaProject javaProject;
60  
61      /**
62       * The Webapp object that stores webapp preferences 
63       */
64      private Webapp webapp;
65  
66      /**
67       * Name of the WEB-INF directory
68       */
69      public static final String WEBINF = "WEB-INF";
70  
71      /**
72       * Name of the lib directory
73       */
74      public static final String LIB = "lib";
75  
76      /**
77       * Name of the web.xml file
78       */
79      public static final String WEBXML = "web.xml";
80  
81      /**
82       * @param theJavaProject the Java project for which the webapp will be 
83       *        created
84       * @throws JavaModelException if we can't get the output location
85       */
86      public WarBuilder(final IJavaProject theJavaProject) 
87          throws JavaModelException
88      {
89          this.javaProject = theJavaProject;
90          this.webapp = new Webapp(theJavaProject);
91      }
92  
93      /**
94       * @param theWebFilesDir webapp directory to get the web.xml from
95       * @return the web.xml file in the given webapp directory,
96       *  or null if none
97       */
98      public static File getWebXML(final File theWebFilesDir)
99      {
100         if (theWebFilesDir == null)
101         {
102             return null;
103         }
104         else
105         {
106             String userWebXMLPath =
107                 theWebFilesDir.getAbsolutePath()
108                     + File.separator
109                     + WEBINF
110                     + File.separator
111                     + WEBXML;
112             return new File(userWebXMLPath);
113         }
114     }
115     /**
116      * For each IClasspathEntry transform the path in an absolute path.
117      * @param theEntries array of IClasspathEntry to render asbolute
118      * @return an array of absolute IClasspathEntries
119      */
120     private static IClasspathEntry[] getAbsoluteEntries(
121         final IClasspathEntry[] theEntries)
122     {
123         if (theEntries == null)
124         {
125             return new IClasspathEntry[0];
126         }
127         Vector result = new Vector();
128         for (int i = 0; i < theEntries.length; i++)
129         {
130             IClasspathEntry currentEntry = theEntries[i];
131             if (currentEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
132             {
133                 IPath path = currentEntry.getPath();
134                 Object target =
135                     JavaModel.getTarget(
136                         ResourcesPlugin.getWorkspace().getRoot(),
137                         path,
138                         true);
139                 if (target instanceof IFile)
140                 {
141                     IFile file = (IFile) target;
142                     IPath absolutePath = file.getLocation();
143                     result.add(
144                         JavaCore.newLibraryEntry(absolutePath, null, null));
145                 }
146                 else
147                     if (target instanceof File)
148                     {
149                         File file = (File) target;
150                         result.add(
151                             JavaCore.newLibraryEntry(
152                                 new Path(file.getAbsolutePath()),
153                                 null,
154                                 null));
155                     }
156             }
157         }
158         return (IClasspathEntry[]) result.toArray(
159             new IClasspathEntry[result.size()]);
160     }
161 
162     /**
163      * @param theJavaProject the java project for which we want to get the
164      *        absolute output path 
165      * @return the absolute project output path
166      * @throws JavaModelException if we fail to get the project relative 
167      *         output location
168      */
169     private static File getAbsoluteOutputLocation(
170         final IJavaProject theJavaProject) throws JavaModelException
171     {
172         IPath projectPath = theJavaProject.getProject().getLocation();
173         IPath outputLocation = theJavaProject.getOutputLocation();
174         IPath classFilesPath =
175             projectPath.append(outputLocation.removeFirstSegments(1));
176         return classFilesPath.toFile();
177     }
178 
179     /**
180      * Creates the war file.
181      * @param thePM a monitor that reflects the overall progress,
182      *  or null if none is to be used.
183      * @return File the location where the war file was created
184      * @throws CoreException if we can't create the file
185      */
186     public final File createWar(final IProgressMonitor thePM) 
187         throws CoreException
188     {
189         IProgressMonitor progressMonitor = thePM;
190         if (progressMonitor == null)
191         {
192             progressMonitor = new NullProgressMonitor();
193         }
194         
195         progressMonitor.subTask(
196             WebappMessages.getString("WarBuilder.message.createwar.monitor"));
197         this.webapp.loadValues();
198         File outputWar = getOutputWar();
199         File userWebFilesDir = getUserWebFilesDir();
200         File userWebXML = getWebXML(userWebFilesDir);
201         IClasspathEntry[] jarEntries = getJarEntries();
202         File userClassFilesDir = getAbsoluteOutputLocation(this.javaProject);
203         
204         outputWar.delete();
205         War warTask = new War();
206         progressMonitor.worked(1);
207         Project antProject = new Project();
208         antProject.init();
209         warTask.setProject(antProject);
210         warTask.setDestFile(outputWar);
211         ZipFileSet classes = new ZipFileSet();
212         classes.setDir(userClassFilesDir);
213         warTask.addClasses(classes);
214         classes = new ZipFileSet();
215         classes.setDir(userClassFilesDir);
216         classes.setIncludes("log4j.properties");
217         warTask.addClasses(classes);
218         if (userWebFilesDir != null && userWebFilesDir.exists())
219         {
220             FileSet webFiles = new FileSet();
221             webFiles.setDir(userWebFilesDir);
222             webFiles.setExcludes(WEBINF);
223             warTask.addFileset(webFiles);
224         }
225         if (userWebXML != null && userWebXML.exists())
226         {
227             warTask.setWebxml(userWebXML);
228         }
229         else
230         {
231             // Without a webxml attribute the Ant war task
232             // requires the update attribute set to true
233             // That's why we actually need an existing war file.
234             try
235             {
236                 // A file is needed for war creation
237                 File voidFile = File.createTempFile("void", null);
238                 createZipFile(outputWar, voidFile);
239                 voidFile.delete();
240             }
241             catch (IOException e)
242             {
243                 throw new CoreException(
244                     new Status(
245                         IStatus.ERROR,
246                         WebappPlugin.getPluginId(),
247                         IStatus.OK,
248                         WebappMessages.getString(
249                             "WarBuilder.message.createwar.temp"),
250                         e));
251             }
252 
253             warTask.setUpdate(true);
254         }
255 
256         ZipFileSet[] jarFS = getZipFileSets(jarEntries);
257         for (int i = 0; i < jarFS.length; i++)
258         {
259             warTask.addLib(jarFS[i]);
260         }
261         warTask.execute();
262         progressMonitor.worked(2);
263         return outputWar;
264     }
265 
266     /**
267      * @param theJarEntries the jars to build ZipFileSets from
268      * @return an array of ZipFileSet corresponding to the given jars
269      */
270     private static ZipFileSet[] getZipFileSets(
271         final IClasspathEntry[] theJarEntries)
272     {
273         Vector result = new Vector();
274         for (int i = 0; i < theJarEntries.length; i++)
275         {
276 
277             IClasspathEntry currentEntry = theJarEntries[i];
278             if (currentEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY)
279             {
280                 File currentJar = currentEntry.getPath().toFile();
281                 ZipFileSet zipFS = new ZipFileSet();
282                 zipFS.setFile(currentJar);
283                 result.add(zipFS);
284             }
285         }
286         return (ZipFileSet[]) result.toArray(new ZipFileSet[result.size()]);
287     }
288 
289     /**
290      * @return the web application folder situated in the user's project
291      */
292     private File getUserWebFilesDir()
293     {
294         // path to the web directory relative to the user's project
295         String userWebFilesPath = this.webapp.getDir();
296         if (userWebFilesPath == null || userWebFilesPath.equals(""))
297         {
298             return null;
299         }
300         else
301         {
302             IPath projectPath = this.javaProject.getProject().getLocation();
303 
304             // web application folder situated in the user's project
305             return projectPath.append(userWebFilesPath).toFile();
306         }
307     }
308 
309     /**
310      * @return the jar entries
311      */
312     private IClasspathEntry[] getJarEntries()
313     {
314         return getAbsoluteEntries(this.webapp.getClasspath());
315     }
316 
317     /**
318      * @return the output war file
319      */
320     private File getOutputWar()
321     {
322         return new File(this.webapp.getOutput());
323     }
324 
325     /**
326      * Removes the specified file or directory, and all subdirectories
327      * @param theFile the file or directory to delete
328      */
329     public static final void delete(final File theFile)
330     {
331         if (theFile.isDirectory())
332         {
333             File[] dir = theFile.listFiles();
334             for (int i = 0; i < dir.length; i++)
335             {
336                 delete(dir[i]);
337             }
338             theFile.delete();
339         }
340         else
341             if (theFile.exists())
342             {
343                 theFile.delete();
344             }
345     }
346 
347     /**
348      * Creates a zip file containing the given existing file. 
349      * @param theZipFile the zip file to create
350      * @param theExistingFile the file to include in the zip
351      */
352     private void createZipFile(final File theZipFile, 
353         final File theExistingFile)
354     {
355         Project antProject = new Project();
356         antProject.init();
357         Zip zip = new Zip();
358         zip.setProject(antProject);
359         zip.setDestFile(theZipFile);
360         FileSet existingFileSet = new FileSet();
361         existingFileSet.setFile(theExistingFile);
362         zip.addFileset(existingFileSet);
363         zip.execute();
364     }
365 
366 }