001    /**
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  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,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License.
018     */
019    
020    package org.apache.geronimo.mavenplugins.car;
021    
022    import java.io.File;
023    import java.net.URI;
024    import java.util.ArrayList;
025    import java.util.Arrays;
026    import java.util.HashMap;
027    import java.util.HashSet;
028    import java.util.Iterator;
029    import java.util.List;
030    import java.util.Set;
031    
032    import org.apache.geronimo.deployment.PluginBootstrap2;
033    import org.apache.geronimo.gbean.AbstractName;
034    import org.apache.geronimo.gbean.AbstractNameQuery;
035    import org.apache.geronimo.gbean.GBeanData;
036    import org.apache.geronimo.gbean.GBeanInfo;
037    import org.apache.geronimo.gbean.ReferencePatterns;
038    import org.apache.geronimo.kernel.Kernel;
039    import org.apache.geronimo.kernel.KernelFactory;
040    import org.apache.geronimo.kernel.KernelRegistry;
041    import org.apache.geronimo.kernel.Naming;
042    import org.apache.geronimo.kernel.config.ConfigurationData;
043    import org.apache.geronimo.kernel.config.ConfigurationManager;
044    import org.apache.geronimo.kernel.config.ConfigurationUtil;
045    import org.apache.geronimo.kernel.config.KernelConfigurationManager;
046    import org.apache.geronimo.kernel.config.LifecycleException;
047    import org.apache.geronimo.kernel.config.RecordingLifecycleMonitor;
048    import org.apache.geronimo.kernel.log.GeronimoLogging;
049    import org.apache.geronimo.kernel.management.State;
050    import org.apache.geronimo.kernel.repository.DefaultArtifactManager;
051    import org.apache.geronimo.system.configuration.RepositoryConfigurationStore;
052    import org.apache.geronimo.system.repository.Maven2Repository;
053    import org.apache.geronimo.system.resolver.ExplicitDefaultArtifactResolver;
054    import org.apache.maven.archiver.MavenArchiveConfiguration;
055    import org.apache.maven.archiver.MavenArchiver;
056    import org.apache.maven.artifact.Artifact;
057    import org.apache.maven.artifact.factory.ArtifactFactory;
058    import org.apache.maven.plugin.MojoExecutionException;
059    import org.apache.maven.project.MavenProject;
060    import org.codehaus.mojo.pluginsupport.dependency.DependencyTree;
061    import org.codehaus.mojo.pluginsupport.util.ArtifactItem;
062    import org.codehaus.plexus.archiver.jar.JarArchiver;
063    import org.codehaus.plexus.util.FileUtils;
064    
065    /**
066     * Jar up a packaged plugin
067     *
068     * @goal archive-car
069     * @requiresDependencyResolution runtime
070     *
071     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
072     */
073    public class ArchiveCarMojo
074        extends AbstractCarMojo
075    {
076    
077        /**
078         * The maven archive configuration to use.
079         *
080         * See <a href="http://maven.apache.org/ref/current/maven-archiver/apidocs/org/apache/maven/archiver/MavenArchiveConfiguration.html">the Javadocs for MavenArchiveConfiguration</a>.
081         *
082         * @parameter
083         */
084        private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
085    
086        /**
087         * The Jar archiver.
088         *
089         * @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
090         * @required
091         * @readonly
092         */
093        private JarArchiver jarArchiver = null;
094    
095        /**
096         * The module base directory.
097         *
098         * @parameter expression="${project.basedir}"
099         * @required
100         * @readonly
101         */
102        private File baseDirectory = null;
103    
104        /**
105         * Directory containing the generated archive.
106         *
107         * @parameter expression="${project.build.directory}"
108         * @required
109         */
110        private File outputDirectory = null;
111    
112        /**
113         * Directory containing the classes/resources.
114         *
115         * @parameter expression="${project.build.outputDirectory}"
116         * @required
117         */
118        private File classesDirectory = null;
119    
120        /**
121         * Name of the generated archive.
122         *
123         * @parameter expression="${project.build.finalName}"
124         * @required
125         */
126        private String finalName = null;
127    
128        /**
129         * The Geronimo repository where modules will be packaged up from.
130         *
131         * @parameter expression="${project.build.directory}/repository"
132         * @required
133         */
134        private File targetRepository = null;
135    
136        /**
137         * The location where the properties mapping will be generated.
138         *
139         * <p>
140         * Probably don't want to change this.
141         * </p>
142         *
143         * @parameter expression="${project.build.directory}/explicit-versions.properties"
144         */
145        private File explicitResolutionProperties = null;
146    
147        /**
148         * An array of {@link org.apache.geronimo.mavenplugins.car.ClasspathElement} objects which will be used to construct the
149         * Class-Path entry of the manifest.
150         *
151         * This is needed to allow per-element prefixes to be added, which the standard Maven archiver
152         * does not provide.
153         *
154         * @parameter
155         */
156        private ClasspathElement[] classpath = null;
157    
158        /**
159         * The default prefix to be applied to all elements of the <tt>classpath</tt> which
160         * do not provide a prefix.
161         *
162         * @parameter
163         */
164        private String classpathPrefix = null;
165    
166        /**
167         * Location of resources directory for additional content to include in the car.
168         *
169         * @parameter expression="${project.build.directory}/resources"
170         */
171        private File resourcesDir;
172    
173        //
174        // Mojo
175        //
176    
177        protected void doExecute() throws Exception {
178    
179            // Build the archive
180            File archive = createArchive();
181    
182            // Attach the generated archive for install/deploy
183            project.getArtifact().setFile(archive);
184        }
185    
186        private File getArtifactInRepositoryDir() {
187            //
188            // HACK: Generate the filename in the repo... really should delegate this to the repo impl
189            //
190    
191            File dir = new File(targetRepository, project.getGroupId().replace('.', '/'));
192            dir = new File(dir, project.getArtifactId());
193            dir = new File(dir, project.getVersion());
194            dir = new File(dir, project.getArtifactId() + "-" + project.getVersion() + ".car");
195    
196            return dir;
197        }
198    
199    
200        /**
201         * Generates the configuration archive.
202         */
203        private File createArchive() throws MojoExecutionException {
204            File archiveFile = getArchiveFile(outputDirectory, finalName, null);
205    
206            MavenArchiver archiver = new MavenArchiver();
207            archiver.setArchiver(jarArchiver);
208            archiver.setOutputFile(archiveFile);
209    
210            try {
211                // Incldue the generated artifact contents
212                archiver.getArchiver().addDirectory(getArtifactInRepositoryDir());
213    
214                // Include the optional classes.resources
215                if (classesDirectory.isDirectory()) {
216                    archiver.getArchiver().addDirectory(classesDirectory);
217                }
218    
219                if (resourcesDir.isDirectory()) {
220                    archiver.getArchiver().addDirectory(resourcesDir);
221                }
222    
223                //
224                // HACK: Include legal files here for sanity
225                //
226    
227                //
228                // NOTE: Would be nice to share this with the copy-legal-files mojo
229                //
230                String[] includes = {
231                    "LICENSE.txt",
232                    "LICENSE",
233                    "NOTICE.txt",
234                    "NOTICE",
235                    "DISCLAIMER.txt",
236                    "DISCLAIMER"
237                };
238    
239                archiver.getArchiver().addDirectory(baseDirectory, "META-INF/", includes, new String[0]);
240    
241                if (classpath != null) {
242                    archive.addManifestEntry("Class-Path", getClassPath());
243                }
244    
245                archiver.createArchive(project, archive);
246    
247                return archiveFile;
248            }
249            catch (Exception e) {
250                throw new MojoExecutionException("Failed to create archive", e);
251            }
252        }
253    
254        private String getClassPath() throws MojoExecutionException {
255            StringBuffer buff = new StringBuffer();
256    
257            for (int i=0; i < classpath.length; i++) {
258                String entry = classpath[i].getEntry();
259                if (entry != null) {
260                    buff.append(entry);
261                } else {
262                    Artifact artifact = getArtifact(classpath[i]);
263    
264                    //
265                    // TODO: Need to optionally get all transitive dependencies... but dunno how to get that intel from m2
266                    //
267    
268                    String prefix = classpath[i].getClasspathPrefix();
269                    if (prefix == null) {
270                        prefix = classpathPrefix;
271                    }
272    
273                    if (prefix != null) {
274                        buff.append(prefix);
275    
276                        if (!prefix.endsWith("/")) {
277                            buff.append("/");
278                        }
279                    }
280    
281                    File file = artifact.getFile();
282                    buff.append(file.getName());
283                }
284    
285                if (i + 1< classpath.length) {
286                    buff.append(" ");
287                }
288            }
289    
290            log.debug("Using classpath: " + buff);
291    
292            return buff.toString();
293        }
294    
295    }