1 package org.codehaus.mojo.natives.plugin;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 import java.io.File;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Enumeration;
28 import java.util.Iterator;
29 import java.util.List;
30 import java.util.zip.ZipEntry;
31 import java.util.zip.ZipFile;
32
33 import org.apache.bcel.classfile.ClassParser;
34 import org.apache.bcel.classfile.JavaClass;
35 import org.apache.bcel.classfile.Method;
36 import org.apache.maven.artifact.Artifact;
37 import org.apache.maven.plugin.MojoExecutionException;
38 import org.apache.maven.plugins.annotations.Component;
39 import org.apache.maven.plugins.annotations.LifecyclePhase;
40 import org.apache.maven.plugins.annotations.Mojo;
41 import org.apache.maven.plugins.annotations.Parameter;
42 import org.apache.maven.plugins.annotations.ResolutionScope;
43 import org.apache.maven.project.MavenProject;
44 import org.apache.maven.project.MavenProjectHelper;
45 import org.codehaus.mojo.natives.NativeBuildException;
46 import org.codehaus.mojo.natives.javah.Javah;
47 import org.codehaus.mojo.natives.javah.JavahConfiguration;
48 import org.codehaus.mojo.natives.manager.JavahManager;
49 import org.codehaus.mojo.natives.manager.NoSuchNativeProviderException;
50 import org.codehaus.plexus.archiver.util.DefaultFileSet;
51 import org.codehaus.plexus.archiver.zip.ZipArchiver;
52 import org.codehaus.plexus.util.FileUtils;
53 import org.codehaus.plexus.util.StringUtils;
54
55
56
57
58 @Mojo(name = "javah", defaultPhase = LifecyclePhase.GENERATE_SOURCES, requiresDependencyResolution = ResolutionScope.COMPILE)
59 public class NativeJavahMojo
60 extends AbstractNativeMojo
61 {
62
63
64
65
66
67 @Parameter(defaultValue = "default", required = true)
68 private String javahProvider;
69
70
71
72
73
74
75 @Parameter
76 private List javahClassNames = new ArrayList( 0 );
77
78
79
80
81
82 @Parameter(defaultValue = "false")
83 private boolean javahSearchJNIFromDependencies;
84
85
86
87
88
89
90 @Parameter
91 private File javahPath;
92
93
94
95
96
97 @Parameter(defaultValue = "${project.build.directory}/native/javah", required = true)
98 protected File javahOutputDirectory;
99
100
101
102
103
104 @Parameter
105 private String javahOutputFileName;
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121 @Parameter
122 private List javahIncludes = new ArrayList();
123
124
125
126
127
128 @Parameter(defaultValue = "false")
129 private boolean javahVerbose;
130
131
132
133
134 @Parameter(defaultValue = "false")
135 private boolean attach;
136
137
138
139
140 @Parameter(defaultValue = "javah")
141 private String classifier;
142
143
144
145
146
147 @Parameter(defaultValue = "${project.build.directory}/${project.build.finalName}.inczip", required = true)
148 private File incZipFile;
149
150
151
152
153
154
155 @Parameter(defaultValue = "false")
156 private boolean useEnvClasspath;
157
158
159
160
161
162
163 @Component
164 private JavahManager manager;
165
166
167
168
169
170 @Component
171 private MavenProjectHelper projectHelper;
172
173
174
175
176 private JavahConfiguration config;
177
178 public void execute()
179 throws MojoExecutionException
180 {
181
182 this.discoverAdditionalJNIClassName();
183
184 if ( this.javahClassNames.size() == 0 && this.javahIncludes.size() == 0 )
185 {
186 return;
187 }
188
189 try
190 {
191 if ( this.javahClassNames.size() != 0 )
192 {
193 this.config =
194 this.createProviderConfiguration( (String[]) javahClassNames.toArray( new String[javahClassNames.size()] ),
195 this.javahOutputFileName );
196 this.getJavah().compile( config );
197 }
198
199 for ( int i = 0; i < this.javahIncludes.size(); ++i )
200 {
201 JavahInclude javahInclude = (JavahInclude) this.javahIncludes.get( i );
202 this.config =
203 this.createProviderConfiguration( new String[] { javahInclude.getClassName() },
204 javahInclude.getHeaderName() );
205 this.getJavah().compile( config );
206 }
207
208 if ( this.attach )
209 {
210 attachGeneratedIncludeFilesAsIncZip();
211 }
212 }
213 catch ( NativeBuildException e )
214 {
215 throw new MojoExecutionException( "Error running javah command", e );
216 }
217
218 this.project.addCompileSourceRoot( this.javahOutputDirectory.getAbsolutePath() );
219
220 }
221
222 private void attachGeneratedIncludeFilesAsIncZip()
223 throws MojoExecutionException
224 {
225 try
226 {
227 ZipArchiver archiver = new ZipArchiver();
228 DefaultFileSet fileSet = new DefaultFileSet();
229 fileSet.setUsingDefaultExcludes( true );
230 fileSet.setDirectory( javahOutputDirectory );
231 archiver.addFileSet( fileSet );
232 archiver.setDestFile( this.incZipFile );
233 archiver.createArchive();
234
235 if ( StringUtils.isBlank( this.classifier ) )
236 {
237 projectHelper.attachArtifact( this.project, INCZIP_TYPE, null, this.incZipFile );
238 }
239 else
240 {
241 projectHelper.attachArtifact( this.project, INCZIP_TYPE, this.classifier, this.incZipFile );
242 }
243 }
244 catch ( Exception e )
245 {
246 throw new MojoExecutionException( "Unable to archive/deploy generated include files", e );
247 }
248 }
249
250 private Javah getJavah()
251 throws MojoExecutionException
252 {
253 Javah javah;
254
255 try
256 {
257 javah = this.manager.getJavah( this.javahProvider );
258
259 }
260 catch ( NoSuchNativeProviderException pe )
261 {
262 throw new MojoExecutionException( pe.getMessage() );
263 }
264
265 return javah;
266 }
267
268
269
270
271
272
273 private List getJavahArtifacts()
274 {
275 List list = new ArrayList();
276
277 List artifacts = this.project.getCompileArtifacts();
278
279 if ( artifacts != null )
280 {
281
282 for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
283 {
284 Artifact artifact = (Artifact) iter.next();
285
286
287 if ( !"jar".equals( artifact.getType() ) )
288 {
289 continue;
290 }
291
292
293 if ( Artifact.SCOPE_PROVIDED.equals( artifact.getScope() ) )
294 {
295 continue;
296 }
297
298 list.add( artifact );
299
300 }
301 }
302
303 return list;
304 }
305
306
307
308
309
310
311 private String[] getJavahClassPath()
312 {
313 List artifacts = this.getJavahArtifacts();
314
315 String[] classPaths = new String[artifacts.size() + 1];
316
317 classPaths[0] = this.project.getBuild().getOutputDirectory();
318
319 Iterator iter = artifacts.iterator();
320
321 for ( int i = 1; i < classPaths.length; ++i )
322 {
323 Artifact artifact = (Artifact) iter.next();
324
325 classPaths[i] = artifact.getFile().getPath();
326 }
327
328 return classPaths;
329 }
330
331
332
333
334
335 private void discoverAdditionalJNIClassName()
336 throws MojoExecutionException
337 {
338 if ( !this.javahSearchJNIFromDependencies )
339 {
340 return;
341 }
342
343
344
345 List artifacts = this.getJavahArtifacts();
346
347 for ( Iterator iter = artifacts.iterator(); iter.hasNext(); )
348 {
349 Artifact artifact = (Artifact) iter.next();
350
351 this.getLog().info( "Parsing " + artifact.getFile() + " for native classes." );
352
353 try
354 {
355 ZipFile zipFile = new ZipFile( artifact.getFile() );
356 Enumeration zipEntries = zipFile.entries();
357
358 while ( zipEntries.hasMoreElements() )
359 {
360 ZipEntry zipEntry = (ZipEntry) zipEntries.nextElement();
361
362 if ( "class".equals( FileUtils.extension( zipEntry.getName() ) ) )
363 {
364 ClassParser parser = new ClassParser( artifact.getFile().getPath(), zipEntry.getName() );
365
366 JavaClass clazz = parser.parse();
367
368 Method[] methods = clazz.getMethods();
369
370 for ( int j = 0; j < methods.length; ++j )
371 {
372 if ( methods[j].isNative() )
373 {
374 javahClassNames.add( clazz.getClassName() );
375
376 this.getLog().info( "Found native class: " + clazz.getClassName() );
377
378 break;
379 }
380 }
381 }
382 }
383
384
385 zipFile.close();
386 }
387 catch ( IOException ioe )
388 {
389 throw new MojoExecutionException( "Error searching for native class in " + artifact.getFile(), ioe );
390 }
391 }
392
393 }
394
395 private JavahConfiguration createProviderConfiguration( String[] classNames, String javahOutputFileName )
396 throws MojoExecutionException
397 {
398 JavahConfiguration config = new JavahConfiguration();
399 config.setWorkingDirectory( this.workingDirectory );
400 config.setVerbose( this.javahVerbose );
401 config.setOutputDirectory( this.javahOutputDirectory );
402 config.setFileName( javahOutputFileName );
403 config.setClassPaths( this.getJavahClassPath() );
404 config.setUseEnvClasspath( useEnvClasspath );
405 config.setClassNames( classNames );
406 config.setJavahPath( this.javahPath );
407
408 return config;
409 }
410
411
412
413
414
415
416 protected JavahConfiguration getJavahConfiguration()
417 {
418 return this.config;
419 }
420
421
422
423
424
425 protected MavenProject getProject()
426 {
427 return this.project;
428 }
429 }