001: package org.andromda.maven.plugin.modelarchiver;
002:
003: import java.io.File;
004: import java.io.FileReader;
005: import java.io.FileWriter;
006: import java.io.IOException;
007:
008: import java.util.ArrayList;
009: import java.util.Arrays;
010: import java.util.Collection;
011: import java.util.zip.ZipEntry;
012: import java.util.zip.ZipOutputStream;
013:
014: import org.apache.commons.io.IOUtils;
015: import org.apache.commons.lang.StringUtils;
016: import org.apache.maven.archiver.MavenArchiveConfiguration;
017: import org.apache.maven.archiver.MavenArchiver;
018: import org.apache.maven.artifact.Artifact;
019: import org.apache.maven.artifact.factory.ArtifactFactory;
020: import org.apache.maven.artifact.repository.ArtifactRepository;
021: import org.apache.maven.plugin.AbstractMojo;
022: import org.apache.maven.plugin.MojoExecutionException;
023: import org.apache.maven.project.MavenProject;
024: import org.apache.maven.project.MavenProjectHelper;
025: import org.codehaus.plexus.archiver.ArchiverException;
026: import org.codehaus.plexus.archiver.UnArchiver;
027: import org.codehaus.plexus.archiver.jar.JarArchiver;
028: import org.codehaus.plexus.archiver.manager.ArchiverManager;
029: import org.codehaus.plexus.util.FileUtils;
030:
031: /**
032: * Builds archived model xml.zip files.
033: *
034: * @author Chad Brandon
035: * @goal xml.zip
036: * @phase package
037: * @requiresProject
038: * @description builds a versioned xml.zip
039: */
040: public class XmiZipArchiverMojo extends AbstractMojo {
041: /**
042: * Single directory that contains the model
043: *
044: * @parameter expression="${basedir}/src/main/uml"
045: * @required
046: */
047: private File modelSourceDirectory;
048:
049: /**
050: * Directory that resources are copied to during the build.
051: *
052: * @parameter expression="${project.build.directory}"
053: * @required
054: */
055: private String workDirectory;
056:
057: /**
058: * The directory for the generated xml.zip.
059: *
060: * @parameter expression="${project.build.outputDirectory}"
061: * @required
062: */
063: private String outputDirectory;
064:
065: /**
066: * The name of the xml.zip file to generate.
067: *
068: * @parameter alias="modelName" expression="${project.build.finalName}"
069: * @required
070: * @readonly
071: */
072: private String finalName;
073:
074: /**
075: * The maven project.
076: *
077: * @parameter expression="${project}"
078: * @required
079: * @readonly
080: * @description "the maven project to use"
081: */
082: private MavenProject project;
083:
084: /**
085: * Artifact factory, needed to download source jars for inclusion in
086: * classpath.
087: *
088: * @component role="org.apache.maven.artifact.factory.ArtifactFactory"
089: * @required
090: * @readonly
091: */
092: private ArtifactFactory artifactFactory;
093:
094: /**
095: * To look up Archiver/UnArchiver implementations
096: *
097: * @parameter expression="${component.org.codehaus.plexus.archiver.manager.ArchiverManager}"
098: * @required
099: */
100: protected ArchiverManager archiverManager;
101:
102: /**
103: * The model Jar archiver.
104: *
105: * @parameter expression="${component.org.codehaus.plexus.archiver.Archiver#jar}"
106: * @required
107: */
108: private JarArchiver modelJarArchiver;
109:
110: /**
111: * The extensions to search for when doing replacement of embedded model HREF references
112: * within the archived model file from non-versioned to versioned references.
113: *
114: * @parameter expression=".xml,.xml.zip,.xmi"
115: * @required
116: */
117: protected String replacementExtensions;
118:
119: /**
120: * Whether or not to do replacement of embedded model HREF reference extensions.
121: *
122: * @parameter expression=true
123: * @required
124: */
125: protected boolean replaceExtensions;
126:
127: /**
128: * The maven project's helper.
129: *
130: * @parameter expression="${component.org.apache.maven.project.MavenProjectHelper}"
131: * @required
132: * @readonly
133: */
134: private MavenProjectHelper projectHelper;
135:
136: /**
137: * Whether or not the model should have a jar created with it as well.
138: *
139: * @parameter
140: */
141: private boolean generateJar;
142: private static final String[] JAR_INCLUDES = new String[] { "**/*" };
143: private static final String[] JAR_EXCLUDES = new String[] { "**/package.html" };
144: private final Collection modelArchiveExcludes = new ArrayList(
145: Arrays.asList(new String[] { "*.xml.zip, **/*.java",
146: "*reports*/**", "tests*/**" }));
147:
148: /**
149: * The pattern of the archived model files that should be extracted
150: * before being re-created as versioned model archives.
151: *
152: * @parameter expression=".*(\\.xml\\.zip)"
153: * @required
154: * @readonly
155: */
156: private String modelArchivePattern;
157:
158: /**
159: * The pattern of the non-archived model file(s) that should be archived.
160: *
161: * @parameter expression=".*(\\.xml|\\.xmi)"
162: * @required
163: * @readonly
164: */
165: private String modelFilePattern;
166:
167: /**
168: * The maven archiver to use.
169: *
170: * @parameter
171: */
172: private MavenArchiveConfiguration archive = new MavenArchiveConfiguration();
173:
174: /**
175: * @parameter expression="${localRepository}"
176: * @required
177: * @readonly
178: */
179: protected ArtifactRepository localRepository;
180:
181: public void execute() throws MojoExecutionException {
182: getLog().debug(" ======= XmlZipArchiverMojo settings =======");
183: getLog().debug(
184: "modelSourceDirectory[" + modelSourceDirectory + "]");
185: getLog().debug("workDirectory[" + workDirectory + "]");
186: getLog().debug("outputDirectory[" + outputDirectory + "]");
187: getLog().debug("finalName[" + finalName + "]");
188: getLog().debug("replaceExtensions[" + replaceExtensions + "]");
189:
190: try {
191: // - the directory which to extract the model file
192: final File modelExtractDirectory = new File(
193: this .workDirectory, "models/xmi");
194: modelExtractDirectory.mkdirs();
195: final File buildDirectory = new File(this .workDirectory);
196:
197: final File modelSourceDir = modelSourceDirectory;
198: final String[] replacementExtensions = this .replacementExtensions != null ? this .replacementExtensions
199: .split(",\\s*")
200: : new String[0];
201: if (modelSourceDir.exists()) {
202: getLog().info(
203: "Copy xml.zip resources to "
204: + buildDirectory.getAbsolutePath());
205: final File[] modelFiles = modelSourceDir.listFiles();
206: for (int ctr = 0; ctr < modelFiles.length; ctr++) {
207: final File file = modelFiles[ctr];
208: if (file.isFile()
209: && file.toString().matches(
210: this .modelArchivePattern)) {
211: // - extract model file
212: this .unpack(file, modelExtractDirectory);
213: final File[] extractedModelFiles = modelExtractDirectory
214: .listFiles();
215: for (int ctr2 = 0; ctr2 < extractedModelFiles.length; ctr2++) {
216: final File extractedFile = extractedModelFiles[ctr2];
217: final String extractedFilePath = extractedFile
218: .toString();
219: if (extractedFile.isFile()
220: && extractedFilePath
221: .matches(this .modelFilePattern)) {
222: final File newFile = new File(
223: modelExtractDirectory,
224: this .finalName
225: + '.'
226: + FileUtils
227: .getExtension(extractedFile
228: .toString()));
229:
230: // - exclude the file that we extracted
231: if (!newFile.equals(extractedFile)) {
232: final String shortPath = extractedFilePath
233: .replaceAll(".*\\\\|/", "");
234: this .modelArchiveExcludes
235: .add(shortPath);
236: }
237: extractedFile.renameTo(newFile);
238: String contents = IOUtils
239: .toString(new FileReader(
240: newFile));
241: if (replaceExtensions) {
242: for (int ctr3 = 0; ctr3 < replacementExtensions.length; ctr3++) {
243: final String version = escapePattern(this .project
244: .getVersion());
245: final String extension = escapePattern(replacementExtensions[ctr3]);
246: final String extensionPattern = "((\\-"
247: + version
248: + ")?)"
249: + extension;
250: final String newExtension = "\\-"
251: + version + extension;
252: contents = contents.replaceAll(
253: extensionPattern,
254: newExtension);
255: }
256: }
257: final FileWriter fileWriter = new FileWriter(
258: newFile);
259: fileWriter.write(contents);
260: fileWriter.flush();
261: final File xmlZipFile = new File(
262: buildDirectory, this .finalName
263: + ".xml.zip");
264: this .writeModelArchive(xmlZipFile,
265: newFile.toString());
266: }
267: }
268: }
269: }
270: }
271:
272: final File xmlZipFile = new File(buildDirectory,
273: this .finalName + ".xml.zip");
274: final Artifact artifact = this .project.getArtifact();
275: artifact.setFile(xmlZipFile);
276: if (this .generateJar) {
277: final File workDirectory = new File(this .workDirectory);
278: this .getLog().info("Building model jar " + finalName);
279:
280: final Artifact jarArtifact = artifactFactory
281: .createArtifact(project.getGroupId(), project
282: .getArtifactId(), project.getVersion(),
283: null, ATTACHED_ARTIFACT_TYPE);
284:
285: File modelJar = new File(workDirectory, finalName + "."
286: + ATTACHED_ARTIFACT_TYPE);
287:
288: final MavenArchiver modelJarArchiver = new MavenArchiver();
289:
290: modelJarArchiver.setArchiver(this .modelJarArchiver);
291: modelJarArchiver.setOutputFile(modelJar);
292: modelJarArchiver.getArchiver().addDirectory(
293: new File(this .outputDirectory), JAR_INCLUDES,
294: JAR_EXCLUDES);
295:
296: // - create archive
297: modelJarArchiver.createArchive(project, archive);
298:
299: // - set the artifact file as the modelJar so that we can install the model jar
300: jarArtifact.setFile(modelJar);
301: this .installModelJar(jarArtifact, modelJar);
302: projectHelper.attachArtifact(project,
303: ATTACHED_ARTIFACT_TYPE, null, modelJar);
304: }
305: } catch (final Throwable throwable) {
306: throw new MojoExecutionException("Error assembling model",
307: throwable);
308: }
309: }
310:
311: /**
312: * The type of the attached artifact.
313: */
314: private static final String ATTACHED_ARTIFACT_TYPE = "jar";
315:
316: /**
317: * Installs the model jar for this xml.zip artifact into the local repository.
318: *
319: * @param artifact the artifact to install.
320: * @param source the source of the artifact.
321: * @throws IOException
322: */
323: private void installModelJar(final Artifact artifact,
324: final File source) throws IOException {
325: // - change the extension to the correct 'jar' extension
326: final String localPath = this .localRepository.pathOf(artifact)
327: .replaceAll("\\.xml\\.zip", "\\.jar");
328: final File destination = new File(this .localRepository
329: .getBasedir(), localPath);
330: this .getLog()
331: .info(
332: "Installing " + source.getPath() + " to "
333: + destination);
334:
335: FileUtils.copyFile(source, destination);
336: }
337:
338: /**
339: * Escapes the pattern so that the reserved regular expression
340: * characters are used literally.
341: * @param pattern the pattern to replace.
342: * @return the resulting pattern.
343: */
344: private static String escapePattern(String pattern) {
345: pattern = StringUtils.replace(pattern, ".", "\\.");
346: pattern = StringUtils.replace(pattern, "-", "\\-");
347: return pattern;
348: }
349:
350: /**
351: * Unpacks the archive file.
352: *
353: * @param file File to be unpacked.
354: * @param location Location where to put the unpacked files.
355: */
356: protected void unpack(final File file, final File location)
357: throws MojoExecutionException {
358: final String archiveExt = FileUtils.getExtension(
359: file.getAbsolutePath()).toLowerCase();
360: try {
361: final UnArchiver unArchiver;
362: unArchiver = this .archiverManager.getUnArchiver(archiveExt);
363: unArchiver.setSourceFile(file);
364: unArchiver.setDestDirectory(location);
365: unArchiver.extract();
366: } catch (Throwable throwable) {
367: if (throwable instanceof IOException
368: || throwable instanceof ArchiverException) {
369: throw new MojoExecutionException(
370: "Error unpacking file: " + file + "to: "
371: + location, throwable);
372: }
373: }
374: }
375:
376: /**
377: * The regular expression pattern used to remove the beginning of the path from the file (and leave the name).
378: */
379: private static final String PATH_REMOVE_PATTERN = ".*(\\\\|/)";
380:
381: /**
382: * Writes the given given <code>model</code> archive file and includes
383: * the file given by the <code>path</code>
384: *
385: * @param modelArchive the model archive.
386: * @param path the path of the model to write.
387: * @throws IOException
388: */
389: private void writeModelArchive(final File modelArchive,
390: final String path) throws IOException {
391: // - retrieve the name of the file given by the path.
392: final String name = path.replaceAll(PATH_REMOVE_PATTERN, "");
393: final ZipOutputStream zipOutputStream = new ZipOutputStream(
394: new java.io.FileOutputStream(modelArchive));
395: final ZipEntry zipEntry = new ZipEntry(name);
396: zipEntry.setMethod(ZipEntry.DEFLATED);
397: zipOutputStream.putNextEntry(zipEntry);
398: final java.io.FileInputStream inputStream = new java.io.FileInputStream(
399: path);
400: final byte[] buffer = new byte[1024];
401: int n = 0;
402: while ((n = inputStream.read(buffer, 0, buffer.length)) > 0) {
403: zipOutputStream.write(buffer, 0, n);
404: }
405: inputStream.close();
406: zipOutputStream.closeEntry();
407: zipOutputStream.close();
408: }
409: }
|