2
* Copyright (C) 2009 Progress Software, Inc.
3
* http://fusesource.com
5
* Licensed under the Apache License, Version 2.0 (the "License");
6
* you may not use this file except in compliance with the License.
7
* You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
17
package org.fusesource.hawtjni.maven;
20
import java.io.IOException;
21
import java.io.Reader;
23
import java.util.ArrayList;
24
import java.util.HashMap;
25
import java.util.List;
29
import org.apache.maven.artifact.Artifact;
30
import org.apache.maven.plugin.AbstractMojo;
31
import org.apache.maven.plugin.MojoExecutionException;
32
import org.apache.maven.project.MavenProject;
33
import org.codehaus.plexus.interpolation.InterpolatorFilterReader;
34
import org.codehaus.plexus.interpolation.MapBasedValueSource;
35
import org.codehaus.plexus.interpolation.StringSearchInterpolator;
36
import org.codehaus.plexus.util.FileUtils;
37
import org.codehaus.plexus.util.FileUtils.FilterWrapper;
38
import org.fusesource.hawtjni.generator.HawtJNI;
39
import org.fusesource.hawtjni.generator.ProgressMonitor;
42
* This goal generates the native source code and a
43
* autoconf/msbuild based build system needed to
44
* build a JNI library for any HawtJNI annotated
45
* classes in your maven project.
48
* @phase process-classes
49
* @author <a href="http://hiramchirino.com">Hiram Chirino</a>
51
public class GenerateMojo extends AbstractMojo {
56
* @parameter expression="${project}"
60
protected MavenProject project;
63
* The directory where the generated native source files are located.
65
* @parameter default-value="${project.build.directory}/generated-sources/hawtjni/native-src"
67
private File generatedNativeSourceDirectory;
70
* The base name of the library, used to determine generated file names.
72
* @parameter default-value="${project.artifactId}"
77
* The copyright header template that will be added to the generated source files.
78
* Use the '%END_YEAR%' token to have it replaced with the current year.
80
* @parameter default-value=""
82
private String copyright;
85
* Restrict looking for JNI classes to the specified package.
89
private List<String> packages = new ArrayList<String>();
92
* The directory where the java classes files are located.
94
* @parameter default-value="${project.build.outputDirectory}"
96
private File classesDirectory;
99
* The directory where the generated build package is located..
101
* @parameter default-value="${project.build.directory}/generated-sources/hawtjni/native-package"
103
private File packageDirectory;
106
* The list of additional files to be included in the package will be
109
* @parameter default-value="${basedir}/src/main/native-package"
111
private File customPackageDirectory;
114
* The text encoding of the files.
116
* @parameter default-value="UTF-8"
118
private String encoding;
121
* Should we skip executing the autogen.sh file.
123
* @parameter default-value="${skip-autogen}"
125
private boolean skipAutogen;
128
* Should we force executing the autogen.sh file.
130
* @parameter default-value="${force-autogen}"
132
private boolean forceAutogen;
135
* Should we display all the native build output?
137
* @parameter default-value="${hawtjni-verbose}"
139
private boolean verbose;
142
* Extra arguments you want to pass to the autogen.sh command.
146
private List<String> autogenArgs;
149
* Set this value to false to disable the callback support in HawtJNI.
150
* Disabling callback support can substantially reduce the size
151
* of the generated native library.
153
* @parameter default-value="true"
155
private boolean callbacks;
157
private File targetSrcDir;
159
private CLI cli = new CLI();
161
public void execute() throws MojoExecutionException {
162
cli.verbose = verbose;
164
generateNativeSourceFiles();
165
generateBuildSystem();
168
private void generateNativeSourceFiles() throws MojoExecutionException {
169
HawtJNI generator = new HawtJNI();
170
generator.setClasspaths(getClasspath());
171
generator.setName(name);
172
generator.setCopyright(copyright);
173
generator.setNativeOutput(generatedNativeSourceDirectory);
174
generator.setPackages(packages);
175
generator.setCallbacks(callbacks);
176
generator.setProgress(new ProgressMonitor() {
179
public void setTotal(int total) {
181
public void setMessage(String message) {
182
getLog().info(message);
186
generator.generate();
187
} catch (Exception e) {
188
throw new MojoExecutionException("Native source code generation failed: "+e, e);
192
private void generateBuildSystem() throws MojoExecutionException {
194
packageDirectory.mkdirs();
195
new File(packageDirectory, "m4").mkdirs();
196
targetSrcDir = new File(packageDirectory, "src");
197
targetSrcDir.mkdirs();
199
if( customPackageDirectory!=null && customPackageDirectory.isDirectory() ) {
200
FileUtils.copyDirectoryStructureIfModified(customPackageDirectory, packageDirectory);
203
if( generatedNativeSourceDirectory!=null && generatedNativeSourceDirectory.isDirectory() ) {
204
FileUtils.copyDirectoryStructureIfModified(generatedNativeSourceDirectory, targetSrcDir);
207
copyTemplateResource("readme.md", false);
208
copyTemplateResource("configure.ac", true);
209
copyTemplateResource("Makefile.am", true);
210
copyTemplateResource("m4/custom.m4", false);
211
copyTemplateResource("m4/jni.m4", false);
212
copyTemplateResource("m4/osx-universal.m4", false);
214
// To support windows based builds..
215
copyTemplateResource("vs2008.vcproj", true);
217
File autogen = new File(packageDirectory, "autogen.sh");
218
File configure = new File(packageDirectory, "configure");
219
if( !autogen.exists() ) {
220
copyTemplateResource("autogen.sh", false);
221
cli.setExecutable(autogen);
224
if( (!configure.exists() && !CLI.IS_WINDOWS) || forceAutogen ) {
226
cli.system(packageDirectory, new String[] {"./autogen.sh"}, autogenArgs);
227
} catch (Exception e) {
234
} catch (Exception e) {
235
throw new MojoExecutionException("Native build system generation failed: "+e, e);
239
@SuppressWarnings("unchecked")
240
private ArrayList<String> getClasspath() throws MojoExecutionException {
241
ArrayList<String> artifacts = new ArrayList<String>();
243
artifacts.add(classesDirectory.getCanonicalPath());
244
for (Artifact artifact : (Set<Artifact>) project.getArtifacts()) {
245
File file = artifact.getFile();
246
getLog().debug("Including: " + file);
247
artifacts.add(file.getCanonicalPath());
249
} catch (IOException e) {
250
throw new MojoExecutionException("Could not determine project classath.", e);
255
private void copyTemplateResource(String file, boolean filter) throws MojoExecutionException {
257
File target = FileUtils.resolveFile(packageDirectory, file);
258
if( target.isFile() && target.canRead() ) {
261
URL source = getClass().getClassLoader().getResource("project-template/" + file);
262
File tmp = FileUtils.createTempFile("tmp", "txt", new File(project.getBuild().getDirectory()));
264
FileUtils.copyURLToFile(source, tmp);
265
FileUtils.copyFile(tmp, target, encoding, filters(filter), true);
269
} catch (IOException e) {
270
throw new MojoExecutionException("Could not extract template resource: "+file, e);
274
@SuppressWarnings("unchecked")
275
private FilterWrapper[] filters(boolean filter) throws IOException {
277
return new FilterWrapper[0];
280
final String startExp = "@";
281
final String endExp = "@";
282
final String escapeString = "\\";
283
final Map<String,String> values = new HashMap<String,String>();
284
values.put("PROJECT_NAME", name);
285
values.put("PROJECT_NAME_UNDER_SCORE", name.replaceAll("\\W", "_"));
286
values.put("VERSION", project.getVersion());
288
List<String> files = new ArrayList<String>();
289
files.addAll(FileUtils.getFileNames(targetSrcDir, "**/*.c", null, false));
290
files.addAll(FileUtils.getFileNames(targetSrcDir, "**/*.cpp", null, false));
291
files.addAll(FileUtils.getFileNames(targetSrcDir, "**/*.cxx", null, false));
293
String xml_sources = "";
294
boolean first = true;
295
for (String f : files) {
299
values.put("FIRST_SOURCE_FILE", "src/"+f.replace('\\', '/'));
302
sources += " src/"+f;
304
xml_sources+=" <File RelativePath=\".\\src\\"+ (f.replace('/', '\\')) +"\"/>\n";
307
values.put("PROJECT_SOURCES", sources);
308
values.put("PROJECT_XML_SOURCES", xml_sources);
311
FileUtils.FilterWrapper wrapper = new FileUtils.FilterWrapper() {
312
public Reader getReader(Reader reader) {
313
StringSearchInterpolator propertiesInterpolator = new StringSearchInterpolator(startExp, endExp);
314
propertiesInterpolator.addValueSource(new MapBasedValueSource(values));
315
propertiesInterpolator.setEscapeString(escapeString);
316
InterpolatorFilterReader interpolatorFilterReader = new InterpolatorFilterReader(reader, propertiesInterpolator, startExp, endExp);
317
interpolatorFilterReader.setInterpolateWithPrefixPattern(false);
318
return interpolatorFilterReader;
321
return new FilterWrapper[] { wrapper };