1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.github.maven_nar;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.ArrayList;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28
29 import org.apache.bcel.classfile.ClassFormatException;
30 import org.apache.bcel.classfile.JavaClass;
31 import org.apache.bcel.classfile.Method;
32 import org.apache.maven.artifact.DependencyResolutionRequiredException;
33 import org.apache.maven.plugin.MojoExecutionException;
34 import org.apache.maven.plugin.MojoFailureException;
35 import org.apache.maven.plugins.annotations.Parameter;
36 import org.apache.maven.toolchain.Toolchain;
37 import org.apache.maven.toolchain.ToolchainManager;
38 import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
39 import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
40 import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
41 import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
42 import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
43 import org.codehaus.plexus.util.FileUtils;
44 import org.codehaus.plexus.util.StringUtils;
45
46
47
48
49
50
51 public class Javah {
52
53
54
55
56 @Parameter(defaultValue = "javah")
57 private String name = "javah";
58
59
60
61
62 @Parameter
63 private List
64
65
66
67
68
69 @Parameter
70 private List
71
72
73
74
75 @Parameter(defaultValue = "${project.build.directory}/nar/javah-include", required = true)
76 private File jniDirectory;
77
78
79
80
81 @Parameter(defaultValue = "${project.build.directory}/classes", required = true)
82 private File classDirectory;
83
84
85
86
87 @Parameter
88 private Set includes = new HashSet();
89
90
91
92
93 @Parameter
94 private Set excludes = new HashSet();
95
96
97
98
99 @Parameter
100 private Set extraClasses = new HashSet();
101
102
103
104
105
106 @Parameter(defaultValue = "0", required = true)
107 private int staleMillis = 0;
108
109
110
111
112
113 @Parameter
114 private File timestampDirectory;
115
116
117
118
119 @Parameter
120 private File timestampFile;
121
122 private AbstractNarMojo mojo;
123
124 public Javah() {
125 }
126
127 public final void execute() throws MojoExecutionException, MojoFailureException {
128 getClassDirectory().mkdirs();
129
130 try {
131 final SourceInclusionScanner scanner = new StaleSourceScanner(this.staleMillis, getIncludes(), this.excludes);
132 if (getTimestampDirectory().exists()) {
133 scanner.addSourceMapping(new SingleTargetSourceMapping(".class", getTimestampFile().getPath()));
134 } else {
135 scanner.addSourceMapping(new SuffixMapping(".class", ".dummy"));
136 }
137
138 final Set classes = scanner.getIncludedSources(getClassDirectory(), getTimestampDirectory());
139
140 if (!classes.isEmpty()) {
141 final Set files = new HashSet();
142 for (final Object aClass : classes) {
143 final String file = ((File) aClass).getPath();
144 final JavaClass clazz = NarUtil.getBcelClass(file);
145 final Method[] method = clazz.getMethods();
146 for (final Method element : method) {
147 if (element.isNative()) {
148 files.add(clazz.getClassName());
149 }
150 }
151 }
152
153 if (!files.isEmpty()) {
154 getJniDirectory().mkdirs();
155 getTimestampDirectory().mkdirs();
156
157 final String javah = getJavah();
158
159 this.mojo.getLog().info("Running " + javah + " compiler on " + files.size() + " classes...");
160 final int result = NarUtil.runCommand(javah, generateArgs(files), null, null, this.mojo.getLog());
161 if (result != 0) {
162 throw new MojoFailureException(javah + " failed with exit code " + result + " 0x"
163 + Integer.toHexString(result));
164 }
165 FileUtils.fileWrite(getTimestampDirectory() + "/" + getTimestampFile(), "");
166 }
167 }
168 } catch (final InclusionScanException e) {
169 throw new MojoExecutionException("JAVAH: Class scanning failed", e);
170 } catch (final IOException e) {
171 throw new MojoExecutionException("JAVAH: IO Exception", e);
172 } catch (final ClassFormatException e) {
173 throw new MojoExecutionException("JAVAH: Class could not be inspected", e);
174 }
175 }
176
177 private String[] generateArgs(final Set
178
179 final List args = new ArrayList();
180
181 if (!this.bootClassPaths.isEmpty()) {
182 args.add("-bootclasspath");
183 args.add(StringUtils.join(this.bootClassPaths.iterator(), File.pathSeparator));
184 }
185
186 args.add("-classpath");
187 args.add(StringUtils.join(getClassPaths().iterator(), File.pathSeparator));
188
189 args.add("-d");
190 args.add(getJniDirectory().getPath());
191
192 if (this.mojo.getLog().isDebugEnabled()) {
193 args.add("-verbose");
194 }
195
196 if (classes != null) {
197 for (final Object aClass : classes) {
198 args.add(aClass);
199 }
200 }
201
202 if (this.extraClasses != null) {
203 for (final Object extraClass : this.extraClasses) {
204 args.add(extraClass);
205 }
206 }
207
208 return (String[]) args.toArray(new String[args.size()]);
209 }
210
211 protected final File getClassDirectory() {
212 if (this.classDirectory == null) {
213 this.classDirectory = new File(this.mojo.getMavenProject().getBuild().getDirectory(), "classes");
214 }
215 return this.classDirectory;
216 }
217
218 protected final List getClassPaths() throws MojoExecutionException {
219 if (this.classPaths.isEmpty()) {
220 try {
221 this.classPaths.addAll(this.mojo.getMavenProject().getCompileClasspathElements());
222 } catch (final DependencyResolutionRequiredException e) {
223 throw new MojoExecutionException("JAVAH, cannot get classpath", e);
224 }
225 }
226 return this.classPaths;
227 }
228
229 protected final Set getIncludes() {
230 NarUtil.removeNulls(this.includes);
231 if (this.includes.isEmpty()) {
232 this.includes.add("**/*.class");
233 }
234 return this.includes;
235 }
236
237 private String getJavah() throws MojoExecutionException, MojoFailureException {
238 String javah = null;
239
240
241 final Toolchain toolchain = getToolchain();
242 if (toolchain != null) {
243 javah = toolchain.findTool("javah");
244 }
245
246
247 if (javah == null) {
248 final File javahFile = new File(this.mojo.getJavaHome(this.mojo.getAOL()), "bin");
249 javah = new File(javahFile, this.name).getAbsolutePath();
250 }
251
252
253 if (javah == null) {
254 throw new MojoExecutionException("NAR: Cannot find 'javah' in Toolchain or on JavaHome");
255 }
256
257 return javah;
258 }
259
260 protected final File getJniDirectory() {
261 if (this.jniDirectory == null) {
262 this.jniDirectory = new File(this.mojo.getMavenProject().getBuild().getDirectory(), "nar/javah-include");
263 }
264 return this.jniDirectory;
265 }
266
267 protected final File getTimestampDirectory() {
268 if (this.timestampDirectory == null) {
269 this.timestampDirectory = getJniDirectory();
270 }
271 return this.timestampDirectory;
272 }
273
274 protected final File getTimestampFile() {
275 if (this.timestampFile == null) {
276 this.timestampFile = new File(this.name);
277 }
278 return this.timestampFile;
279 }
280
281
282
283 private Toolchain getToolchain() {
284 Toolchain toolChain = null;
285 final ToolchainManager toolchainManager = ((NarJavahMojo) this.mojo).getToolchainManager();
286
287 if (toolchainManager != null) {
288 toolChain = toolchainManager.getToolchainFromBuildContext("jdk", ((NarJavahMojo) this.mojo).getSession());
289 }
290 return toolChain;
291 }
292
293 public final void setAbstractCompileMojo(final AbstractNarMojo abstractNarMojo) {
294 this.mojo = abstractNarMojo;
295 }
296 }