PageRenderTime 27ms CodeModel.GetById 11ms app.highlight 12ms RepoModel.GetById 1ms app.codeStats 0ms

/maven-amps-plugin/src/main/java/com/atlassian/maven/plugins/amps/product/AmpsProductHandler.java

https://bitbucket.org/mmeinhold/amps
Java | 304 lines | 210 code | 40 blank | 54 comment | 19 complexity | f5e6500594e518a5ec07da9fa38a1f69 MD5 | raw file
  1package com.atlassian.maven.plugins.amps.product;
  2
  3
  4import static com.atlassian.maven.plugins.amps.util.FileUtils.copyDirectory;
  5import static org.apache.commons.lang.StringUtils.isNotBlank;
  6
  7import java.io.File;
  8import java.io.IOException;
  9import java.io.UnsupportedEncodingException;
 10import java.net.InetAddress;
 11import java.net.URLEncoder;
 12import java.net.UnknownHostException;
 13import java.util.Collections;
 14import java.util.Comparator;
 15import java.util.List;
 16
 17import com.atlassian.maven.plugins.amps.*;
 18import org.apache.commons.io.FileUtils;
 19import org.apache.commons.lang.StringUtils;
 20import org.apache.maven.plugin.MojoExecutionException;
 21import org.apache.maven.plugin.logging.Log;
 22import org.apache.maven.project.MavenProject;
 23
 24import com.atlassian.maven.plugins.amps.util.ConfigFileUtils;
 25import com.atlassian.maven.plugins.amps.util.ConfigFileUtils.Replacement;
 26import com.atlassian.maven.plugins.amps.util.ProjectUtils;
 27import com.atlassian.maven.plugins.amps.util.ZipUtils;
 28import com.google.common.collect.Lists;
 29
 30/**
 31 * This abstract class is common to real applications (which inherit from AbstractProductHandler, like JIRA or Confluence)
 32 * and the fake application Studio.
 33 *
 34 * This class handles common operations
 35 *
 36 * @since 3.6
 37 */
 38public abstract class AmpsProductHandler implements ProductHandler
 39{
 40    protected final MavenGoals goals;
 41    protected final MavenProject project;
 42    protected final MavenContext context;
 43    protected final Log log;
 44
 45    protected AmpsProductHandler(MavenContext context, MavenGoals goals)
 46    {
 47        this.project = context.getProject();
 48        this.context = context;
 49        this.goals = goals;
 50        this.log = context.getLog();
 51    }
 52
 53    /**
 54     * Copies and creates a zip file of the previous run's home directory minus any installed plugins.
 55     *
 56     * @param homeDirectory
 57     *            The path to the previous run's home directory.
 58     * @param targetZip
 59     *            The path to the final zip file.
 60     * @param product
 61     *            The product
 62     *
 63     * @since 3.1-m3
 64     */
 65    public void createHomeZip(final File homeDirectory, final File targetZip, final Product product) throws MojoExecutionException
 66    {
 67        if (homeDirectory == null || !homeDirectory.exists())
 68        {
 69            String homePath = "null";
 70            if (homeDirectory != null)
 71            {
 72                homePath = homeDirectory.getAbsolutePath();
 73            }
 74            context.getLog().info("home directory doesn't exist, skipping. [" + homePath + "]");
 75            return;
 76        }
 77
 78
 79        try
 80            {
 81            /*
 82             * The zip has /someRootFolder/{productId}-home/
 83             */
 84            final File appDir = getBaseDirectory(product);
 85            final File tmpDir = new File(appDir, "tmp-resources");
 86            final File homeSnapshot = new File(tmpDir, "generated-home");
 87            final String entryBase = "generated-resources/" + product.getId() + "-home";
 88
 89            if (homeSnapshot.exists())
 90            {
 91                FileUtils.deleteDirectory(homeSnapshot);
 92            }
 93
 94            homeSnapshot.mkdirs();
 95            copyDirectory(homeDirectory, homeSnapshot, true);
 96
 97            cleanupProductHomeForZip(product, homeSnapshot);
 98            ZipUtils.zipDir(targetZip, homeSnapshot, entryBase);
 99        }
100        catch (IOException e)
101        {
102            throw new RuntimeException("Error zipping home directory", e);
103        }
104    }
105
106    /**
107     * Prepares the home directory to snapshot:
108     * <ul>
109     * <li>Removes all unnecessary files</li>
110     * <li>Perform product-specific clean-up</li>
111     * <ul>
112     * This is a reference implementation. It is probable that each application has a different set of directories to delete.
113     * @param product the product details
114     * @param snapshotDir an image of the home which will be zipped. This is not the working home, so you're free to remove files and parametrise them.
115     * @throws IOException
116     */
117    public void cleanupProductHomeForZip(Product product, File snapshotDir) throws MojoExecutionException, IOException
118    {
119        try {
120            // we want to get rid of the plugins folders.
121            FileUtils.deleteDirectory(new File(snapshotDir, "plugins")); // Not used by: fisheye, confluence, studio - Used by: crowd, bamboo, jira
122            FileUtils.deleteDirectory(new File(snapshotDir, "bundled-plugins")); // Not used by: fisheye, jira - Used by: confluence, crowd, bamboo
123
124            // Get rid of "studio-test-resources.zip", which is the homeZip that was used
125            // when we started Amps.
126            if (this.getTestResourcesArtifact() != null)
127            {
128                String originalHomeZip = this.getTestResourcesArtifact().getArtifactId() + ".zip";
129                FileUtils.deleteQuietly(new File(snapshotDir, originalHomeZip));
130            }
131
132
133            // Proceed to replacements
134            List<Replacement> replacements = getReplacements(product);
135            // Sort by longer values first, so that the right keys are used.
136            Collections.sort(replacements, new Comparator<Replacement>(){
137                @Override
138                public int compare(Replacement replacement1, Replacement replacement2)
139                {
140                    // longest value < shortest value
141                    int length1 = replacement1.getValue().length();
142                    int length2 = replacement2.getValue().length();
143                    return length2 - length1;
144                }
145            });
146            List<File> files = getConfigFiles(product, snapshotDir);
147
148            ConfigFileUtils.replace(files, replacements, true, log);
149        }
150        catch (IOException ioe)
151        {
152            throw new MojoExecutionException("Could not delete home/plugins/ and /home/bundled-plugins/", ioe);
153        }
154    }
155
156    abstract protected ProductArtifact getTestResourcesArtifact();
157
158    protected File getProductHomeData(final Product ctx) throws MojoExecutionException
159    {
160        File productHomeZip = null;
161        String dataPath = ctx.getDataPath();
162
163        //use custom zip if supplied
164        if (isNotBlank(dataPath))
165        {
166            File customHomeZip = new File(dataPath);
167
168            if (customHomeZip.exists())
169            {
170                return customHomeZip;
171            }
172            throw new MojoExecutionException("Unable to use custom test resources set by <dataPath>. File '" +
173                    customHomeZip.getAbsolutePath() + "' does not exist");
174        }
175
176        //if we didn't find a custom zip, use the default
177        ProductArtifact testResourcesArtifact = getTestResourcesArtifact();
178        if (productHomeZip == null && testResourcesArtifact != null)
179        {
180            ProductArtifact artifact = new ProductArtifact(
181                testResourcesArtifact.getGroupId(), testResourcesArtifact.getArtifactId(), ctx.getDataVersion());
182            productHomeZip = goals.copyHome(getBaseDirectory(ctx), artifact);
183        }
184
185        return productHomeZip;
186    }
187
188    protected void overrideAndPatchHomeDir(File homeDir, final Product ctx) throws MojoExecutionException
189    {
190        try
191        {
192            final File srcDir = new File(project.getBasedir(), "src/test/resources/" + ctx.getInstanceId() + "-home");
193            if (srcDir.exists() && homeDir.exists())
194            {
195                copyDirectory(srcDir, homeDir, false);
196            }
197        }
198        catch (IOException e)
199        {
200            throw new MojoExecutionException("Unable to override files using src/test/resources", e);
201        }
202    }
203
204
205    /**
206     * Lists parameters which must be replaced in the configuration files of the home directory.
207     * <p/>
208     * Used reversely when reading / when creating a home zip.
209     */
210    public List<ConfigFileUtils.Replacement> getReplacements(Product product)
211    {
212        // Standard replacements:
213        List<Replacement> replacements = Lists.newArrayList();
214        String buildDirectory = project.getBuild().getDirectory();
215        String baseDirectory = getBaseDirectory(product).getAbsolutePath();
216        String homeDirectory = getHomeDirectory(product).getAbsolutePath();
217
218        replacements.add(new Replacement("%PROJECT_BUILD_DIR%", buildDirectory));
219        replacements.add(new Replacement("%PRODUCT_BASE_DIR%", baseDirectory));
220        replacements.add(new Replacement("%PRODUCT_HOME_DIR%", homeDirectory));
221
222        // These replacements are especially for Fecru, but there's no reason not to find them in other config files
223        try {
224            replacements.add(new Replacement("%PROJECT_BUILD_DIR_URL_ENCODED%", URLEncoder.encode(propertiesEncode(buildDirectory), "UTF-8")));
225            replacements.add(new Replacement("%PRODUCT_BASE_DIR_URL_ENCODED%", URLEncoder.encode(propertiesEncode(baseDirectory), "UTF-8")));
226            replacements.add(new Replacement("%PRODUCT_HOME_DIR_URL_ENCODED%", URLEncoder.encode(propertiesEncode(homeDirectory), "UTF-8")));
227        }
228        catch (UnsupportedEncodingException badJvm)
229        {
230            throw new RuntimeException("UTF-8 should be supported on any JVM", badJvm);
231        }
232
233        replacements.add(Replacement.onlyWhenCreatingSnapshot("localhost", product.getServer()));
234
235        try
236        {
237            String localHostName = InetAddress.getLocalHost().getHostName();
238            replacements.add(new Replacement("%LOCAL_HOST_NAME%", localHostName));
239        }
240        catch (UnknownHostException e)
241        {
242            // If we can't get the local computer's hostname, it's probable no product could,
243            // so we don't need to search-replace the value.
244        }
245
246        return replacements;
247    }
248
249    /**
250     * Encodes a String for a Properties file. Escapes : and =.
251     */
252    protected String propertiesEncode(String decoded)
253    {
254        if (decoded == null)
255        {
256            return null;
257        }
258        String replacement1 = decoded.replaceAll(":", "\\:");
259        String replacement2 = replacement1.replaceAll("=", "\\=");
260        return replacement2;
261    }
262
263    @Override
264    public List<File> getConfigFiles(Product product, File snapshotDir)
265    {
266        return Lists.newArrayList();
267    }
268
269    public File getBaseDirectory(Product ctx)
270    {
271        return ProjectUtils.createDirectory(new File(project.getBuild().getDirectory(), ctx.getInstanceId()));
272    }
273
274    public File getHomeDirectory(Product ctx)
275    {
276        if (StringUtils.isNotBlank(ctx.getDataHome()))
277        {
278            return new File(ctx.getDataHome());
279        }
280        return new File(getBaseDirectory(ctx), "home");
281    }
282
283    public File getSnapshotDirectory(Product product)
284    {
285        return getHomeDirectory(product);
286    }
287
288    @Override
289    public String getDefaultContextPath()
290    {
291        return "/" + getId();
292    }
293
294    @Override
295    public String getDefaultContainerId()
296    {
297        return AmpsDefaults.DEFAULT_CONTAINER;
298    }
299
300    protected File createHomeDirectory(Product ctx)
301    {
302        return ProjectUtils.createDirectory(getHomeDirectory(ctx));
303    }
304}