package de.saumya.mojo.mavengem; import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.nio.file.NoSuchFileException; import org.sonatype.nexus.ruby.FileType; import org.sonatype.nexus.ruby.GemArtifactFile; import org.sonatype.nexus.ruby.IOUtil; import org.sonatype.nexus.ruby.RubygemsFile; import org.sonatype.nexus.ruby.cuba.RubygemsFileSystem; import org.sonatype.nexus.ruby.layout.Storage; public class MavenGemURLConnection extends URLConnection { public static final String MAVEN_RELEASES = "/maven/releases"; public static final String PING = MAVEN_RELEASES + "/ping"; private InputStream in; private long timestamp = -1; // package private for testing final URL baseurl; final String path; final RubygemsFactory factory; public static MavenGemURLConnection create(String uri) throws MalformedURLException { return create(null, uri); } public static MavenGemURLConnection create(RubygemsFactory factory, String uri) throws MalformedURLException { int index = uri.indexOf(MAVEN_RELEASES); String path = uri.substring(index); String baseurl = uri.substring(0, index); return new MavenGemURLConnection(factory, new URL(baseurl), path); } public MavenGemURLConnection(URL baseurl, String path) throws MalformedURLException { this(null, baseurl, path); } public MavenGemURLConnection(RubygemsFactory factory, URL baseurl, String path) throws MalformedURLException { super(baseurl); this.factory = factory == null ? RubygemsFactory.defaultFactory() : factory; this.baseurl = baseurl; this.path = path.startsWith(MAVEN_RELEASES) ? path : MAVEN_RELEASES + path; } @Override synchronized public InputStream getInputStream() throws IOException { if (in == null) { connect(); } return in; } synchronized public long getModified() throws IOException { if (timestamp == -1) { connect(); } return timestamp; } private int counter = 12; // seconds @Override synchronized public void connect() throws IOException { connect(factory.getOrCreate(baseurl)); } private void connect(Rubygems facade) throws IOException { RubygemsFile file = facade.get(path); switch( file.state() ) { case FORBIDDEN: throw new IOException("forbidden: " + file + " on " + baseurl); case NOT_EXISTS: if (path.equals(PING)) { in = new ByteArrayInputStream("pong".getBytes()); break; } throw new FileNotFoundException(file.toString() + " on " + baseurl); case NO_PAYLOAD: switch( file.type() ) { case GEM_ARTIFACT: // we can pass in null as dependenciesData since we have already the gem in = new URL(baseurl + "/gems/" + ((GemArtifactFile) file ).gem( null ).filename() + ".gem" ).openStream(); case GEM: // TODO timestamp in = new URL(baseurl + "/" + file.remotePath()).openStream(); default: throw new FileNotFoundException("view - not implemented. " + file + " on " + baseurl + " on " + baseurl); } case ERROR: if (file.getException() instanceof NoSuchFileException) { throw new FileNotFoundException(file.toString() + " on " + baseurl); } throw new IOException(file.toString() + " on " + baseurl, file.getException()); case TEMP_UNAVAILABLE: try { Thread.currentThread().sleep(1000); } catch(InterruptedException ignore) { } if (--counter > 0) { connect(facade); } break; case PAYLOAD: in = facade.getInputStream(file); timestamp = facade.getModified(file); break; case NEW_INSTANCE: default: throw new RuntimeException("BUG: should never reach here. " + file + " on " + baseurl); } } }