Java tutorial
package org.jfrog.jade.plugins.natives.plugin; /* * The MIT License * * Copyright (c) 2004, The Codehaus * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.resolver.ArtifactNotFoundException; import org.apache.maven.artifact.resolver.ArtifactResolutionException; import org.apache.maven.artifact.resolver.filter.ArtifactFilter; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.apache.tools.ant.Project; import org.apache.tools.ant.taskdefs.Expand; import org.apache.tools.ant.types.PatternSet; import org.codehaus.mojo.natives.NativeBuildException; import org.codehaus.mojo.natives.NativeSources; import org.codehaus.mojo.natives.compiler.Compiler; import org.codehaus.mojo.natives.compiler.CompilerConfiguration; import org.codehaus.mojo.natives.manager.CompilerManager; import org.codehaus.mojo.natives.manager.NoSuchNativeProviderException; import org.codehaus.plexus.util.StringUtils; import org.jfrog.jade.plugins.multijar.Multijar; import org.jfrog.maven.annomojo.annotations.MojoGoal; import org.jfrog.maven.annomojo.annotations.MojoParameter; import org.jfrog.maven.annomojo.annotations.MojoPhase; import org.jfrog.maven.annomojo.annotations.MojoRequiresDependencyResolution; import java.io.File; import java.util.*; /** * Compile source files into native object files * * @author <a href="dantran@gmail.com">Dan T. Tran</a> * @author Fred Simon * @version $Id: NativeCompileMojo.java 2436 2006-09-29 13:54:03Z dantran $ */ @MojoGoal("compile") @MojoPhase("compile") @MojoRequiresDependencyResolution public class NativeCompileMojo extends AbstractNativeMojo { @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(description = "Use this field to override object file extension.\n" + "The default extenstions are .obj and .o on Windows and Unix respectively") private String objectFileExtension; @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(description = "Use this field to override provider specific compiler executable") private String compilerExecutable; @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(description = "Compiler options to produce shared libraries. Activated when shared flag is on.") private List<String> compilerSharedOptions; @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(description = "Compiler options to compile in debug mode.") private List<String> compilerDebugOptions; @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(description = "Compiler Start options to produce native object file") private List<String> compilerStartOptions; @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(description = "Compiler Middle options to produce native object file") private List<String> compilerMiddleOptions; @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(description = "Compiler End options to produce native object file") private List<String> compilerEndOptions; @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(description = "Javah OS name.\n" + "${jdkIncludePath} and ${jdkIncludePath}/${javaOS} are added to system include path \n" + "when this field is set") private String javahOS; @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(defaultValue = "${java.home}/../include", description = "JDK native include directory") private File jdkIncludePath; @MojoParameter(description = "Array of NativeSources containing include directories and source files") protected List<NativeSources> sources = new ArrayList<NativeSources>(); @SuppressWarnings({ "UnusedDeclaration" }) @MojoParameter(expression = "${component.org.codehaus.mojo.natives.manager.CompilerManager}", required = true, readonly = true, description = "Internal compiler manager") private CompilerManager manager; @MojoParameter(description = "Flag enabling the deployment and retrieval of include zip files") private boolean deployInclude = false; @MojoParameter(description = "The pattern for creating the zip file containing the \".h\" files.\nThe default is \"**/*.h\"", defaultValue = "**/*.h") private String includesPattern; @MojoParameter(description = "The file extension containing the .h files.", defaultValue = "zip") private String includesExtension; @MojoParameter(expression = "${includesRootDir}", defaultValue = "${project.build.directory}/includes", description = "The root directory where the XXX-include.zip files will be extracted") private File includesRootDir; @MojoParameter(expression = "${reactorProjects}", required = true, readonly = true) private List<MavenProject> reactorProjects; @MojoParameter(description = "List of options that are inserted when compiling with debug information.\n" + "It should be declared the following way:\n" + "<debugOptions>\n\t<option>-option1</option>\n...\n</debugOptions>") private boolean debugOptions = true; @MojoParameter(description = "The maximum amount of paralell threads to activated when doing compilation") private int nbParallelCompilation = 0; @MojoParameter(description = "Additional environments values used before execution of the compile Command.") private Map<String, String> compileSystemProperties = new HashMap<String, String>(); @MojoParameter(description = "The root folder for ALL object files output. The default value is ${project.build.directory}/obj.\n" + "If it is set to something else the plugin will create all obj files under ${objOutputDir}/$artifactId-$version/[debug,release,test]", expression = "${objRootOutputDir}", required = true, defaultValue = "${project.build.directory}/obj") private File objRootOutputDir; @MojoParameter(description = "Flag to activate the transitive parsing of C/C++ files for #include statements in " + "order to generate real up-to-date flag. If obj file older than ALL .h files than up-to-date.\n" + "Deactivating this falg will make the native plugin use the configured up-to-date manager which will check the date" + " between the obj and C file like in standard make (faster).", defaultValue = "true", expression = "${useTransitiveScanning}") private boolean useTransitiveScanning = true; private File objProjectOutputDir; private File objFinalOutputDir; private static final String INCLUDE_CLASSIFIER = "include"; public void execute() throws MojoExecutionException { if (isSkipped()) { return; } File sourceDir = getCompileSourceDir(); addCppSourceDirectory(sourceDir); List sourceRoots = getProject().getCompileSourceRoots(); if (sourceRoots != null) { for (Object path : sourceRoots) { String sPath = (String) path; if (sPath != null && sPath.length() > 0) { File dir = new File(sPath); if (dir.exists()) addCppSourceDirectory(dir); } } } List<Multijar> includesBuilder = null; if (isDeployInclude()) { File jarFile = null; for (NativeSources source : sources) { if (source.getDependencyAnalysisParticipation()) { if (includesBuilder == null) { includesBuilder = new ArrayList<Multijar>(); } Multijar includesZipper = createIncludesZipper(source, jarFile); includesBuilder.add(includesZipper); includesZipper.initFromMojo(this, null); if (jarFile == null) { jarFile = includesZipper.getJarfile(); } } } if (jarFile == null) { throw new MojoExecutionException( "Cannot create zip of include files if no sourcedirectory are defined"); } } Compiler compiler; try { compiler = this.manager.getCompiler(getCompilerProvider()); } catch (NoSuchNativeProviderException pe) { throw new MojoExecutionException(pe.getMessage(), pe); } if (this.javahOS != null) { this.addJavaHIncludePaths(); } this.addDependantIncludePath(getIncludesArtifactFilter()); CompilerConfiguration config = this.createProviderConfiguration(); List<File> objectFiles; try { objectFiles = compiler.compile(config, NativeSources.getAllSourceFiles(this.sources)); } catch (NativeBuildException e) { throw new MojoExecutionException(e.getMessage(), e); } this.saveCompilerOutputFilePaths(objectFiles); if (includesBuilder != null) { for (Multijar multijar : includesBuilder) { multijar.execute(); } } } public Multijar createIncludesZipper(NativeSources source, File jarFile) { Multijar includesZipper = new Multijar(); if (source.getExcludes() != null && !source.getExcludes().isEmpty()) { includesZipper.setExcludes(StringUtils.join(source.getExcludes().iterator(), ",")); } includesZipper.setIncludes(includesPattern); includesZipper.setSkippedIfUpToDate(true); if (jarFile == null) { includesZipper.setClassifier(INCLUDE_CLASSIFIER); includesZipper.setExtension(includesExtension); includesZipper.setDeploymentType(INCLUDE_CLASSIFIER); } else { includesZipper.setJarfile(jarFile); includesZipper.setClassifier(null); includesZipper.setExtension(includesExtension); includesZipper.setDeploymentType(null); includesZipper.setUpdateExisting(true); } includesZipper.setSkippedIfEmpty(false); includesZipper.setSourceDir(source.getDirectory()); return includesZipper; } private void addJavaHIncludePaths() { NativeSources jdkIncludeSource = new NativeSources(); jdkIncludeSource.setDirectory(this.jdkIncludePath); jdkIncludeSource.setDependencyAnalysisParticipation(false); sources.add(jdkIncludeSource); File jdkOsIncludeDir = new File(this.jdkIncludePath, this.javahOS); NativeSources jdkIncludeOsSource = new NativeSources(); jdkIncludeOsSource.setDirectory(jdkOsIncludeDir); jdkIncludeOsSource.setDependencyAnalysisParticipation(false); sources.add(jdkIncludeOsSource); } /** * Add include path from the list of dependant artifacts * * @param filter * @throws MojoExecutionException */ private void addDependantIncludePath(ArtifactFilter filter) throws MojoExecutionException { Collection<Artifact> allArtifacts = getProject().getArtifacts(); if (allArtifacts == null || allArtifacts.isEmpty()) { return; } // If no sources nothing to do? if (this.sources == null) { return; } for (Artifact artifact : allArtifacts) { if (filter.include(artifact)) { MavenProject reactorProject = findInReactorList(artifact); if (reactorProject != null) { List<Artifact> attachedArtifacts = reactorProject.getAttachedArtifacts(); for (Artifact attachedArtifact : attachedArtifacts) { if (attachedArtifact.getClassifier() != null && attachedArtifact.getClassifier().equals(INCLUDE_CLASSIFIER)) { addIncludeDirectory( extractIncludeZipFile(attachedArtifact, attachedArtifact.getFile())); break; } } } else { addIncludeDirectory(findAndExtractInclude(artifact)); } } } } public MavenProject findInReactorList(Artifact artifact) { for (MavenProject reactorProject : reactorProjects) { if (reactorProject.getGroupId().equals(artifact.getGroupId()) && reactorProject.getArtifactId().equals(artifact.getArtifactId()) && reactorProject.getVersion().equals(artifact.getVersion())) { return reactorProject; } } return null; } public void addIncludeDirectory(File includeDirectory) { if (includeDirectory == null || !includeDirectory.exists()) { return; } NativeSources genIncludeSource = new NativeSources(); genIncludeSource.setDirectory(includeDirectory); sources.add(genIncludeSource); } private File findAndExtractInclude(Artifact artifact) throws MojoExecutionException { File includeZipFile = null; try { // Resolve the artifact of include zip file Artifact includeZip = null; includeZip = getArtifactFactory().createArtifactWithClassifier(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), includesExtension, INCLUDE_CLASSIFIER); getArtifactResolver().resolve(includeZip, getProject().getRemoteArtifactRepositories(), getLocalRepository()); if (includeZip != null) { includeZipFile = includeZip.getFile(); } } catch (ArtifactResolutionException e) { getLog().info("Dependency " + artifact + " does not have an include zip file"); getLog().debug("Dependency " + artifact + " does not have an include zip file", e); } catch (ArtifactNotFoundException e) { getLog().info("Dependency " + artifact + " does not have an include zip file"); getLog().debug("Dependency " + artifact + " does not have an include zip file", e); } return extractIncludeZipFile(artifact, includeZipFile); } private File extractIncludeZipFile(Artifact artifact, File includeZipFile) throws MojoExecutionException { if (includeZipFile == null || !includeZipFile.exists()) { return null; } File includeDirectory; if (includesRootDir == null) { includesRootDir = new File(getProject().getBuild().getDirectory(), "includes"); } String versionName = getVersionName(artifact); includeDirectory = new File(includesRootDir, artifact.getArtifactId() + "-" + versionName); boolean executeUnzip = !includeDirectory.exists(); createFolder(includeDirectory); if (!executeUnzip) { // Check that the zip file is newer executeUnzip = includeZipFile.lastModified() >= includeDirectory.lastModified(); } if (executeUnzip) { // We use the Ant expand task Project antProject = getAntProject(); Expand expand = new Expand(); expand.setProject(antProject); expand.setDest(includeDirectory); expand.setSrc(includeZipFile); PatternSet noMetaInf = new PatternSet(); noMetaInf.setProject(antProject); PatternSet.NameEntry nameEntry = noMetaInf.createExclude(); nameEntry.setName("META-INF"); expand.addPatternset(noMetaInf); expand.execute(); includeDirectory.setLastModified(System.currentTimeMillis()); } return includeDirectory; } public File getObjRootOutputDir() { return objRootOutputDir; } public void setObjRootOutputDir(File objRootOutputDir) { this.objRootOutputDir = objRootOutputDir; } protected File getObjProjectOutputDir() throws MojoExecutionException { if (objProjectOutputDir == null) { File outputDir = getObjRootOutputDir(); if (outputDir == null) { outputDir = getOutputDirectory(); objProjectOutputDir = new File(outputDir, "obj"); } else { String versionName = getVersionName(getProject().getVersion()); objProjectOutputDir = new File(outputDir, getProject().getArtifactId() + "-" + versionName); } createFolder(objProjectOutputDir); } return objProjectOutputDir; } public File getObjFinalOutputDir() throws MojoExecutionException { if (objFinalOutputDir == null) { if (addDebugOptions()) createObjOutputSubDir("debug"); else createObjOutputSubDir("release"); } createFolder(objFinalOutputDir); return objFinalOutputDir; } protected void createObjOutputSubDir(String objOutputSubDir) throws MojoExecutionException { objFinalOutputDir = new File(getObjProjectOutputDir(), objOutputSubDir); } /* * use protected scope for unit test purpose */ protected CompilerConfiguration createProviderConfiguration() throws MojoExecutionException { this.config = new CompilerConfiguration(); config.setWorkingDirectory(getProject().getBasedir()); config.setExecutable(getCompilerExecutable()); List<String> startOptions = compilerStartOptions; if (addSharedOptions() && compilerSharedOptions != null) { startOptions = new ArrayList<String>(); if (compilerStartOptions != null) { startOptions.addAll(compilerStartOptions); } startOptions.addAll(compilerSharedOptions); } config.setStartOptions(removeEmptyOptions(startOptions)); List<String> middleOptions = compilerMiddleOptions; if (addDebugOptions() && compilerDebugOptions != null) { middleOptions = new ArrayList<String>(); if (compilerMiddleOptions != null) { middleOptions.addAll(compilerMiddleOptions); } middleOptions.addAll(compilerDebugOptions); } config.setMiddleOptions(removeEmptyOptions(middleOptions)); config.setEndOptions(removeEmptyOptions(this.compilerEndOptions)); config.setIncludePaths(NativeSources.getIncludePaths(sources)); config.setSystemIncludePaths(NativeSources.getSystemIncludePaths(sources)); config.setOutputDirectory(this.getObjFinalOutputDir()); config.setEnvFactoryName(this.envFactoryName); config.setSystemProperties(this.compileSystemProperties); config.setObjectFileExtension(this.objectFileExtension); config.setNbParallelCompilation(this.nbParallelCompilation); if (useTransitiveScanning) config.setUpToDateAnalyzer(null); else config.setUpToDateAnalyzer(this.getUpToDateManager().getUpToDateAnalyzer(this)); return config; } //////////////// Getter/Setters for plugin reuse //////////////////////////////// public List<NativeSources> getSources() { return sources; } public void setReactorProjects(List<MavenProject> reactorProjects) { this.reactorProjects = reactorProjects; } protected ArtifactFilter getIncludesArtifactFilter() { return new ArtifactFilter() { public boolean include(Artifact artifact) { String scope = getFailSafeScope(artifact); return NativeNameProvider.isLibrary(artifact) && !scope.equals(Artifact.SCOPE_RUNTIME) && !scope.equals(Artifact.SCOPE_TEST); } }; } protected File getCompileSourceDir() { String pathname = getProject().getBuild().getSourceDirectory(); if (pathname == null || pathname.length() == 0) { return null; } return new File(pathname); } public boolean isDeployInclude() { return deployInclude; } public boolean addDebugOptions() { return debugOptions; } public void addCppSourceDirectory(File sourceDir) { if (sourceDir == null) { return; } // First check if not already there for (NativeSources source : sources) { if (source.getDirectory().getAbsoluteFile().equals(sourceDir.getAbsoluteFile())) { return; } } NativeSources projectSources = new NativeSources(); projectSources.setDirectory(sourceDir); projectSources.addInclude("**/*.c"); projectSources.addInclude("**/*.cpp"); projectSources.setDependencyAnalysisParticipation(true); sources.add(projectSources); } public String getCompilerExecutable() { return compilerExecutable; } ////////////////////////////////////// UNIT TEST HELPERS //////////////////////////////// /** * For unittest only */ private CompilerConfiguration config; /** * Internal only for test harness purpose * * @return */ protected CompilerConfiguration getCompilerConfiguration() { return this.config; } }