1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.felix.bundleplugin;
20
21
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.OutputStream;
27 import java.util.Iterator;
28 import java.util.LinkedHashMap;
29 import java.util.Map;
30 import java.util.Map.Entry;
31 import java.util.Properties;
32 import java.util.jar.Manifest;
33
34 import org.apache.maven.plugin.MojoExecutionException;
35 import org.apache.maven.plugin.MojoFailureException;
36 import org.apache.maven.project.MavenProject;
37
38 import aQute.bnd.osgi.Analyzer;
39 import aQute.bnd.osgi.Builder;
40 import aQute.bnd.osgi.Jar;
41 import aQute.bnd.osgi.Resource;
42
43
44
45
46
47
48
49
50
51
52 public class ManifestPlugin extends BundlePlugin
53 {
54
55
56
57
58
59 protected boolean rebuildBundle;
60
61
62 @Override
63 protected void execute( MavenProject project, Map instructions, Properties properties, Jar[] classpath )
64 throws MojoExecutionException
65 {
66 Manifest manifest;
67 try
68 {
69 manifest = getManifest( project, instructions, properties, classpath );
70 }
71 catch ( FileNotFoundException e )
72 {
73 throw new MojoExecutionException( "Cannot find " + e.getMessage()
74 + " (manifest goal must be run after compile phase)", e );
75 }
76 catch ( IOException e )
77 {
78 throw new MojoExecutionException( "Error trying to generate Manifest", e );
79 }
80 catch ( MojoFailureException e )
81 {
82 getLog().error( e.getLocalizedMessage() );
83 throw new MojoExecutionException( "Error(s) found in manifest configuration", e );
84 }
85 catch ( Exception e )
86 {
87 getLog().error( "An internal error occurred", e );
88 throw new MojoExecutionException( "Internal error in maven-bundle-plugin", e );
89 }
90
91 File outputFile = new File( manifestLocation, "MANIFEST.MF" );
92
93 try
94 {
95 writeManifest( manifest, outputFile );
96 }
97 catch ( IOException e )
98 {
99 throw new MojoExecutionException( "Error trying to write Manifest to file " + outputFile, e );
100 }
101 }
102
103
104 public Manifest getManifest( MavenProject project, Jar[] classpath ) throws IOException, MojoFailureException,
105 MojoExecutionException, Exception
106 {
107 return getManifest( project, new LinkedHashMap(), new Properties(), classpath );
108 }
109
110
111 public Manifest getManifest( MavenProject project, Map instructions, Properties properties, Jar[] classpath )
112 throws IOException, MojoFailureException, MojoExecutionException, Exception
113 {
114 Analyzer analyzer = getAnalyzer( project, instructions, properties, classpath );
115 boolean hasErrors = reportErrors( "Manifest " + project.getArtifact(), analyzer );
116 if ( hasErrors )
117 {
118 String failok = analyzer.getProperty( "-failok" );
119 if ( null == failok || "false".equalsIgnoreCase( failok ) )
120 {
121 throw new MojoFailureException( "Error(s) found in manifest configuration" );
122 }
123 }
124
125 Jar jar = analyzer.getJar();
126
127 if ( unpackBundle )
128 {
129 File outputFile = getOutputDirectory();
130 for ( Entry<String, Resource> entry : jar.getResources().entrySet() )
131 {
132 File entryFile = new File( outputFile, entry.getKey() );
133 if ( !entryFile.exists() || entry.getValue().lastModified() == 0 )
134 {
135 entryFile.getParentFile().mkdirs();
136 OutputStream os = new FileOutputStream( entryFile );
137 entry.getValue().write( os );
138 os.close();
139 }
140 }
141 }
142
143 Manifest manifest = jar.getManifest();
144
145
146 analyzer.close();
147
148 return manifest;
149 }
150
151
152 protected Analyzer getAnalyzer( MavenProject project, Jar[] classpath ) throws IOException, MojoExecutionException,
153 Exception
154 {
155 return getAnalyzer( project, new LinkedHashMap(), new Properties(), classpath );
156 }
157
158
159 protected Analyzer getAnalyzer( MavenProject project, Map instructions, Properties properties, Jar[] classpath )
160 throws IOException, MojoExecutionException, Exception
161 {
162 if ( rebuildBundle && supportedProjectTypes.contains( project.getArtifact().getType() ) )
163 {
164 return buildOSGiBundle( project, instructions, properties, classpath );
165 }
166
167 File file = getOutputDirectory();
168 if ( file == null )
169 {
170 file = project.getArtifact().getFile();
171 }
172
173 if ( !file.exists() )
174 {
175 if ( file.equals( getOutputDirectory() ) )
176 {
177 file.mkdirs();
178 }
179 else
180 {
181 throw new FileNotFoundException( file.getPath() );
182 }
183 }
184
185 Builder analyzer = getOSGiBuilder( project, instructions, properties, classpath );
186
187 analyzer.setJar( file );
188
189
190
191
192
193 boolean isOutputDirectory = file.equals( getOutputDirectory() );
194
195 if ( analyzer.getProperty( Analyzer.EXPORT_PACKAGE ) == null
196 && analyzer.getProperty( Analyzer.EXPORT_CONTENTS ) == null
197 && analyzer.getProperty( Analyzer.PRIVATE_PACKAGE ) == null && !isOutputDirectory )
198 {
199 String export = calculateExportsFromContents( analyzer.getJar() );
200 analyzer.setProperty( Analyzer.EXPORT_PACKAGE, export );
201 }
202
203 addMavenInstructions( project, analyzer );
204
205
206 if ( analyzer.getProperty( DependencyEmbedder.EMBED_DEPENDENCY ) != null && isOutputDirectory )
207 {
208 analyzer.build();
209 }
210 else
211 {
212 analyzer.mergeManifest( analyzer.getJar().getManifest() );
213 analyzer.getJar().setManifest( analyzer.calcManifest() );
214 }
215
216 mergeMavenManifest( project, analyzer );
217
218 return analyzer;
219 }
220
221
222 public static void writeManifest( Manifest manifest, File outputFile ) throws IOException
223 {
224 outputFile.getParentFile().mkdirs();
225
226 FileOutputStream os;
227 os = new FileOutputStream( outputFile );
228 try
229 {
230 Jar.writeManifest( manifest, os );
231 }
232 finally
233 {
234 try
235 {
236 os.close();
237 }
238 catch ( IOException e )
239 {
240
241 }
242 }
243 }
244
245
246
247
248
249 public static String calculateExportsFromContents( Jar bundle )
250 {
251 String ddel = "";
252 StringBuffer sb = new StringBuffer();
253 Map<String, Map<String, Resource>> map = bundle.getDirectories();
254 for ( Iterator<Entry<String, Map<String, Resource>>> i = map.entrySet().iterator(); i.hasNext(); )
255 {
256
257
258
259 Entry<String, Map<String, Resource>> entry = i.next();
260 if ( entry.getValue() == null || entry.getValue().isEmpty() )
261 continue;
262
263 String directory = entry.getKey();
264 if ( directory.equals( "META-INF" ) || directory.startsWith( "META-INF/" ) )
265 continue;
266 if ( directory.equals( "OSGI-OPT" ) || directory.startsWith( "OSGI-OPT/" ) )
267 continue;
268 if ( directory.equals( "/" ) )
269 continue;
270
271 if ( directory.endsWith( "/" ) )
272 directory = directory.substring( 0, directory.length() - 1 );
273
274 directory = directory.replace( '/', '.' );
275 sb.append( ddel );
276 sb.append( directory );
277 ddel = ",";
278 }
279 return sb.toString();
280 }
281 }