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