Addjars Plugin을 개발하기 위해서 가장 먼저 Maven Project를 빈것을 하나 생성하고 그 다음에는 다음과 같이 pom.xml
파일을 생성합니다.
pom.xml 파일
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>io.datadynamics.maven.plugins</groupId> <artifactId>addjars-maven-plugin</artifactId> <version>1.0.0</version> <packaging>maven-plugin</packaging> <name>AddJars Maven Plugin</name> <description>Adds arbitrary jars to project's classpath</description> <prerequisites> <maven>3.0.3</maven> </prerequisites> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-project</artifactId> <version>2.2.1</version> </dependency> </dependencies> <licenses> <license> <name>The Apache Software License, Version 2.0</name> <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url> <distribution>repo</distribution> </license> </licenses> </project>
이 플러그인을 사용하기 위해서는 우선 다음과 같이 Maven POM에 Plugin을 정의하고 리소스 설정을 통해 JAR 파일이 있는 위치를 지정할 수 있도록 합니다.
플러그인 사용 방법
<plugin> <groupId>io.datadynamics.maven.plugins</groupId> <artifactId>addjars-maven-plugin</artifactId> <version>1.0.0</version> <executions> <execution> <goals> <goal>add-jars</goal> </goals> <configuration> <resources> <resource> <directory>${basedir}/lib</directory> <includes> <include>**/*.jar</include> </includes> <excludes> <exclude>${basedir}/lib/runtime/**/*.jar</exclude> </excludes> </resource> <resource> <directory>${basedir}/lib/runtime</directory> <scope>runtime</scope> </resource> </resources> </configuration> </execution> </executions> </plugin>
플러그인 설정에서 resource 설정 정보를 담고 있는 model 클래스인 JarResource.java
를 생성합니다.
JarResource.java
package io.datadynamics.maven.plugins.addjars; import java.io.File; import java.io.Serializable; import java.util.List; public class JarResource implements Serializable { private File directory; private String scope = "compile"; private List<String> includes; private List<String> excludes; public File getDirectory() { return directory; } public void setDirectory(File directory) { this.directory = directory; } public String getScope() { return scope; } public void setScope(String scope) { this.scope = scope; } public List<String> getIncludes() { return includes; } public void setIncludes(List<String> includes) { this.includes = includes; } public List<String> getExcludes() { return excludes; } public void setExcludes(List<String> excludes) { this.excludes = excludes; } }
이제 가장 중요한 Maven Plugin의 Mojo라 불리우는 플러그의 단위 기능을 작성할 차례입니다.
AddJarsMojo.java
package io.datadynamics.maven.plugins.addjars; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.installer.ArtifactInstaller; import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Writer; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.project.MavenProject; import org.apache.maven.project.artifact.ProjectArtifactMetadata; import org.codehaus.plexus.util.DirectoryScanner; import org.codehaus.plexus.util.WriterFactory; import java.io.File; import java.io.IOException; import java.io.Writer; import java.util.*; /** * Adds arbitrary jars to project's classpath. * * @goal add-jars * @phase generate-sources */ public class AddJarsMojo extends AbstractMojo { /** * @parameter * @required * @readonly */ private List<JarResource> resources; /** * @parameter property="${project}" * @required * @readonly */ private MavenProject project; /** * @component */ private ArtifactFactory artifactFactory; /** * @component */ private ArtifactInstaller artifactInstaller; @Override public void execute() throws MojoExecutionException, MojoFailureException { try { executeInt(); } catch (MojoFailureException e) { throw e; } catch (MojoExecutionException e) { throw e; } catch (Exception e) { throw new MojoExecutionException(e.getMessage(), e); } } private void executeInt() throws Exception { // Maven 빌드 디렉토리에 임의의 경로를 생성한다. File workdir = new File(project.getBuild().getDirectory(), getClass().getName()); workdir.mkdirs(); // JAR 파일을 실제로 존재하지 않지만 실제로 존재하는 것처럼 꾸며서 생성한 Dependency 목록 Set<Artifact> dependenciesArtifacts = new HashSet<Artifact>(); // Plugin의 Resource 설정을 통해 모든 JAR 파일을 가져온다. for (JarResource resource : resources) { for (File jar : getJars(resource)) { // JAR 파일명과 Plugin을 사용한 Project Group ID를 바탕으로 JAR 파일의 Artifact를 생성한다. Artifact a = artifactFactory.createArtifact(project.getGroupId(), project.getArtifactId() + "-" + jar.getName(), project.getVersion(), resource.getScope(), "jar"); // 각 Artifact의 POM을 생성한다. File stamp = new File(workdir, a.getArtifactId()); if (jar.lastModified() > stamp.lastModified()) { a.addMetadata(new ProjectArtifactMetadata(a, createArtifactPom(a))); artifactInstaller.install(jar, a, null); stamp.createNewFile(); stamp.setLastModified(jar.lastModified()); } dependenciesArtifacts.add(a); } } // 프로젝트의 모든 Dependency를 가지고 와서 임의로 추가한 Artifact 목록에 함께 추가한다. Set newDependenciesArtifacts = new HashSet(project.getDependencyArtifacts()); newDependenciesArtifacts.addAll(dependenciesArtifacts); project.setDependencyArtifacts(newDependenciesArtifacts); for (Artifact dependency : dependenciesArtifacts) { project.getOriginalModel().addDependency(createDependency(dependency)); } // 새로운 POM을 생성한다. File pomFile = new File(workdir, "pom.xml"); writePom(pomFile, project.getOriginalModel()); project.setFile(pomFile); } /** * Plugin의 Resource 설정 정보를 기반으로 JAR 파일을 찾아서 반환한다. * * @param resource Maven POM에 정의되어 있는 Plugin의 Resource 설정 * @return JAR 파일목록 * @throws IOException */ private List<File> getJars(JarResource resource) throws IOException { DirectoryScanner scanner = new DirectoryScanner(); scanner.setBasedir(resource.getDirectory()); if (resource.getIncludes() != null) { scanner.setIncludes(resource.getIncludes().toArray(new String[]{})); } if (resource.getExcludes() != null) { scanner.setExcludes(resource.getExcludes().toArray(new String[]{})); } try { scanner.scan(); } catch (IllegalStateException e) { getLog().warn("디렉토리가 아닙니다 : " + resource.getDirectory()); return Collections.emptyList(); } List<File> files = new ArrayList<File>(); for (String file : scanner.getIncludedFiles()) { File f = new File(resource.getDirectory(), file).getCanonicalFile(); if (f.getName().endsWith(".jar")) { files.add(f); } else { getLog().warn("JAR 파일이 아닙니다 : " + f); } } Collections.sort(files); return files; } private Dependency createDependency(Artifact a) { Dependency d = new Dependency(); d.setGroupId(a.getGroupId()); d.setArtifactId(a.getArtifactId()); d.setVersion(a.getVersion()); d.setScope(a.getScope()); d.setType(a.getType()); return d; } private File createArtifactPom(Artifact a) throws IOException { File pomFile = File.createTempFile(a.getArtifactId(), ".pom"); writePom(pomFile, createModel(a)); return pomFile; } private Model createModel(Artifact a) { Model model = new Model(); model.setModelVersion("4.0.0"); model.setGroupId(a.getGroupId()); model.setArtifactId(a.getArtifactId()); model.setVersion(a.getVersion()); model.setPackaging(a.getType()); return model; } private void writePom(File pom, Model model) throws IOException { Writer writer = WriterFactory.newXmlWriter(pom); new MavenXpp3Writer().write(writer, model); writer.close(); } }
모든 작업이 완료되면 이제 Maven Plugin을 사용할 수 있도록 빌드합니다. 로컬에서 테스트할 때에는 mvn install
을 통해서 수행하고 Maven Repository 서버에 배포를 하는 경우는 mvn deploy
커맨드를 하도록 합니다.
# mvn -Dmaven.test.skip=true install