001/**
002 * Copyright (C) 2009-2011 FuseSource Corp.
003 * http://fusesource.com
004 * 
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 * 
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 * 
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.fusesource.hawtjni.maven;
018
019import java.io.File;
020import java.util.List;
021
022import org.apache.maven.plugin.AbstractMojo;
023import org.apache.maven.plugin.MojoExecutionException;
024import org.apache.maven.plugins.annotations.Component;
025import org.apache.maven.plugins.annotations.LifecyclePhase;
026import org.apache.maven.plugins.annotations.Mojo;
027import org.apache.maven.plugins.annotations.Parameter;
028import org.apache.maven.project.MavenProject;
029import org.apache.maven.project.MavenProjectHelper;
030import org.codehaus.plexus.archiver.jar.JarArchiver;
031import org.codehaus.plexus.archiver.jar.Manifest;
032import org.codehaus.plexus.archiver.jar.Manifest.Attribute;
033import org.codehaus.plexus.archiver.manager.ArchiverManager;
034import org.fusesource.hawtjni.runtime.Library;
035
036/**
037 * This goal allows allows you to package the JNI library created by build goal
038 * in a JAR which the HawtJNI runtime can unpack when the library needs to be
039 * loaded.
040 * 
041 * This platform specific jar is attached with a classifier which matches the
042 * current platform.
043 * 
044 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
045 */
046@Mojo(name = "package-jar", defaultPhase = LifecyclePhase.PREPARE_PACKAGE)
047public class PackageJarMojo extends AbstractMojo {
048
049    /**
050     * The maven project.
051     */
052    @Parameter(defaultValue = "${project}", readonly = true)
053    protected MavenProject project;
054
055    /**
056     * The base name of the library, used to determine generated file names.
057     */
058    @Parameter(defaultValue = "${project.artifactId}")
059    private String name;
060
061    /**
062     */
063    @Component
064    private ArchiverManager archiverManager;
065
066    /**
067     */
068    @Component
069    private MavenProjectHelper projectHelper;
070
071    /**
072     * The output directory where the built JNI library will placed. This
073     * directory will be added to as a test resource path so that unit tests can
074     * verify the built JNI library.
075     * 
076     * The library will placed under the META-INF/native/${platform} directory
077     * that the HawtJNI Library uses to find JNI libraries as classpath
078     * resources.
079     */
080    @Parameter(defaultValue = "${project.build.directory}/generated-sources/hawtjni/lib")
081    private File libDirectory;
082    
083    /**
084     * The platform identifier of this build.  If not specified,
085     * it will be automatically detected.
086     * 
087     * @parameter
088     */
089    @Parameter
090    private String platform;     
091
092    /**
093     * Should a classifier of the native jar be set
094     * to match the platform?
095     */
096    @Parameter(defaultValue = "true")
097    private boolean classified;
098
099    /**
100     * The osgi platforms that the library match for.  Example value:
101     * osname=MacOS;processor=x86-64
102     */
103    @Parameter
104    private List<String> osgiPlatforms;
105
106    public void execute() throws MojoExecutionException {
107        try {
108
109            Library library = new Library(name);
110            if (platform == null) {
111                platform = Library.getPlatform();
112            }
113
114            String classifier = null;
115            if( classified ) {
116                classifier = platform;
117
118                String packageName = project.getArtifactId() + "-" + project.getVersion() + "-" + platform;
119                JarArchiver archiver = (JarArchiver) archiverManager.getArchiver("jar");
120
121                File packageFile = new File(new File(project.getBuild().getDirectory()), packageName + ".jar");
122                archiver.setDestFile(packageFile);
123                archiver.setIncludeEmptyDirs(true);
124                archiver.addDirectory(libDirectory);
125
126                Manifest manifest = new Manifest();
127                manifest.addConfiguredAttribute(new Attribute("Bundle-SymbolicName", project.getArtifactId() + "-" + platform));
128                manifest.addConfiguredAttribute(new Attribute("Bundle-Name", name + " for " + platform));
129                manifest.addConfiguredAttribute(new Attribute("Bundle-NativeCode", getNativeCodeValue(library)));
130                manifest.addConfiguredAttribute(new Attribute("Bundle-Version", project.getVersion()));
131                manifest.addConfiguredAttribute(new Attribute("Bundle-ManifestVersion", "2"));
132                manifest.addConfiguredAttribute(new Attribute("Bundle-Description", project.getDescription()));
133                archiver.addConfiguredManifest(manifest);
134
135                archiver.createArchive();
136
137                projectHelper.attachArtifact(project, "jar", classifier, packageFile);
138
139            } else {
140                projectHelper.addResource(project, libDirectory.getCanonicalPath(), null, null);
141            }
142
143        } catch (Exception e) {
144            throw new MojoExecutionException("packaging failed: " + e, e);
145        }
146    }
147    
148    public String getNativeCodeValue(Library library) {
149        if (osgiPlatforms == null || osgiPlatforms.isEmpty() ) {
150            return library.getPlatformSpecificResourcePath(platform) + ";" +"osname=" + getOsgiOSName() + ";processor=" + getOsgiProcessor()+ ",*";
151        }
152        boolean first=true;
153        String rc = "";
154        for (String s : osgiPlatforms) {
155            if( !first ) {
156                rc += ",";
157            }
158            first = false;
159            if( "*".equals(s) ) {
160                rc += s;
161            } else {
162                rc += library.getPlatformSpecificResourcePath(platform) + ";"+s;
163            }
164        }
165        return rc;
166    }
167
168    public String getOsgiOSName() {
169        String name = System.getProperty("os.name");
170
171        String trimmed = name.toLowerCase().trim();
172        if (trimmed.startsWith("win")) {
173            return "Win32";
174        } else if (trimmed.startsWith("linux")) {
175            return "Linux";
176        } else if (trimmed.startsWith("macos") || trimmed.startsWith("mac os")) {
177            return "MacOS";
178        } else if (trimmed.startsWith("aix")) {
179            return "AIX";
180        } else if (trimmed.startsWith("hpux")) {
181            return "HPUX";
182        } else if (trimmed.startsWith("irix")) {
183            return "IRIX";
184        } else if (trimmed.startsWith("netware")) {
185            return "Netware";
186        } else if (trimmed.startsWith("openbsd")) {
187            return "OpenBSD";
188        } else if (trimmed.startsWith("netbsd")) {
189            return "NetBSD";
190        } else if (trimmed.startsWith("os2") || trimmed.startsWith("os/2")) {
191            return "OS2";
192        } else if (trimmed.startsWith("qnx") || trimmed.startsWith("procnto")) {
193            return "QNX";
194        } else if (trimmed.startsWith("solaris")) {
195            return "Solaris";
196        } else if (trimmed.startsWith("sunos")) {
197            return "SunOS";
198        } else if (trimmed.startsWith("vxworks")) {
199            return "VxWorks";
200        }
201        return name;
202    }
203
204    public String getOsgiProcessor() {
205        String name = System.getProperty("os.arch");
206        String trimmed = name.toLowerCase().trim();
207        if (trimmed.startsWith("x86-64") || trimmed.startsWith("amd64") || trimmed.startsWith("em64") || trimmed.startsWith("x86_64")) {
208            return "x86-64";
209        } else if (trimmed.startsWith("x86") || trimmed.startsWith("pentium") || trimmed.startsWith("i386") 
210                || trimmed.startsWith("i486") || trimmed.startsWith("i586") || trimmed.startsWith("i686")) {
211            return "x86";
212        } else if (trimmed.startsWith("68k")) {
213            return "68k";
214        } else if (trimmed.startsWith("arm")) {
215            return "ARM";
216        } else if (trimmed.startsWith("alpha")) {
217            return "Alpha";
218        } else if (trimmed.startsWith("ignite") || trimmed.startsWith("psc1k")) {
219            return "Ignite";
220        } else if (trimmed.startsWith("mips")) {
221            return "Mips";
222        } else if (trimmed.startsWith("parisc")) {
223            return "PArisc";
224        } else if (trimmed.startsWith("powerpc") || trimmed.startsWith("power") || trimmed.startsWith("ppc")) {
225            return "PowerPC";
226        } else if (trimmed.startsWith("sparc")) {
227            return "Sparc";
228        }
229        return name;
230    }
231
232}