Overlay directories for modules #1013

Implemented overlay directories for modules.
Implemented by extending the basehome initializer to be able to handle
directory to directory copies, with a default of jetty.base if no location
is specified.
This commit is contained in:
Greg Wilkins 2016-10-20 17:42:42 +11:00
parent 6ff5a3a7e9
commit 97470c4736
34 changed files with 561 additions and 333 deletions

View File

@ -8,68 +8,67 @@ gcloud
[depends]
gcloud
jcl-slf4j
jul-slf4j
jul-impl
[files]
maven://com.google.cloud/google-cloud-datastore/0.4.0|lib/gcloud/google-cloud-datastore-0.4.0.jar
maven://com.google.cloud/google-cloud-core/0.4.0|lib/gcloud/google-cloud-core-0.4.0.jar
maven://aopalliance/aopalliance/1.0|lib/gcloud/aopalliance-1.0.jar
maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar
maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar
maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar
maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client-1.20.0.jar
maven://com.google.api.grpc/grpc-google-common-protos/0.1.0|lib/gcloud/grpc-google-common-protos-0.1.0.jar
maven://com.google.api.grpc/grpc-google-iam-v1/0.1.0|lib/gcloud/grpc-google-iam-v1-0.1.0.jar
maven://com.google.api/gax/0.0.18|lib/gcloud/gax-0.0.18.jar
maven://com.google.auth/google-auth-library-credentials/0.3.1|lib/gcloud/google-auth-library-credentials-0.3.1.jar
maven://com.google.auth/google-auth-library-oauth2-http/0.3.1|lib/gcloud/google-auth-library-oauth2-http-0.3.1.jar
maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar
maven://com.fasterxml.jackson.core/jackson-core/2.1.3|lib/gcloud/jackson-core-2.1.3.jar
maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar
maven://com.google.auto.value/auto-value/1.1|lib/gcloud/auto-value-1.1.jar
maven://com.google.cloud.datastore/datastore-v1-proto-client/1.2.0|lib/gcloud/datastore-v1-proto-client-1.2.0.jar
maven://com.google.cloud.datastore/datastore-v1-protos/1.2.0|lib/gcloud/datastore-v1-protos-1.2.0.jar
maven://com.google.cloud/google-cloud-core/0.4.0|lib/gcloud/google-cloud-core-0.4.0.jar
maven://com.google.cloud/google-cloud-datastore/0.4.0|lib/gcloud/google-cloud-datastore-0.4.0.jar
maven://com.google.code.findbugs/jsr305/1.3.9|lib/gcloud/jsr305-1.3.9.jar
maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar
maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar
maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar
maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar
maven://com.google.code.gson/gson/2.3|lib/gcloud/gson-2.3.jar
maven://com.google.guava/guava/19.0|lib/gcloud/guava-19.0.jar
maven://com.google.api-client/google-api-client-appengine/1.21.0|lib/gcloud/google-api-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar
maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar
maven://com.google.api-client/google-api-client-servlet/1.21.0|lib/gcloud/google-api-client-servlet-1.21.0.jar
maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar
maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar
maven://com.google.http-client/google-http-client-appengine/1.21.0|lib/gcloud/google-http-client-appengine-1.21.0.jar
maven://com.google.http-client/google-http-client-jackson/1.21.0|lib/gcloud/google-http-client-jackson-1.21.0.jar
maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar
maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar
maven://org.json/json/20151123|lib/gcloud/json-20151123.jar
maven://com.google.http-client/google-http-client-jackson2/1.19.0|lib/gcloud/google-http-client-jackson2-1.19.0.jar
maven://com.google.http-client/google-http-client-jdo/1.21.0|lib/gcloud/google-http-client-jdo-1.21.0.jar
maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar
maven://com.google.http-client/google-http-client/1.21.0|lib/gcloud/google-http-client-1.21.0.jar
maven://com.google.inject/guice/4.0|lib/gcloud/guice-4.0.jar
maven://com.google.oauth-client/google-oauth-client-appengine/1.21.0|lib/gcloud/google-oauth-client-appengine-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client-servlet/1.21.0|lib/gcloud/google-oauth-client-servlet-1.21.0.jar
maven://com.google.oauth-client/google-oauth-client/1.21.0|lib/gcloud/google-oauth-client-1.21.0.jar
maven://com.google.protobuf.nano/protobuf-javanano/3.0.0-alpha-5|lib/gcloud/protobuf-javanano-3.0.0-alpha-5.jar
maven://com.google.protobuf/protobuf-java-util/3.0.0|lib/gcloud/protobuf-java-util-3.0.0.jar
maven://com.google.protobuf/protobuf-java/3.0.0|lib/gcloud/protobuf-java-3.0.0.jar
maven://com.google.api/gax/0.0.18|lib/gcloud/gax-0.0.18.jar
maven://com.google.auto.value/auto-value/1.1|lib/gcloud/auto-value-1.1.jar
maven://com.google.protobuf/protobuf-lite/3.0.1|lib/gcloud/protobuf-lite-3.0.1.jar
maven://com.squareup.okhttp/okhttp/2.5.0|lib/gcloud/okhttp-2.5.0.jar
maven://com.squareup.okio/okio/1.6.0|lib/gcloud/okio-1.6.0.jar
maven://commons-codec/commons-codec/1.3|lib/gcloud/commons-codec-1.3.jar
maven://io.grpc/grpc-all/1.0.1|lib/gcloud/grpc-all-1.0.1.jar
maven://io.grpc/grpc-auth/1.0.1|lib/gcloud/grpc-auth-1.0.1.jar
maven://io.grpc/grpc-context/1.0.1|lib/gcloud/grpc-context-1.0.1.jar
maven://io.grpc/grpc-protobuf/1.0.1|lib/gcloud/grpc-protobuf-1.0.1.jar
maven://com.google.protobuf/protobuf-java-util/3.0.0|lib/gcloud/protobuf-java-util-3.0.0.jar
maven://com.google.code.gson/gson/2.3|lib/gcloud/gson-2.3.jar
maven://io.grpc/grpc-netty/1.0.1|lib/gcloud/grpc-netty-1.0.1.jar
maven://io.netty/netty-codec-http2/4.1.3.Final|lib/gcloud/netty-codec-http2-4.1.3.jar
maven://io.netty/netty-codec-http/4.1.3.Final|lib/gcloud/netty-codec-http-4.1.3.Final.jar
maven://io.netty/netty-codec/4.1.3.Final|lib/gcloud/netty-codec-4.1.3.Final.jar
maven://io.netty/netty-handler/4.1.3.Final|lib/gcloud/netty-handler-4.1.3.Final.jar
maven://io.netty/netty-buffer/4.1.3.Final|lib/gcloud/netty-buffer-4.1.3.Final.jar
maven://io.netty/netty-common/4.1.3.Final|lib/gcloud/netty-common-4.1.3.Final.jar
maven://io.netty/netty-transport/4.1.3.Final|lib/gcloud/netty-transport-4.1.3.Final.jar
maven://io.netty/netty-resolver/4.1.3.Final|lib/gcloud/netty-resolver-4.1.3.Final.jar
maven://io.grpc/grpc-stub/1.0.1|lib/gcloud/grpc-stub-1.0.1.jar
maven://io.grpc/grpc-protobuf-nano/1.0.1|lib/gcloud/grpc-protobuf-nano-1.0.1.jar
maven://com.google.protobuf.nano/protobuf-javanano/3.0.0-alpha-5|lib/gcloud/protobuf-javanano/3.0.0-alpha-5.jar
maven://io.grpc/grpc-core/1.0.1|lib/gcloud/grpc-core-1.0.1.jar
maven://io.grpc/grpc-netty/1.0.1|lib/gcloud/grpc-netty-1.0.1.jar
maven://io.grpc/grpc-okhttp/1.0.1|lib/gcloud/grpc-okhttp-1.0.1.jar
maven://com.squareup.okio/okio/1.6.0|lib/gcloud/okio-1.6.0.jar
maven://com.squareup.okhttp/okhttp/2.5.0|lib/gcloud/okhttp-2.5.0.jar
maven://io.grpc/grpc-protobuf-lite/1.0.1|lib/gcloud/grpc-protobuf-lite-1.0.1.jar
maven://com.google.protobuf/protobuf-lite/3.0.1|lib/gcloud/protobuf-lite-3.0.1.jar
maven://com.google.inject/guice/4.0|lib/gcloud/guice-4.0.jar
maven://io.grpc/grpc-protobuf-nano/1.0.1|lib/gcloud/grpc-protobuf-nano-1.0.1.jar
maven://io.grpc/grpc-protobuf/1.0.1|lib/gcloud/grpc-protobuf-1.0.1.jar
maven://io.grpc/grpc-stub/1.0.1|lib/gcloud/grpc-stub-1.0.1.jar
maven://io.netty/netty-buffer/4.1.3.Final|lib/gcloud/netty-buffer-4.1.3.Final.jar
maven://io.netty/netty-codec-http/4.1.3.Final|lib/gcloud/netty-codec-http-4.1.3.Final.jar
maven://io.netty/netty-codec-http2/4.1.3.Final|lib/gcloud/netty-codec-http2-4.1.3.jar
maven://io.netty/netty-codec/4.1.3.Final|lib/gcloud/netty-codec-4.1.3.Final.jar
maven://io.netty/netty-common/4.1.3.Final|lib/gcloud/netty-common-4.1.3.Final.jar
maven://io.netty/netty-handler/4.1.3.Final|lib/gcloud/netty-handler-4.1.3.Final.jar
maven://io.netty/netty-resolver/4.1.3.Final|lib/gcloud/netty-resolver-4.1.3.Final.jar
maven://io.netty/netty-transport/4.1.3.Final|lib/gcloud/netty-transport-4.1.3.Final.jar
maven://javax.inject/javax.inject/1|lib/gcloud/javax.inject-1.jar
maven://aopalliance/aopalliance/1.0|lib/gcloud/aopalliance-1.0.jar
maven://com.google.api.grpc/grpc-google-common-protos/0.1.0|lib/gcloud/grpc-google-common-protos-0.1.0.jar
maven://com.google.api.grpc/grpc-google-iam-v1/0.1.0|lib/gcloud/grpc-google-iam-v1-0.1.0.jar
maven://com.google.cloud.datastore/datastore-v1-protos/1.2.0|lib/gcloud/datastore-v1-protos-1.2.0.jar
maven://com.google.cloud.datastore/datastore-v1-proto-client/1.2.0|lib/gcloud/datastore-v1-proto-client-1.2.0.jar
maven://com.google.http-client/google-http-client-protobuf/1.20.0|lib/gcloud/google-http-client-protobuf-1.20.0.jar
maven://com.google.api-client/google-api-client/1.20.0|lib/gcloud/google-api-client/1.20.0
maven://javax.jdo/jdo2-api/2.3-eb|lib/gcloud/jdo2-api-2.3-eb.jar
maven://javax.transaction/transaction-api/1.1|lib/gcloud/transaction-api-1.1.jar
maven://joda-time/joda-time/2.9.2|lib/gcloud/joda-time-2.9.2.jar
maven://org.apache.httpcomponents/httpclient/4.0.1|lib/gcloud/httpclient-4.0.1.jar
maven://org.apache.httpcomponents/httpcore/4.0.1|lib/gcloud/httpcore-4.0.1.jar
maven://org.codehaus.jackson/jackson-core-asl/1.9.11|lib/gcloud/jackson-core-asl-1.9.11.jar
maven://org.json/json/20151123|lib/gcloud/json-20151123.jar

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.start.builders.StartDirBuilder;
import org.eclipse.jetty.start.builders.StartIniBuilder;
import org.eclipse.jetty.start.fileinits.BaseHomeFileInitializer;
import org.eclipse.jetty.start.fileinits.MavenLocalRepoFileInitializer;
import org.eclipse.jetty.start.fileinits.LocalFileInitializer;
import org.eclipse.jetty.start.fileinits.TestFileInitializer;
import org.eclipse.jetty.start.fileinits.UriFileInitializer;
@ -73,19 +74,25 @@ public class BaseBuilder
{
// Copy from basehome
fileInitializers.add(new BaseHomeFileInitializer(baseHome));
// Handle local directories
fileInitializers.add(new LocalFileInitializer(baseHome));
// No downloads performed
fileInitializers.add(new TestFileInitializer());
fileInitializers.add(new TestFileInitializer(baseHome));
}
else if (args.isDownload())
else if (args.isCreateFiles())
{
// Handle local directories
fileInitializers.add(new LocalFileInitializer(baseHome));
// Downloads are allowed to be performed
// Setup Maven Local Repo
Path localRepoDir = args.getMavenLocalRepoDir();
Path localRepoDir = args.findMavenLocalRepoDir();
if (localRepoDir != null)
{
// Use provided local repo directory
fileInitializers.add(new MavenLocalRepoFileInitializer(baseHome,localRepoDir));
fileInitializers.add(new MavenLocalRepoFileInitializer(baseHome,localRepoDir,args.getMavenLocalRepoDir()==null));
}
else
{
@ -258,104 +265,35 @@ public class BaseBuilder
/**
* Process a specific file resource
*
* @param arg
* the fileArg to work with
* @param file
* the resolved file reference to work with
* @param arg the fileArg to work with
* @return true if change was made as a result of the file, false if no change made.
* @throws IOException
* if there was an issue in processing this file
* if there was an issue in processing this file
*/
private boolean processFileResource(FileArg arg, Path file) throws IOException
private boolean processFileResource(FileArg arg) throws IOException
{
// now on copy/download paths (be safe above all else)
if (!file.startsWith(baseHome.getBasePath()))
throw new IOException("For security reasons, Jetty start is unable to process maven file resource not in ${jetty.base} - " + file);
if (startArgs.isDownload() && (arg.uri != null))
{
// make the directories in ${jetty.base} that we need
boolean modified = FS.ensureDirectoryExists(file.getParent());
if (modified)
StartLog.log("MKDIR",baseHome.toShortForm(file.getParent()));
URI uri = URI.create(arg.uri);
URI uri = arg.uri==null?null:URI.create(arg.uri);
// Process via initializers
if (startArgs.isCreateFiles())
{
for (FileInitializer finit : fileInitializers)
{
if (finit.init(uri,file,arg.location))
{
// Completed successfully
return true;
}
if (finit.isApplicable(uri))
return finit.create(uri,arg.location);
}
if (!FS.exists(file))
System.err.println("Failed to initialize: "+arg.uri+"|"+arg.location);
return modified;
throw new IOException(String.format("Unable to create %s",arg));
}
else
for (FileInitializer finit : fileInitializers)
{
// Process directly
boolean isDir = arg.location.endsWith("/");
if (FS.exists(file))
{
// Validate existence
if (isDir)
{
if (!Files.isDirectory(file))
{
throw new IOException("Invalid: path should be a directory (but isn't): " + file);
}
if (!FS.canReadDirectory(file))
{
throw new IOException("Unable to read directory: " + file);
}
}
else
{
if (!FS.canReadFile(file))
{
throw new IOException("Unable to read file: " + file);
}
}
return false;
}
if (isDir)
{
// Create directory
boolean mkdir = FS.ensureDirectoryExists(file);
if (mkdir)
StartLog.log("MKDIR",baseHome.toShortForm(file));
return mkdir;
}
else
{
// Warn on missing file (this has to be resolved manually by user)
String shortRef = baseHome.toShortForm(file);
if (startArgs.isTestingModeEnabled())
{
StartLog.log("TESTING MODE","Skipping required file check on: %s",shortRef);
return false;
}
StartLog.warn("Missing Required File: %s",baseHome.toShortForm(file));
startArgs.setRun(false);
if (arg.uri != null)
{
StartLog.warn(" Can be downloaded From: %s",arg.uri);
StartLog.warn(" Run start.jar --create-files to download");
}
return false;
}
if (finit.isApplicable(uri))
if (!finit.check(uri,arg.location))
startArgs.setRun(false);
}
return false;
}
/**
* Process the {@link FileArg} for startup, assume that all licenses have
@ -378,16 +316,15 @@ public class BaseBuilder
for (FileArg arg : files)
{
Path file = baseHome.getBasePath(arg.location);
try
{
boolean processed = processFileResource(arg,file);
boolean processed = processFileResource(arg);
dirty |= processed;
}
catch (Throwable t)
{
StartLog.warn(t);
failures.add(String.format("[%s] %s - %s",t.getClass().getSimpleName(),t.getMessage(),file.toAbsolutePath().toString()));
failures.add(String.format("[%s] %s - %s",t.getClass().getSimpleName(),t.getMessage(),arg.location));
}
}

View File

@ -71,6 +71,10 @@ public class FS
{
if (exists(dir))
{
// Is it a directory?
if (!Files.isDirectory(dir))
throw new IOException("Path is not directory: " + dir.toAbsolutePath());
// exists already, nothing to do
return false;
}

View File

@ -46,6 +46,7 @@ public class FileArg
err.append(LN).append("Valid Syntaxes: ");
err.append(LN).append(" <relative-path> - eg: resources/");
err.append(LN).append(" or <absolute-path> - eg: /var/run/jetty.pid");
err.append(LN).append(" or <uri> - eg: basehome:some/path");
err.append(LN).append(" or <uri>|<rel-path> - eg: http://machine/my.conf|resources/my.conf");
err.append(LN).append(" or <uri>|<abs-path> - eg: http://machine/glob.dat|/opt/run/glob.dat");
err.append(LN).append("Known uri schemes: http, maven, home");
@ -56,6 +57,11 @@ public class FileArg
this.uri = parts[0];
this.location = parts[1];
}
else if (uriLocation.contains(":"))
{
this.uri = uriLocation;
this.location = null;
}
else
{
this.uri = null;
@ -118,11 +124,7 @@ public class FileArg
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("DownloadArg [uri=");
builder.append(uri);
builder.append(", location=");
builder.append(location);
builder.append("]");
builder.append("DownloadArg [uri=").append(uri).append(", location=").append(location).append("]");
return builder.toString();
}
}

View File

@ -19,28 +19,219 @@
package org.eclipse.jetty.start;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
/**
* Interface for initializing a file resource.
*/
public interface FileInitializer
public abstract class FileInitializer
{
protected final Set<String> _scheme = new HashSet<>();
protected final BaseHome _basehome;
protected FileInitializer(BaseHome basehome, String... scheme)
{
_basehome = basehome;
if (scheme!=null)
for (String s:scheme)
_scheme.add(s.toLowerCase());
}
public boolean isApplicable(URI uri)
{
if (_scheme.isEmpty())
return uri==null;
return uri!=null && _scheme.contains(uri.getScheme().toLowerCase());
}
/**
* Initialize a file resource
*
* @param uri
* the remote URI of the resource acting as its source
* @param file
* the local file resource to initialize. (often in ${jetty.base} directory)
* @param fileRef
* the URI of the resource acting as its source
* @param location
* the simple string reference to the output file, suitable for searching
* for the file in other locations (like ${jetty.home} or ${jetty.dir})
* @return true if local file is initialized (resulted in a change on disk), false if this
* {@link FileInitializer} did nothing.
* @param create if True, create the file if missing, otherwise just check for existance.
*
* @return True if local file is initialized (resulted in a change on disk), False if
could not be initialized or null if it does not apply.
* @throws IOException
* if there was an attempt to initialize, but an error occurred.
*/
public boolean init(URI uri, Path file, String fileRef) throws IOException;
public abstract boolean create(URI uri, String location) throws IOException;
public boolean check(URI uri, String location) throws IOException
{
if (location!=null)
{
// Process directly
boolean isDir = location.endsWith("/");
Path destination = getDestination(uri,location);
if (FS.exists(destination))
{
// Validate existence
if (isDir)
{
if (!Files.isDirectory(destination))
{
throw new IOException("Invalid: path should be a directory (but isn't): " + location);
}
if (!FS.canReadDirectory(destination))
{
throw new IOException("Unable to read directory: " + location);
}
}
else
{
if (!FS.canReadFile(destination))
{
throw new IOException("Unable to read file: " + location);
}
}
return true;
}
StartLog.error("Missing Required File: %s",_basehome.toShortForm(location));
return false;
}
return true;
}
protected Path getDestination(URI uri, String location) throws IOException
{
if (location==null)
return null;
Path destination = _basehome.getBasePath(location);
// now on copy/download paths (be safe above all else)
if (destination!=null && !destination.startsWith(_basehome.getBasePath()))
throw new IOException("For security reasons, Jetty start is unable to process file resource not in ${jetty.base} - " + location);
boolean isDestDir = Files.isDirectory(destination) || !Files.exists(destination) && location.endsWith("/");
if (isDestDir && uri!=null && uri.getSchemeSpecificPart().contains("/") && !uri.getSchemeSpecificPart().endsWith("/"))
destination = destination.resolve(uri.getSchemeSpecificPart().substring(uri.getSchemeSpecificPart().lastIndexOf('/')+1));
return destination;
}
protected void download(URI uri, Path destination) throws IOException
{
if (FS.ensureDirectoryExists(destination.getParent()))
StartLog.log("MKDIR",_basehome.toShortForm(destination.getParent()));
StartLog.log("DOWNLD","%s to %s",uri,_basehome.toShortForm(destination));
HttpURLConnection http = (HttpURLConnection)uri.toURL().openConnection();
http.setInstanceFollowRedirects(true);
http.setAllowUserInteraction(false);
int status = http.getResponseCode();
if(status != HttpURLConnection.HTTP_OK)
{
throw new IOException("URL GET Failure [" + status + "/" + http.getResponseMessage() + "] on " + uri);
}
byte[] buf = new byte[8192];
try (InputStream in = http.getInputStream(); OutputStream out = Files.newOutputStream(destination,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE))
{
while (true)
{
int len = in.read(buf);
if (len > 0)
{
out.write(buf,0,len);
}
if (len < 0)
{
break;
}
}
}
}
/**
* Test if any of the Paths exist (as files)
*
* @param paths
* the list of paths to check
* @return true if the path exist (as a file), false if it doesn't exist
* @throws IOException
* if the path points to a non-file, or is not readable.
*/
protected boolean isFilePresent(Path... paths) throws IOException
{
for (Path file : paths)
{
if (Files.exists(file))
{
if (Files.isDirectory(file))
{
throw new IOException("Directory in the way: " + file.toAbsolutePath());
}
if (!Files.isReadable(file))
{
throw new IOException("File not readable: " + file.toAbsolutePath());
}
return true;
}
}
return false;
}
public boolean copyDirectory(Path source, Path destination) throws IOException
{
boolean modified=false;
try(DirectoryStream<Path> stream = Files.newDirectoryStream(source))
{
for (Path from : stream)
{
Path to = destination.resolve(from.getFileName());
if (Files.isDirectory(from))
{
if (FS.ensureDirectoryExists(to))
{
StartLog.log("MKDIR",_basehome.toShortForm(to));
modified = true;
}
if (copyDirectory(from,to))
modified = true;
}
else if (!Files.exists(to))
{
StartLog.log("COPY ","%s to %s",_basehome.toShortForm(from),_basehome.toShortForm(to));
Files.copy(from,to);
modified = true;
}
}
}
return modified;
}
}

View File

@ -404,7 +404,7 @@ public class Main
BaseBuilder baseBuilder = new BaseBuilder(baseHome,args);
if(baseBuilder.build())
StartLog.info("Base directory was modified");
else if (args.isDownload() || !args.getStartModules().isEmpty())
else if (args.isCreateFiles() || !args.getStartModules().isEmpty())
StartLog.info("Base directory was not modified");
// Check module dependencies

View File

@ -163,8 +163,8 @@ public class StartArgs
/** Should the server be run? */
private boolean run = true;
/** Download related args */
private boolean download = false;
/** Files related args */
private boolean createFiles = false;
private boolean licenseCheckRequired = false;
private boolean testingMode = false;
@ -620,24 +620,33 @@ public class StartArgs
return System.getProperty("main.class",mainclass);
}
public Path getMavenLocalRepoDir()
public String getMavenLocalRepoDir()
{
// Try property first
String localRepo = getProperties().getString("maven.local.repo");
if (Utils.isBlank(localRepo))
{
// Try jetty specific env variable
localRepo = System.getenv("JETTY_MAVEN_LOCAL_REPO");
}
if (Utils.isBlank(localRepo))
localRepo = System.getenv("MAVEN_LOCAL_REPO");
return localRepo;
}
public Path findMavenLocalRepoDir()
{
// Try property first
String localRepo = getMavenLocalRepoDir();
if (Utils.isBlank(localRepo))
{
// Try generic env variable
localRepo = System.getenv("MAVEN_LOCAL_REPO");
String home = System.getenv("HOME");
Path home_m2_repository = new File(new File(home,".m2"),"repository").toPath();
if (Files.exists(home_m2_repository))
localRepo = home_m2_repository.toString();
}
// TODO: load & use $HOME/.m2/settings.xml ?
// TODO: possibly use Eclipse Aether to manage it ?
// TODO: see https://bugs.eclipse.org/bugs/show_bug.cgi?id=449511
@ -710,9 +719,9 @@ public class StartArgs
return approveAllLicenses;
}
public boolean isDownload()
public boolean isCreateFiles()
{
return download;
return createFiles;
}
public boolean isDryRun()
@ -859,14 +868,14 @@ public class StartArgs
{
addFile(null,Props.getValue(arg));
run = false;
download = true;
createFiles = true;
return;
}
if (arg.equals("--create-files"))
{
run = false;
download = true;
createFiles = true;
licenseCheckRequired = true;
return;
}
@ -959,7 +968,7 @@ public class StartArgs
{
createStartd=true;
run = false;
download = true;
createFiles = true;
licenseCheckRequired = true;
return;
}
@ -970,7 +979,7 @@ public class StartArgs
createStartd=true;
startModules.addAll(Props.getValues(arg));
run = false;
download = true;
createFiles = true;
licenseCheckRequired = true;
return;
}
@ -978,7 +987,7 @@ public class StartArgs
{
startModules.addAll(Props.getValues(arg));
run = false;
download = true;
createFiles = true;
licenseCheckRequired = true;
return;
}

View File

@ -33,33 +33,66 @@ import org.eclipse.jetty.start.StartLog;
* "basehome:some/path"
* {@link FileInitializer}
*/
public class BaseHomeFileInitializer implements FileInitializer
{
private final BaseHome _basehome;
public class BaseHomeFileInitializer extends FileInitializer
{
public BaseHomeFileInitializer(BaseHome basehome)
{
_basehome=basehome;
super(basehome,"basehome");
}
@Override
public boolean init(URI uri, Path file, String fileRef) throws IOException
public boolean create(URI uri, String location) throws IOException
{
if (!"basehome".equalsIgnoreCase(uri.getScheme()) || uri.getSchemeSpecificPart().startsWith("/"))
return false;
if (uri.getSchemeSpecificPart().startsWith("/"))
throw new IllegalArgumentException(String.format("Bad file arg: %s",uri));
Path source = _basehome.getPath(uri.getSchemeSpecificPart());
if (FS.exists(source) && !FS.exists(file))
{
if (FS.ensureDirectoryExists(file.getParent()))
StartLog.log("MKDIR",_basehome.toShortForm(file.getParent()));
StartLog.log("COPY ","%s to %s",_basehome.toShortForm(source),_basehome.toShortForm(file));
Files.copy(source,file);
return true;
}
if (!FS.exists(source))
throw new IllegalArgumentException(String.format("File does not exist: %s",uri));
return false;
Path destination = location==null?_basehome.getBasePath():getDestination(uri,location);
boolean modified=false;
if (Files.isDirectory(source))
{
// Check destination
if (destination!=null && Files.exists(destination))
{
if (!Files.isDirectory(destination))
{
StartLog.error("Cannot copy directory %s to file %s",source,destination);
return false;
}
}
else if (FS.ensureDirectoryExists(destination))
{
modified = true;
StartLog.log("MKDIR",_basehome.toShortForm(destination));
}
copyDirectory(source,destination);
}
else
{
if (FS.ensureDirectoryExists(destination.getParent()))
{
modified = true;
StartLog.log("MKDIR",_basehome.toShortForm(destination.getParent()));
}
if (!FS.exists(destination))
{
StartLog.log("COPY ","%s to %s",_basehome.toShortForm(source),_basehome.toShortForm(destination));
Files.copy(source,destination);
modified = true;
}
}
return modified;
}
}

View File

@ -0,0 +1,87 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.start.fileinits;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import org.eclipse.jetty.start.BaseHome;
import org.eclipse.jetty.start.FS;
import org.eclipse.jetty.start.FileInitializer;
import org.eclipse.jetty.start.StartLog;
public class LocalFileInitializer extends FileInitializer
{
public LocalFileInitializer(BaseHome basehome)
{
super(basehome);
}
@Override
public boolean create(URI uri, String location) throws IOException
{
Path destination = getDestination(uri,location);
if (destination == null)
{
StartLog.error("Bad file arg %s",uri);
return false;
}
boolean isDir = location.endsWith("/");
if (FS.exists(destination))
{
// Validate existence
if (isDir)
{
if (!Files.isDirectory(destination))
{
throw new IOException("Invalid: path should be a directory (but isn't): " + location);
}
if (!FS.canReadDirectory(destination))
{
throw new IOException("Unable to read directory: " + location);
}
}
else
{
if (!FS.canReadFile(destination))
{
throw new IOException("Unable to read file: " + location);
}
}
return false;
}
if (isDir)
{
// Create directory
boolean mkdir = FS.ensureDirectoryExists(destination);
if (mkdir)
StartLog.log("MKDIR",_basehome.toShortForm(destination));
return mkdir;
}
throw new IOException("Unable to create "+_basehome.toShortForm(destination));
}
}

View File

@ -25,6 +25,7 @@ import java.nio.file.Path;
import org.eclipse.jetty.start.BaseHome;
import org.eclipse.jetty.start.FS;
import org.eclipse.jetty.start.FileInitializer;
import org.eclipse.jetty.start.StartLog;
import org.eclipse.jetty.start.Utils;
@ -46,7 +47,7 @@ import org.eclipse.jetty.start.Utils;
* <dd>optional type and classifier requirement</dd>
* </dl>
*/
public class MavenLocalRepoFileInitializer extends UriFileInitializer
public class MavenLocalRepoFileInitializer extends FileInitializer
{
public static class Coordinates
{
@ -79,20 +80,22 @@ public class MavenLocalRepoFileInitializer extends UriFileInitializer
}
private Path localRepositoryDir;
private final boolean readonly;
public MavenLocalRepoFileInitializer(BaseHome baseHome)
{
this(baseHome,null);
this(baseHome,null,true);
}
public MavenLocalRepoFileInitializer(BaseHome baseHome, Path localRepoDir)
public MavenLocalRepoFileInitializer(BaseHome baseHome, Path localRepoDir, boolean readonly)
{
super(baseHome);
super(baseHome,"maven");
this.localRepositoryDir = localRepoDir;
this.readonly = readonly;
}
@Override
public boolean init(URI uri, Path file, String fileRef) throws IOException
public boolean create(URI uri, String location) throws IOException
{
Coordinates coords = getCoordinates(uri);
if (coords == null)
@ -101,26 +104,31 @@ public class MavenLocalRepoFileInitializer extends UriFileInitializer
return false;
}
if (isFilePresent(file, baseHome.getPath(fileRef)))
{
// All done
Path destination = getDestination(uri,location);
if (isFilePresent(destination))
return false;
}
// If using local repository
if (this.localRepositoryDir != null)
{
// Grab copy from local repository (download if needed to local
// repository)
Path localRepoFile = getLocalRepoFile(coords);
StartLog.log("COPY ","%s to %s",localRepoFile,baseHome.toShortForm(file));
Files.copy(localRepoFile,file);
}
else
{
// normal non-local repo version
download(coords.toCentralURI(),file);
if (localRepoFile!=null)
{
if (FS.ensureDirectoryExists(destination.getParent()))
StartLog.log("MKDIR",_basehome.toShortForm(destination.getParent()));
StartLog.log("COPY ","%s to %s",localRepoFile,_basehome.toShortForm(destination));
Files.copy(localRepoFile,destination);
return true;
}
}
// normal non-local repo version
download(coords.toCentralURI(),destination);
return true;
}
@ -128,13 +136,16 @@ public class MavenLocalRepoFileInitializer extends UriFileInitializer
{
Path localFile = localRepositoryDir.resolve(coords.toPath());
if (FS.canReadFile(localFile))
{
return localFile;
}
// Download, if needed
download(coords.toCentralURI(),localFile);
return localFile;
if (!readonly)
{
download(coords.toCentralURI(),localFile);
return localFile;
}
return null;
}
public Coordinates getCoordinates(URI uri)

View File

@ -22,6 +22,7 @@ import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import org.eclipse.jetty.start.BaseHome;
import org.eclipse.jetty.start.FS;
import org.eclipse.jetty.start.FileInitializer;
import org.eclipse.jetty.start.StartLog;
@ -31,14 +32,33 @@ import org.eclipse.jetty.start.StartLog;
* or initialize a file, this implementation is merely a no-op for the
* {@link FileInitializer}
*/
public class TestFileInitializer implements FileInitializer
public class TestFileInitializer extends FileInitializer
{
@Override
public boolean init(URI uri, Path file, String fileRef) throws IOException
public TestFileInitializer(BaseHome basehome)
{
FS.ensureDirectoryExists(file.getParent());
super(basehome);
}
StartLog.log("TESTING MODE","Skipping download of " + uri);
@Override
public boolean isApplicable(URI uri)
{
return true;
}
@Override
public boolean create(URI uri, String location) throws IOException
{
Path destination = getDestination(uri,location);
if (destination!=null)
{
if (location.endsWith("/"))
FS.ensureDirectoryExists(destination);
else
FS.ensureDirectoryExists(destination.getParent());
}
StartLog.log("TESTING MODE","Skipping download of " + uri);
return Boolean.TRUE;
}
}

View File

@ -32,119 +32,26 @@ import org.eclipse.jetty.start.FS;
import org.eclipse.jetty.start.FileInitializer;
import org.eclipse.jetty.start.StartLog;
public class UriFileInitializer implements FileInitializer
{
private final static String[] SUPPORTED_SCHEMES = { "http", "https" };
protected final BaseHome baseHome;
public class UriFileInitializer extends FileInitializer
{
public UriFileInitializer(BaseHome baseHome)
{
this.baseHome = baseHome;
super(baseHome,"http", "https");
}
@Override
public boolean init(URI uri, Path file, String fileRef) throws IOException
public boolean create(URI uri, String location) throws IOException
{
if (!isSupportedScheme(uri))
{
// Not a supported scheme.
Path destination = getDestination(uri,location);
if (Files.isDirectory(destination))
destination = destination.resolve(uri.getSchemeSpecificPart().substring(uri.getRawSchemeSpecificPart().lastIndexOf('/')+1));
if(isFilePresent(destination))
return false;
}
if(isFilePresent(file, baseHome.getPath(fileRef)))
{
// All done
return false;
}
download(uri,file);
download(uri,destination);
return true;
}
protected void download(URI uri, Path file) throws IOException
{
StartLog.log("DOWNLOAD","%s to %s",uri,baseHome.toShortForm(file));
if (FS.ensureDirectoryExists(file.getParent()))
StartLog.log("MKDIR",baseHome.toShortForm(file.getParent()));
HttpURLConnection http = (HttpURLConnection)uri.toURL().openConnection();
http.setInstanceFollowRedirects(true);
http.setAllowUserInteraction(false);
int status = http.getResponseCode();
if(status != HttpURLConnection.HTTP_OK)
{
throw new IOException("URL GET Failure [" + status + "/" + http.getResponseMessage() + "] on " + uri);
}
byte[] buf = new byte[8192];
try (InputStream in = http.getInputStream(); OutputStream out = Files.newOutputStream(file,StandardOpenOption.CREATE_NEW,StandardOpenOption.WRITE))
{
while (true)
{
int len = in.read(buf);
if (len > 0)
{
out.write(buf,0,len);
}
if (len < 0)
{
break;
}
}
}
}
/**
* Test if any of the Paths exist (as files)
*
* @param paths
* the list of paths to check
* @return true if the path exist (as a file), false if it doesn't exist
* @throws IOException
* if the path points to a non-file, or is not readable.
*/
protected boolean isFilePresent(Path... paths) throws IOException
{
for (Path file : paths)
{
if (Files.exists(file))
{
if (Files.isDirectory(file))
{
throw new IOException("Directory in the way: " + file.toAbsolutePath());
}
if (!Files.isReadable(file))
{
throw new IOException("File not readable: " + file.toAbsolutePath());
}
return true;
}
}
return false;
}
private boolean isSupportedScheme(URI uri)
{
String scheme = uri.getScheme();
if (scheme == null)
{
return false;
}
for (String supported : SUPPORTED_SCHEMES)
{
if (supported.equalsIgnoreCase(scheme))
{
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,15 @@
DOWNLOAD|basehome:modules/withfiles/test.txt|one/renamed.txt
DOWNLOAD|basehome:modules/withfiles/test.txt|two/
DOWNLOAD|basehome:modules/withfiles/test.txt|three
DOWNLOAD|basehome:modules/withfiles|null
DOWNLOAD|basehome:modules/withfiles/four/|five/
DOWNLOAD|basehome:modules/withfiles/four/sub|six
EXISTS|test.txt
EXISTS|one/renamed.txt
EXISTS|two/test.txt
EXISTS|three/test.txt
EXISTS|four/sub/dir/test.txt
EXISTS|five/sub/dir/test.txt
EXISTS|six/sub/dir/test.txt

View File

@ -0,0 +1,2 @@
--create-startd
--add-to-start=withfiles

View File

@ -0,0 +1,12 @@
[files]
basehome:modules/withfiles/test.txt|one/renamed.txt
basehome:modules/withfiles/test.txt|two/
three/
basehome:modules/withfiles/test.txt|three
basehome:modules/withfiles
basehome:modules/withfiles/four/|five/
six/
basehome:modules/withfiles/four/sub|six

View File

@ -1 +0,0 @@
org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog

View File

@ -14,8 +14,7 @@ jul-api
jul-impl
[files]
basehome:modules/jul-impl/java-util-logging.properties|etc/java-util-logging.properties
logs/
basehome:modules/jul-impl
[exec]
-Djava.util.logging.config.file=etc/java-util-logging.properties

View File

@ -11,12 +11,13 @@ slf4j-api
slf4j-impl
[provides]
jul-api
jul-impl
slf4j+jul
[files]
maven://org.slf4j/jul-to-slf4j/${slf4j.version}|lib/slf4j/jul-to-slf4j-${slf4j.version}.jar
basehome:modules/jul-slf4j/java-util-logging.properties|etc/java-util-logging.properties
basehome:modules/jul-slf4j
[lib]
lib/slf4j/jul-to-slf4j-${slf4j.version}.jar

View File

@ -15,9 +15,8 @@ log4j-api
log4j-impl
[files]
basehome:modules/log4j/log4j.xml|resources/log4j.xml
maven://log4j/log4j/${log4j.version}|lib/log4j/log4j-${log4j.version}.jar
logs/
basehome:modules/log4j-impl
[lib]
lib/log4j/log4j-${log4j.version}.jar

View File

@ -17,8 +17,7 @@ log4j2-impl
[files]
maven://org.apache.logging.log4j/log4j-core/${log4j2.version}|lib/log4j2/log4j-core-${log4j2.version}.jar
basehome:modules/log4j2/log4j2.xml|resources/log4j2.xml
logs/
basehome:modules/log4j2-impl
[lib]
lib/log4j2/*.jar

View File

@ -11,7 +11,9 @@
<Appenders>
<Console name="console" target="SYSTEM_ERR">
<PatternLayout pattern="%m%n"/>
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n</Pattern>
</PatternLayout>
</Console>
<!--

View File

@ -11,8 +11,7 @@ resources
[files]
maven://ch.qos.logback/logback-core/${logback.version}|lib/logback/logback-core-${logback.version}.jar
basehome:modules/logback/logback.xml|resources/logback.xml
logs/
basehome:modules/logback-impl
[lib]
lib/logback/logback-core-${logback.version}.jar

View File

@ -12,4 +12,4 @@ resources
logging
[files]
basehome:modules/logging-jetty/jetty-logging.properties|resources/jetty-logging.properties
basehome:modules/logging-jetty

View File

@ -16,7 +16,6 @@ slf4j-impl
[files]
maven://ch.qos.logback/logback-classic/${logback.version}|lib/logback/logback-classic-${logback.version}.jar
basehome:modules/logback/logback.xml|resources/logback.xml
[lib]
lib/logback/logback-classic-${logback.version}.jar

View File

@ -16,8 +16,7 @@ slf4j-impl
[files]
maven://org.slf4j/slf4j-simple/${slf4j.version}|lib/slf4j/slf4j-simple-${slf4j.version}.jar
basehome:modules/slf4j/simplelogger.properties|resources/simplelogger.properties
logs/
basehome:modules/slf4j-impl
[lib]
lib/slf4j/slf4j-simple-${slf4j.version}.jar