View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  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,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.maven.plugin;
21  
22  import org.apache.maven.artifact.DependencyResolutionRequiredException;
23  import org.apache.maven.plugin.MojoExecutionException;
24  import org.codehaus.plexus.archiver.ArchiverException;
25  import org.codehaus.plexus.archiver.UnArchiver;
26  import org.codehaus.plexus.archiver.manager.ArchiverManager;
27  import org.codehaus.plexus.archiver.manager.NoSuchArchiverException;
28  import org.codehaus.plexus.archiver.zip.ZipEntry;
29  import org.codehaus.plexus.archiver.zip.ZipFile;
30  import org.codehaus.plexus.util.FileUtils;
31  import org.codehaus.plexus.util.IOUtil;
32  import org.codehaus.plexus.util.ReaderFactory;
33  import org.codehaus.plexus.util.xml.XmlStreamReader;
34  import org.codehaus.plexus.util.xml.Xpp3Dom;
35  import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
36  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
37  
38  import java.io.ByteArrayInputStream;
39  import java.io.File;
40  import java.io.IOException;
41  import java.io.StringReader;
42  import java.io.StringWriter;
43  import java.util.Enumeration;
44  import java.util.Iterator;
45  import java.util.Locale;
46  import java.util.Properties;
47  
48  /**
49   * @goal resources
50   * @phase process-resources
51   * @requiresDependencyResolution runtime
52   */
53  public class UnPackThemeMojo extends AbstractThemeMojo {
54    /**
55     * To look up Archiver/UnArchiver implementations
56     *
57     * @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}"
58     * @required
59     */
60    private ArchiverManager archiverManager;
61  
62    /**
63     * Directory to unpack JARs into if needed
64     *
65     * @parameter expression="${project.build.directory}/theme/work"
66     * @required
67     */
68    private File workDirectory;
69  
70    /**
71     * The directory where the webapp is built.
72     *
73     * @parameter expression="${project.build.directory}/${project.build.finalName}"
74     * @required
75     */
76    private File webappDirectory;
77  
78    /**
79     * Don't use the versioned information of the themes..
80     *
81     * @parameter
82     */
83    private boolean ignoreVersioned;
84  
85  
86    private String getThemeDescriptor(final File jarFile) throws MojoExecutionException {
87      ZipFile zip = null;
88      try {
89        zip = new ZipFile(jarFile);
90        final Enumeration files = zip.getEntries();
91        while (files.hasMoreElements()) {
92          final ZipEntry nextEntry = (ZipEntry) files.nextElement();
93          if (nextEntry == null || nextEntry.isDirectory()) {
94            continue;
95          }
96          final String name = nextEntry.getName();
97          if (name.equals("META-INF/tobago-theme.xml") || name.equals("META-INF/tobago-config.xml")) {
98            XmlStreamReader xsr = null;
99            try {
100             final StringWriter stringWriter = new StringWriter();
101             xsr = ReaderFactory.newXmlReader(zip.getInputStream(nextEntry));
102             IOUtil.copy(xsr, stringWriter);
103             return stringWriter.toString();
104           } finally {
105             IOUtil.close(xsr);
106           }
107         }
108       }
109     } catch (final IOException e) {
110       throw new MojoExecutionException("Error find ThemeDescriptor in " + jarFile, e);
111     } finally {
112       if (zip != null) {
113         try {
114           zip.close();
115         } catch (final IOException e) {
116           // ignore
117         }
118       }
119     }
120     return null;
121   }
122 
123   public void execute() throws MojoExecutionException {
124     try {
125       final Iterator artifacts =  getProject().getRuntimeClasspathElements().iterator();
126       if (!workDirectory.exists()) {
127         workDirectory.mkdirs();
128       }
129       while (artifacts.hasNext()) {
130 
131         final String artifact = (String) artifacts.next();
132         if (getLog().isDebugEnabled()) {
133           getLog().debug("Testing jar "+ artifact);
134         }
135 
136         final File file = new File(artifact);
137         if (file.isFile() && artifact.endsWith(".jar")) {
138           final String descriptor = getThemeDescriptor(file);
139           if (descriptor != null) {
140 
141             final String name = file.getName();
142             final File tempLocation = new File(workDirectory, name.substring(0, name.length() - 4));
143             boolean process = false;
144             if (!tempLocation.exists()) {
145               tempLocation.mkdirs();
146               process = true;
147             } else if (file.lastModified() > tempLocation.lastModified()) {
148               process = true;
149             }
150             if (process) {
151               try {
152                 unpack(file, tempLocation);
153                 String version = null;
154                 String resourcePath = null;
155                 try {
156                   final Xpp3Dom xpp3Dom = Xpp3DomBuilder.build(new StringReader(descriptor));
157                   final Xpp3Dom themeDefinitions = xpp3Dom.getChild("theme-definitions");
158                   if (themeDefinitions != null && !ignoreVersioned) {
159                     for (final Xpp3Dom themeDefinition : themeDefinitions.getChildren()) {
160                       final Xpp3Dom versionedDom = themeDefinition.getChild("versioned");
161                       if (versionedDom != null) {
162                         final boolean versioned = Boolean.parseBoolean(versionedDom.getValue());
163                         if (versioned) {
164                           final Xpp3Dom resourcePathDom = themeDefinition.getChild("resource-path");
165                           resourcePath = resourcePathDom.getValue();
166                           final Properties properties = new Properties();
167                           final String metaInf = tempLocation + "/META-INF/MANIFEST.MF";
168                           properties.load(new ByteArrayInputStream(FileUtils.fileRead(metaInf).getBytes()));
169                           version = properties.getProperty("Implementation-Version");
170                           if (version == null) {
171                             getLog().error("No Implementation-Version found in Manifest-File for theme: '"
172                                 + name + "'.");
173                           }
174                         }
175                       }
176                     }
177                   }
178                 } catch (final IOException e) {
179                   getLog().error(e);
180                 } catch (final XmlPullParserException e) {
181                   getLog().error(e);
182                 }
183                 if (getLog().isDebugEnabled()) {
184                   getLog().debug("Expanding theme: "+ name);
185                   getLog().debug("Version: " + version);
186                   getLog().debug("ResourcePath: " + resourcePath);
187                 }
188                 final String[] fileNames = getThemeFiles(tempLocation);
189                 for (final String fileName : fileNames) {
190                   final File fromFile = new File(tempLocation, fileName);
191                   String toFileName = fileName;
192                   if (resourcePath != null && version != null && toFileName.startsWith(resourcePath)
193                       && !fileName.endsWith("blank.html")) {
194                     toFileName = resourcePath + "/" + version + "/" + toFileName.substring(resourcePath.length() + 1);
195                   }
196                   if (getLog().isDebugEnabled()) {
197                     getLog().debug("Copy file " + fromFile + " to: " + toFileName);
198                   }
199                   final File toFile = new File(webappDirectory, toFileName);
200                   try {
201                     FileUtils.copyFile(fromFile, toFile);
202                   } catch (final IOException e) {
203                     throw new MojoExecutionException("Error copy file: " + fromFile + " to: " + toFile, e);
204                   }
205                 }
206               } catch (final NoSuchArchiverException e) {
207                 getLog().info("Skip unpacking dependency file with unknown extension: " + file.getPath());
208               }
209             }
210           }
211         }
212       }
213     } catch (final DependencyResolutionRequiredException drre) {
214       throw new MojoExecutionException(drre.getMessage(), drre);
215     }
216   }
217 
218   private void unpack(final File file, final File location)
219       throws MojoExecutionException, NoSuchArchiverException {
220     final String archiveExt = FileUtils.getExtension(file.getAbsolutePath()).toLowerCase(Locale.ENGLISH);
221     try {
222       final UnArchiver unArchiver = archiverManager.getUnArchiver(archiveExt);
223       unArchiver.setSourceFile(file);
224       unArchiver.setDestDirectory(location);
225       unArchiver.extract();
226     } catch (final ArchiverException e) {
227       throw new MojoExecutionException("Error unpacking file: " + file + "to: " + location, e);
228     }
229   }
230 }
231 
232