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: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
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 enum InstallType {
108 FROM_ARTIFACT,
109 FROM_FILE,
110 ALREADY_EXISTS
111 }
112
113 protected InstallType installType;
114
115 private File discoverGeronimoHome(final File archive) throws IOException, 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 n = zipFile.entries();
124 while (n.hasMoreElements()) {
125 ZipEntry entry = (ZipEntry)n.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.getCanonicalFile();
144 }
145
146 protected void init() throws MojoExecutionException, MojoFailureException {
147 super.init();
148
149 try {
150 // First check if geronimoHome is set, if it is, then we can skip this
151 if (geronimoHome != null) {
152 geronimoHome = geronimoHome.getCanonicalFile();
153
154 // Quick sanity check
155 File file = new File(geronimoHome, "bin/server.jar");
156 if (!file.exists()) {
157 throw new MojoExecutionException("When geronimoHome is set, it must point to a directory that contains 'bin/server.jar'");
158 }
159 log.info("Using pre-installed assembly: " + geronimoHome);
160
161 installType = InstallType.ALREADY_EXISTS;
162 }
163 else {
164 if (assemblyArchive != null) {
165 assemblyArchive = assemblyArchive.getCanonicalFile();
166
167 log.info("Using non-artifact based assembly archive: " + assemblyArchive);
168
169 installType = InstallType.FROM_FILE;
170 }
171 else {
172 Artifact artifact = getAssemblyArtifact();
173
174 if (!"zip".equals(artifact.getType())) {
175 throw new MojoExecutionException("Assembly file does not look like a ZIP archive");
176 }
177
178 log.info("Using assembly artifact: " + artifact);
179
180 assemblyArchive = artifact.getFile();
181
182 installType = InstallType.FROM_ARTIFACT;
183 }
184
185 geronimoHome = discoverGeronimoHome(assemblyArchive);
186 log.info("Using geronimoHome: " + geronimoHome);
187 }
188 }
189 catch (java.io.IOException e) {
190 throw new MojoExecutionException(e.getMessage(), e);
191 }
192 }
193
194 /**
195 * Selects the assembly artifact tp be used for installation.
196 *
197 * @return The assembly artifact selected to be installed.
198 *
199 * @throws MojoExecutionException Failed to select assembly artifact
200 */
201 protected Artifact getAssemblyArtifact() throws MojoExecutionException {
202 AssemblyConfig config;
203
204 if (assemblies == null || assemblies.length == 0) {
205 throw new MojoExecutionException("At least one assembly configuration must be specified");
206 }
207 else if (assemblies.length > 1 && assemblyId == null && defaultAssemblyId == null) {
208 throw new MojoExecutionException("Must specify assemblyId (or defaultAssemblyId) when more than on assembly configuration is given");
209 }
210 else if (assemblies.length == 1) {
211 config = assemblies[0];
212 }
213 else {
214 if (assemblyId == null) {
215 assemblyId = defaultAssemblyId;
216 }
217
218 log.debug("Searching for assembly config for id: " + assemblyId);
219
220 // Make sure there are no duplicate ids
221 Map idMap = new HashMap();
222
223 for (int i=0; i < assemblies.length; i++) {
224 String id = assemblies[i].getId();
225
226 if (id == null) {
227 throw new MojoExecutionException("Missing id for assembly configuration: " + assemblies[i]);
228 }
229
230 if (idMap.containsKey(id)) {
231 throw new MojoExecutionException("Duplicate assembly id: " + id);
232 }
233
234 idMap.put(id, assemblies[i]);
235 }
236
237 config = (AssemblyConfig) idMap.get(assemblyId);
238 if (config == null) {
239 throw new MojoExecutionException("Missing assembly configuration for id: " + assemblyId);
240 }
241 }
242
243 log.info("Using assembly configuration: " + config.getId());
244 Artifact artifact = getArtifact(config);
245
246 if (artifact.getFile() == null) {
247 throw new MojoExecutionException("Assembly artifact does not have an attached file: " + artifact);
248 }
249
250 return artifact;
251 }
252
253 /**
254 * Performs assembly installation unless the install type is pre-existing.
255 *
256 * @throws Exception
257 */
258 protected void installAssembly() throws Exception {
259 if (installType == InstallType.ALREADY_EXISTS) {
260 log.info("Installation type is pre-existing; skipping installation");
261 return;
262 }
263
264 // Check if there is a newer archive or missing marker to trigger assembly install
265 File installMarker = new File(geronimoHome, ".installed");
266
267 if (!refresh) {
268 if (!installMarker.exists()) {
269 refresh = true;
270 }
271 else if (assemblyArchive.lastModified() > installMarker.lastModified()) {
272 log.debug("Detected new assembly archive");
273 refresh = true;
274 }
275 }
276 else {
277 log.debug("User requested installation refresh");
278 }
279
280 if (refresh) {
281 if (geronimoHome.exists()) {
282 log.info("Uninstalling: " + geronimoHome);
283 FileUtils.forceDelete(geronimoHome);
284 }
285 }
286
287 // Install the assembly
288 if (!installMarker.exists()) {
289 log.info("Installing assembly...");
290
291 FileUtils.forceMkdir(geronimoHome);
292
293 Expand unzip = (Expand)createTask("unzip");
294 unzip.setSrc(assemblyArchive);
295 unzip.setDest(installDirectory.getCanonicalFile());
296 unzip.execute();
297
298 // Make scripts executable, since Java unzip ignores perms
299 Chmod chmod = (Chmod)createTask("chmod");
300 chmod.setPerm("ugo+rx");
301 chmod.setDir(geronimoHome);
302 chmod.setIncludes("bin/*");
303 chmod.setExcludes("bin/*.bat");
304 chmod.execute();
305
306 installMarker.createNewFile();
307 }
308 else {
309 log.info("Re-using previously installed assembly");
310 }
311 }
312 }