001package org.andromda.maven.plugin.modelarchiver;
002
003import java.io.File;
004import java.io.FileInputStream;
005import java.io.FileOutputStream;
006import java.io.IOException;
007import java.util.zip.ZipEntry;
008import java.util.zip.ZipOutputStream;
009import org.apache.commons.io.FileUtils;
010import org.apache.commons.io.FilenameUtils;
011import org.apache.commons.io.IOUtils;
012import org.apache.maven.plugin.MojoExecutionException;
013import org.codehaus.plexus.archiver.ArchiverException;
014import org.codehaus.plexus.archiver.UnArchiver;
015
016/**
017 * Builds archived model xml.zip files.
018 *
019 * @author Chad Brandon
020 * @version $Id: $
021 * @goal xml.zip
022 * @phase package
023 * @description builds a versioned xml.zip
024 */
025public class XmiZipArchiverMojo
026        extends BaseArchiveMojo
027{
028    private static final String ARTIFACT_TYPE = "xml.zip";
029
030    /**
031     * The extensions to search for when doing replacement of embedded model HREF references
032     * within the archived model file from non-versioned to versioned references.
033     *
034     * @parameter expression=".xml,.xml.zip,.xmi"
035     * @required
036     */
037    protected String replacementExtensions;
038
039    /**
040     * The pattern of the archived model files that should be extracted
041     * before being re-created as versioned model archives.
042     *
043     * @parameter expression=".*(\\.xml\\.zip)"
044     * @required
045     * @readonly
046     */
047    private String modelArchivePattern;
048
049    /**
050     * The pattern of the non-archived model file(s) that should be archived.
051     *
052     * @parameter expression=".*(\\.xml|\\.xmi)"
053     * @required
054     * @readonly
055     */
056    private String modelFilePattern;
057
058    /**
059     * Whether or not to do replacement of embedded model HREF reference extensions.
060     *
061     * @parameter expression="true"
062     * @required
063     */
064    protected boolean replaceExtensions;
065
066    /**
067     * Whether or not the model should be attached as new artifact.
068     *
069     * @parameter expression="false"
070     */
071    private boolean attachArtifact;
072
073    /**
074     * <p>execute</p>
075     *
076     * @throws org.apache.maven.plugin.MojoExecutionException
077     *          if any.
078     * @see org.apache.maven.plugin.Mojo#execute()
079     */
080    public void execute()
081            throws MojoExecutionException
082    {
083        if (getLog().isDebugEnabled())
084        {
085            getLog().debug(" ======= XmlZipArchiverMojo settings =======");
086            getLog().debug("modelSourceDirectory[" + modelSourceDirectory + ']');
087            getLog().debug("workDirectory[" + workDirectory + ']');
088            getLog().debug("outputDirectory[" + outputDirectory + ']');
089            getLog().debug("finalName[" + finalName + ']');
090            getLog().debug("replaceExtensions[" + replaceExtensions + ']');
091            getLog().debug("version[" + this.project.getVersion() + ']');
092            getLog().debug("extension[" + this.replacementExtensions + ']');
093            getLog().debug("extensionPattern[" + "((\\-" + this.project.getVersion() + ")?)" + this.replacementExtensions + ']');
094            getLog().debug("newExtension[" + "\\-" + this.project.getVersion() + this.replacementExtensions + ']');
095            getLog().debug("attachArtifact[" + attachArtifact + ']');
096        }
097
098        try
099        {
100            final File buildDirectory = this.workDirectory;
101            if (buildDirectory.exists())
102            {
103                // old files in directory are not automatically deleted.
104                deleteFiles(buildDirectory.getAbsolutePath(), ARTIFACT_TYPE);
105                FileUtils.deleteDirectory(new File(buildDirectory, "models"));
106            }
107            // - the directory which to extract the model file
108            final File modelExtractDirectory = new File(buildDirectory, "models/xmi");
109            modelExtractDirectory.mkdirs();
110
111            if (modelSourceDirectory.exists())
112            {
113                getLog().info("Copy xml.zip resources to " + modelExtractDirectory.getAbsolutePath());
114                final File[] modelFiles = modelSourceDirectory.listFiles();
115                for (final File file : modelFiles)
116                {
117                    if (file.isFile() && file.toString().matches(this.modelArchivePattern))
118                    {
119                        // - extract model file
120                        this.unpack(file, modelExtractDirectory);
121
122                        final File[] extractedModelFiles = modelExtractDirectory.listFiles();
123                        for (final File extractedFile : extractedModelFiles)
124                        {
125                            final String extractedFilePath = extractedFile.toString();
126                            if (extractedFile.isFile() && extractedFilePath.matches(this.modelFilePattern))
127                            {
128                                final File newFile =
129                                        new File(modelExtractDirectory,
130                                                this.finalName + '.' + FilenameUtils.getExtension(extractedFile.getName()));
131                                extractedFile.renameTo(newFile);
132
133                                if (replaceExtensions)
134                                {
135                                    getLog().info("Replace extensions in " + newFile);
136                                    replaceExtensions(this.replacementExtensions, newFile);
137                                }
138
139                                final File xmlZipFile = new File(buildDirectory, this.finalName + '.' + ARTIFACT_TYPE);
140                                this.writeModelArchive(xmlZipFile, newFile);
141                            }
142                        }
143                    }
144                }
145            }
146
147            final File xmlZipFile = new File(buildDirectory, this.finalName + "." + ARTIFACT_TYPE);
148            if (!this.attachArtifact)
149            {
150                setArtifactFile(xmlZipFile);
151            }
152            else
153            {
154                //Attach artifact
155                projectHelper.attachArtifact(project, ARTIFACT_TYPE, xmlZipFile);
156            }
157        }
158        catch (final Throwable throwable)
159        {
160            throw new MojoExecutionException("Error assembling model", throwable);
161        }
162    }
163
164    /**
165     * Unpacks the archive file.
166     *
167     * @param file     File to be unpacked.
168     * @param location Location where to put the unpacked files.
169     * @throws MojoExecutionException if IOException or ArchiverException from unArchiver.extract()
170     */
171    private void unpack(
172            final File file,
173            final File location)
174            throws MojoExecutionException
175    {
176        final String archiveExt = FilenameUtils.getExtension(file.getAbsolutePath()).toLowerCase();
177        try
178        {
179            final UnArchiver unArchiver;
180            unArchiver = this.archiverManager.getUnArchiver(archiveExt);
181            unArchiver.setSourceFile(file);
182            unArchiver.setDestDirectory(location);
183            unArchiver.extract();
184        }
185        catch (Throwable throwable)
186        {
187            if (throwable instanceof IOException || throwable instanceof ArchiverException)
188            {
189                throw new MojoExecutionException("Error unpacking file: " + file + "to: " + location, throwable);
190            }
191        }
192    }
193
194    /**
195     * Writes the given given <code>model</code> archive file and includes
196     * the file given by the <code>model</code>
197     *
198     * @param modelArchive the model archive.
199     * @param model        the file of model to write.
200     * @throws IOException
201     */
202    private void writeModelArchive(
203            final File modelArchive,
204            final File model)
205            throws IOException
206    {
207        final ZipOutputStream zipOutputStream = new ZipOutputStream(new FileOutputStream(modelArchive));
208        final ZipEntry zipEntry = new ZipEntry(model.getName());
209        zipEntry.setMethod(ZipEntry.DEFLATED);
210        zipOutputStream.putNextEntry(zipEntry);
211        final FileInputStream inputStream = new FileInputStream(model);
212
213        IOUtils.copy(inputStream, zipOutputStream);
214
215        zipOutputStream.closeEntry();
216
217        IOUtils.closeQuietly(inputStream);
218        IOUtils.closeQuietly(zipOutputStream);
219    }
220}