View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   * 
19   * Author: Siamak Haschemi
20   * Contact: haschemi@informatik.hu-berlin.de
21   */
22  package net.sourceforge.osgi.deployment.maven;
23  
24  import java.io.File;
25  import java.io.FileInputStream;
26  import java.io.FileOutputStream;
27  import java.io.IOException;
28  import java.io.OutputStream;
29  import java.util.jar.JarEntry;
30  import java.util.jar.JarOutputStream;
31  
32  import net.sourceforge.osgi.deployment.maven.container.BundleResource;
33  import net.sourceforge.osgi.deployment.maven.container.DeploymentPackageInfo;
34  import net.sourceforge.osgi.deployment.maven.container.ProcessedResource;
35  import net.sourceforge.osgi.deployment.maven.manifest.DeploymentPackageManifest;
36  import net.sourceforge.osgi.deployment.maven.manifest.OrderedManifest;
37  
38  import org.apache.maven.artifact.Artifact;
39  
40  
41  /**
42   * 
43   * @author Siamak Haschemi, haschemi@informatik.hu-berlin.de
44   * 
45   */
46  public final class DeploymentPlugin {
47  
48    private static final String DP_FILE_EXTENSION = ".dp";
49    private static final String MANIFEST_MF_PATH = "META-INF/MANIFEST.MF";
50  
51    private final IDeploymentPluginContext m_ctx;
52  
53    /**
54     * Default constructor to inject the context.
55     * 
56     * @param p_ctx
57     *          the {@link IDeploymentPluginContext} for the {@link DeploymentPlugin}
58     */
59    public DeploymentPlugin(final IDeploymentPluginContext p_ctx) {
60      m_ctx = p_ctx;
61    }
62  
63    /**
64     * Starts the execution of the Deployment-Package generation.
65     */
66    public void execute() {
67      // ignore project types not supported, useful when the plugin is configured in the parent pom
68      final Artifact artifact = m_ctx.getProject().getArtifact();
69      if (!m_ctx.getSupportedProjectTypes().contains(artifact.getType())) {
70        m_ctx.getLogger().debug(
71            "Ignoring project " + artifact + " : type " + artifact.getType() + " is not supported by bundle plugin, supported types are "
72                + m_ctx.getSupportedProjectTypes());
73        return;
74      }
75  
76      final DeploymentPackageManifest deploymentPackageManifest = new DeploymentPackageManifest(m_ctx);
77  
78      buildJar(deploymentPackageManifest);
79  
80      if (m_ctx.getManifestLocation() != null) {
81        writeManifestFile(deploymentPackageManifest);
82      }
83    }
84  
85    private void buildJar(final OrderedManifest p_orderedManifest) {
86      // the target deployment package jar file
87      final File jarFile = new File(m_ctx.getBuildDirectory(), getBundleName());
88  
89      // make dir dirs if not exists
90      jarFile.getParentFile().mkdirs();
91  
92      final Artifact mainArtifact = m_ctx.getProject().getArtifact();
93      // workaround for MNG-1682: force maven to install artifact using the "jar" handler
94      mainArtifact.setArtifactHandler(m_ctx.getArtifactHandlerManager().getArtifactHandler("jar"));
95      mainArtifact.setFile(jarFile);
96  
97      // Write the deployment package jar, which includes the manifest and all resources.
98      OutputStream out = null;
99      try {
100       out = new FileOutputStream(jarFile);
101       // The destination jar file
102       final JarOutputStream jout = new JarOutputStream(out);
103 
104       writeManifestIntoJar(p_orderedManifest, jout);
105       writeResourcesIntoJar(jout);
106       jout.finish();
107     } catch (final Exception t) {
108       throw new DeploymentPluginException("Problem writing Deployment package jar " + jarFile, t);
109     } finally {
110       if (out != null) {
111         try {
112           out.close();
113         } catch (final IOException e) {
114           throw new DeploymentPluginException("Problem closing stream of Deployment package jar " + jarFile, e);
115         }
116       }
117     }
118   }
119 
120   private void writeManifestFile(final OrderedManifest p_orderedManifest) {
121     final File outputFile = new File(m_ctx.getManifestLocation(), "MANIFEST.MF");
122     outputFile.getParentFile().mkdirs();
123 
124     FileOutputStream os = null;
125     try {
126       os = new FileOutputStream(outputFile);
127       p_orderedManifest.write(os);
128     } catch (final Exception e) {
129       throw new DeploymentPluginException("Error trying to write Manifest to file " + outputFile, e);
130     } finally {
131       try {
132         os.close();
133       } catch (final IOException e) {
134         throw new DeploymentPluginException("Error trying to close the stream to the Manifest to file " + outputFile, e);
135       }
136     }
137   }
138 
139   private void writeResourcesIntoJar(final JarOutputStream p_jout) {
140     final DeploymentPackageInfo deploymentPackageInfo = m_ctx.getDeploymentPackageInfo();
141 
142     // Sort the resources
143     // 1. META-INF/MANIFEST.MF (Will be generated)
144     // 2. Signature files TODO
145     // 3. Localization files (Stored in the OSGI-INF directory)
146     // 4. Bundle resources
147     // 5. processed resources
148 
149     for (final ProcessedResource localizationResource : deploymentPackageInfo.getLocalizationResources()) {
150       copyIntoJar(p_jout, localizationResource);
151     }
152 
153     for (final BundleResource bundleResource : deploymentPackageInfo.getBundleResources()) {
154       copyIntoJar(p_jout, bundleResource);
155     }
156 
157     for (final ProcessedResource processedResource : deploymentPackageInfo.getProcessedResources()) {
158       copyIntoJar(p_jout, processedResource);
159     }
160   }
161 
162   private void copyIntoJar(final JarOutputStream p_jout, final ProcessedResource p_processedResource) {
163     copyIntoJar(p_jout, new File(m_ctx.getOutputDirectory(), p_processedResource.getFilePath()), p_processedResource.getResourceId());
164   }
165 
166   private void copyIntoJar(final JarOutputStream p_jout, final BundleResource p_bundleResource) {
167     copyIntoJar(p_jout, p_bundleResource.getResolvedFile(), p_bundleResource.getResourceId());
168   }
169 
170   private static final int BUFFER_SIZE = 1024;
171 
172   private static void copyIntoJar(final JarOutputStream p_jout, final File p_file, final String p_path) {
173     try {
174       p_jout.putNextEntry(new JarEntry(p_path));
175       final FileInputStream inputStream = new FileInputStream(p_file);
176       final byte[] buffer = new byte[BUFFER_SIZE];
177       int bytesRead = 0;
178       while ((bytesRead = inputStream.read(buffer)) > 0) {
179         p_jout.write(buffer, 0, bytesRead);
180       }
181       inputStream.close();
182       p_jout.closeEntry();
183       p_jout.flush();
184     } catch (final Exception e) {
185       // Wrap checked exception
186       throw new RuntimeException("Error while copying file " + p_file + " into jar", e);
187     }
188   }
189 
190   private void writeManifestIntoJar(final OrderedManifest p_manifest, final JarOutputStream p_jout) {
191     try {
192       p_jout.putNextEntry(new JarEntry(MANIFEST_MF_PATH));
193       p_manifest.write(p_jout);
194       p_jout.closeEntry();
195     } catch (IOException e) {
196       throw new DeploymentPluginException("Error while writing the manifest into " + MANIFEST_MF_PATH, e);
197     }
198   }
199 
200   /**
201    * @return the bundle symbolic name derived from the maven project informations.
202    */
203   private String getBundleName() {
204     final String finalName = m_ctx.getProject().getBuild().getFinalName();
205 
206     return finalName + DP_FILE_EXTENSION;
207   }
208 }