package xapi.mvn.impl; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.StringReader; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.apache.maven.repository.internal.MavenRepositorySystemUtils; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.RepositorySystem; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory; import org.eclipse.aether.impl.DefaultServiceLocator; import org.eclipse.aether.repository.LocalArtifactRequest; import org.eclipse.aether.repository.LocalArtifactResult; import org.eclipse.aether.repository.LocalRepository; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactRequest; import org.eclipse.aether.resolution.ArtifactResolutionException; import org.eclipse.aether.resolution.ArtifactResult; import org.eclipse.aether.spi.connector.RepositoryConnectorFactory; import org.eclipse.aether.spi.connector.transport.TransporterFactory; import org.eclipse.aether.transport.file.FileTransporterFactory; import org.eclipse.aether.transport.http.HttpTransporterFactory; import xapi.annotation.inject.SingletonDefault; import xapi.collect.impl.AbstractMultiInitMap; import xapi.dev.resource.impl.StringDataResource; import xapi.dev.scanner.X_Scanner; import xapi.dev.scanner.impl.ClasspathResourceMap; import xapi.inject.impl.SingletonInitializer; import xapi.log.X_Log; import xapi.log.api.LogLevel; import xapi.mvn.service.MvnService; import xapi.time.X_Time; import xapi.time.api.Moment; import xapi.util.X_Debug; import xapi.util.X_String; import xapi.util.X_Util; @SingletonDefault(implFor = MvnService.class) public class MvnServiceDefault implements MvnService { public MvnServiceDefault() { } private static final Pattern POM_PATTERN = Pattern.compile(".*pom.*xml"); protected final DefaultServiceLocator maven = MavenRepositorySystemUtils.newServiceLocator(); protected final SingletonInitializer<RepositorySystem> repoSystem = new SingletonInitializer<RepositorySystem>() { @Override protected RepositorySystem initialValue() { // use netty to stream from maven maven.addService( RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class ); maven.addService( TransporterFactory.class, FileTransporterFactory.class ); maven.addService( TransporterFactory.class, HttpTransporterFactory.class ); return maven.getService(RepositorySystem.class); } }; @Override public RepositorySystemSession getRepoSession() { return session.get(); } protected final SingletonInitializer<RepositorySystemSession> session = new SingletonInitializer<RepositorySystemSession>() { @Override protected RepositorySystemSession initialValue() { return initLocalRepo(); } }; private LogLevel logLevel = LogLevel.INFO; private final class ResourceMap extends AbstractMultiInitMap<Integer, ClasspathResourceMap, ClassLoader> { @SuppressWarnings("unchecked") public ResourceMap() { super(TO_STRING); } @Override protected ClasspathResourceMap initialize(Integer key, ClassLoader params) { return X_Scanner.scanClassloader(params); } } @Override public ArtifactResult loadArtifact(String groupId, String artifactId, String version) { return loadArtifact(groupId, artifactId, "", "jar", version); } @Override public ArtifactResult loadArtifact(String groupId, String artifactId, String classifier, String extension, String version) { Moment before = X_Time.now(); RepositorySystem repoSystem = this.repoSystem.get(); RepositorySystemSession session = this.session.get(); DefaultArtifact artifact = new DefaultArtifact( groupId,artifactId,classifier, X_String.isEmpty(extension) ? "jar" : extension, version); try { ArtifactRequest request = new ArtifactRequest(artifact, remoteRepos(), null); return repoSystem.resolveArtifact(session, request); } catch (ArtifactResolutionException e) { X_Log.log(getClass(), getLogLevel(), "Resolved? ", e.getResult().isResolved(), e.getResult().getExceptions()); X_Log.log(getClass(), getLogLevel(), "Could not download " + artifact, e); throw X_Debug.rethrow(e); } finally { if (X_Log.loggable(LogLevel.DEBUG)) { X_Log.debug("Resolved: " + artifact.toString() + " in " + X_Time.difference(before)); } } } @Override public LocalArtifactResult loadLocalArtifact(String groupId, String artifactId, String version) { return loadLocalArtifact(groupId, artifactId, "", "jar", version); } @Override public LocalArtifactResult loadLocalArtifact(String groupId, String artifactId, String classifier, String extension, String version) { Moment before = X_Time.now(); RepositorySystemSession session = this.session.get(); DefaultArtifact artifact = new DefaultArtifact( groupId,artifactId,classifier, X_String.isEmpty(extension) ? "jar" : extension, version); try { LocalArtifactRequest request = new LocalArtifactRequest(artifact, null, null); return session.getLocalRepositoryManager().find(session, request); } finally { if (X_Log.loggable(LogLevel.DEBUG)) { X_Log.debug("Resolved: " + artifact.toString() + " in " + X_Time.difference(before)); } } } protected LogLevel getLogLevel() { return logLevel; } @Override public void setLogLevel(LogLevel logLevel) { this.logLevel = logLevel; } protected RepositorySystemSession initLocalRepo() { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); String userHome = System.getProperty("user.home"); String path = "target/local-repo"; if (userHome != null) { File maybeUse = new File(userHome, ".m2/repository"); if (maybeUse.exists()) { path = maybeUse.getAbsolutePath(); } } LocalRepository localRepo = new LocalRepository(path); localRepo.getBasedir().mkdirs(); session.setLocalRepositoryManager(repoSystem.get() .newLocalRepositoryManager(session, localRepo)); return session; } @Override public Model loadPomFile(String pomLocation) throws IOException, XmlPullParserException { File pomfile = new File(pomLocation); FileReader reader = null; MavenXpp3Reader mavenreader = new MavenXpp3Reader(); reader = new FileReader(pomfile); Model model = mavenreader.read(reader); model.setPomFile(pomfile); return model; } @Override public Model loadPomString(String pomString) throws XmlPullParserException { try { return new MavenXpp3Reader().read(new StringReader(pomString)); } catch (IOException ignored) { throw X_Util.rethrow(ignored); } } @Override public String mvnHome() { return System.getenv("M2_HOME"); } @Override public String localRepo() { return session.get().getLocalRepository().getBasedir().getAbsolutePath(); } @Override public List<RemoteRepository> remoteRepos() { return Arrays.asList(new RemoteRepository .Builder("maven-central", "default", "http://repo1.maven.org/maven2/") .build() ); } private final ResourceMap loaded = new ResourceMap(); @Override public Iterable<Model> findPoms(final ClassLoader loader) { final Iterable<StringDataResource> poms = loaded.get(loader.hashCode(), loader).findResources("", POM_PATTERN); class Itr implements Iterator<Model> { Iterator<StringDataResource> iterator = poms.iterator(); @Override public boolean hasNext() { return iterator.hasNext(); } @Override public Model next() { StringDataResource next = iterator.next(); try { return loadPomString(next.readAll()); } catch (Exception e) { X_Log.error("Unable to load resouce " + next.getResourceName(), e); throw X_Util.rethrow(e); } } @Override public void remove() { throw new UnsupportedOperationException(); } } return new Iterable<Model>() { @Override public Iterator<Model> iterator() { return new Itr(); } }; } }