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.geronimo.server;
021    
022    import java.io.File;
023    import java.io.IOException;
024    import java.util.Map;
025    import java.util.HashMap;
026    import java.util.Enumeration;
027    import java.util.zip.ZipFile;
028    import java.util.zip.ZipEntry;
029    
030    import org.apache.maven.artifact.Artifact;
031    
032    import org.apache.maven.plugin.MojoExecutionException;
033    import org.apache.maven.plugin.MojoFailureException;
034    
035    import org.codehaus.plexus.util.FileUtils;
036    
037    import org.apache.tools.ant.taskdefs.Expand;
038    import org.apache.tools.ant.taskdefs.Chmod;
039    
040    import org.apache.geronimo.mavenplugins.geronimo.AssemblyConfig;
041    import org.apache.geronimo.mavenplugins.geronimo.reporting.ReportingMojoSupport;
042    
043    /**
044     * Common assembly install support.
045     *
046     * @version $Rev: 450613 $ $Date: 2006-09-27 15:45:46 -0700 (Wed, 27 Sep 2006) $
047     */
048    public abstract class InstallerMojoSupport
049        extends ReportingMojoSupport
050    {
051        /**
052         * Enable forced install refresh.
053         *
054         * @parameter expression="${refresh}" default-value="false"
055         */
056        protected boolean refresh = false;
057    
058        /**
059         * List of assembly artifact configurations.  Artifacts need to point to ZIP archives.
060         *
061         * @parameter
062         */
063        protected AssemblyConfig[] assemblies = null;
064    
065        /**
066         * Identifer of the assembly configuration to use.
067         *
068         * @parameter expression="${assemblyId}"
069         */
070        protected String assemblyId = null;
071    
072        /**
073         * The default assemblyId to use when no assemblyId configured.
074         *
075         * @parameter
076         */
077        protected String defaultAssemblyId = null;
078    
079        /**
080         * A file which points to a specific assembly ZIP archive.
081         * If this parameter is set, then it will be used instead of from the
082         * assemblies configuration.
083         *
084         * @parameter expression="${assemblyArchive}"
085         */
086        protected File assemblyArchive = null;
087    
088        /**
089         * Directory to install the assembly into.
090         *
091         * @parameter expression="${installDirectory}" default-value="${project.build.directory}"
092         * @required
093         */
094        protected File installDirectory = null;
095    
096        /**
097         * The directory where the assembly has been installed to.
098         *
099         * Normally this value is detected,
100         * but if it is set, then it is assumed to be the location where a pre-installed assembly exists
101         * and no installation will be done.
102         *
103         * @parameter expression="${geronimoHome}"
104         */
105        protected File geronimoHome;
106    
107        protected static final int INSTALL_FROM_ARTIFACT = 0;
108    
109        protected static final int INSTALL_FROM_FILE = 1;
110    
111        protected static final int INSTALL_ALREADY_EXISTS = 2;
112    
113        protected int installType;
114    
115        private File discoverGeronimoHome(final File archive) throws MojoExecutionException {
116            log.debug("Attempting to discover geronimoHome...");
117    
118            File dir = null;
119    
120            try {
121                ZipFile zipFile = new ZipFile(archive);
122    
123                Enumeration enum = zipFile.entries();
124                while (enum.hasMoreElements()) {
125                    ZipEntry entry = (ZipEntry)enum.nextElement();
126                    if (entry.getName().endsWith("bin/server.jar")) {
127                        File file = new File(installDirectory, entry.getName());
128                        dir = file.getParentFile().getParentFile();
129                        break;
130                    }
131                }
132    
133                zipFile.close();
134            }
135            catch (IOException e) {
136                throw new MojoExecutionException("Failed to determine geronimoHome while scanning archive for 'bin/server.jar'", e);
137            }
138    
139            if (dir == null) {
140                throw new MojoExecutionException("Archive does not contain a Geronimo assembly: " + archive);
141            }
142    
143            return dir;
144        }
145    
146        protected void init() throws MojoExecutionException, MojoFailureException {
147            super.init();
148    
149            // First check if geronimoHome is set, if it is, then we can skip this
150            if (geronimoHome != null) {
151                // Quick sanity check
152                File file = new File(geronimoHome, "bin/server.jar");
153                if (!file.exists()) {
154                    throw new MojoExecutionException("When geronimoHome is set, it must point to a directory that contains 'bin/server.jar'");
155                }
156                log.info("Using pre-installed assembly: " + geronimoHome);
157    
158                installType = INSTALL_ALREADY_EXISTS;
159            }
160            else {
161                if (assemblyArchive != null) {
162                    log.info("Using non-artifact based assembly archive: " + assemblyArchive);
163    
164                    installType = INSTALL_FROM_FILE;
165                }
166                else {
167                    Artifact artifact = getAssemblyArtifact();
168    
169                    if (!"zip".equals(artifact.getType())) {
170                        throw new MojoExecutionException("Assembly file does not look like a ZIP archive");
171                    }
172    
173                    log.info("Using assembly artifact: " + artifact);
174    
175                    assemblyArchive = artifact.getFile();
176    
177                    installType = INSTALL_FROM_ARTIFACT;
178                }
179    
180                geronimoHome = discoverGeronimoHome(assemblyArchive);
181                log.info("Using geronimoHome: " + geronimoHome);
182            }
183        }
184    
185        /**
186         * Selects the assembly artifact tp be used for installation.
187         *
188         * @return The assembly artifact selected to be installed.
189         *
190         * @throws MojoExecutionException   Failed to select assembly artifact
191         */
192        protected Artifact getAssemblyArtifact() throws MojoExecutionException {
193            AssemblyConfig config;
194    
195            if (assemblies == null || assemblies.length == 0) {
196                throw new MojoExecutionException("At least one assembly configuration must be specified");
197            }
198            else if (assemblies.length > 1 && assemblyId == null && defaultAssemblyId == null) {
199                throw new MojoExecutionException("Must specify assemblyId (or defaultAssemblyId) when more than on assembly configuration is given");
200            }
201            else if (assemblies.length == 1) {
202                config = assemblies[0];
203            }
204            else {
205                if (assemblyId == null) {
206                    assemblyId = defaultAssemblyId;
207                }
208    
209                log.debug("Searching for assembly config for id: " + assemblyId);
210    
211                // Make sure there are no duplicate ids
212                Map idMap = new HashMap();
213    
214                for (int i=0; i < assemblies.length; i++) {
215                    String id = assemblies[i].getId();
216    
217                    if (id == null) {
218                        throw new MojoExecutionException("Missing id for assembly configuration: " + assemblies[i]);
219                    }
220    
221                    if (idMap.containsKey(id)) {
222                        throw new MojoExecutionException("Duplicate assembly id: " + id);
223                    }
224    
225                    idMap.put(id, assemblies[i]);
226                }
227    
228                config = (AssemblyConfig) idMap.get(assemblyId);
229                if (config == null) {
230                    throw new MojoExecutionException("Missing assembly configuration for id: " + assemblyId);
231                }
232            }
233    
234            log.info("Using assembly configuration: " + config.getId());
235            Artifact artifact = getArtifact(config);
236    
237            if (artifact.getFile() == null) {
238                throw new MojoExecutionException("Assembly artifact does not have an attached file: " + artifact);
239            }
240    
241            return artifact;
242        }
243    
244        /**
245         * Performs assembly installation unless the install type is pre-existing.
246         *
247         * @throws Exception
248         */
249        protected void installAssembly() throws Exception {
250            if (installType == INSTALL_ALREADY_EXISTS) {
251                log.info("Installation type is pre-existing; skipping installation");
252                return;
253            }
254    
255            // Check if there is a newer archive or missing marker to trigger assembly install
256            File installMarker = new File(geronimoHome, ".installed");
257    
258            if (!refresh) {
259                if (!installMarker.exists()) {
260                    refresh = true;
261                }
262                else if (assemblyArchive.lastModified() > installMarker.lastModified()) {
263                    log.debug("Detected new assembly archive");
264                    refresh = true;
265                }
266            }
267            else {
268                log.debug("User requested installation refresh");
269            }
270    
271            if (refresh) {
272                if (geronimoHome.exists()) {
273                    log.info("Uninstalling: " + geronimoHome);
274                    FileUtils.forceDelete(geronimoHome);
275                }
276            }
277    
278            // Install the assembly
279            if (!installMarker.exists()) {
280                log.info("Installing assembly...");
281    
282                FileUtils.forceMkdir(geronimoHome);
283                
284                Expand unzip = (Expand)createTask("unzip");
285                unzip.setSrc(assemblyArchive);
286                unzip.setDest(installDirectory);
287                unzip.execute();
288    
289                // Make scripts executable, since Java unzip ignores perms
290                Chmod chmod = (Chmod)createTask("chmod");
291                chmod.setPerm("ugo+rx");
292                chmod.setDir(geronimoHome);
293                chmod.setIncludes("bin/*.sh");
294                chmod.execute();
295    
296                installMarker.createNewFile();
297            }
298            else {
299                log.info("Re-using previously installed assembly");
300            }
301        }
302    }