branched for release 1.0.0 in gCube 2.14
git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/branches/common/common-configuration-scanner/1.0@73667 82a268e6-3cf1-43bd-a215-b396298e98cfmaster
commit
7b519bf6b7
@ -0,0 +1,36 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||
<attributes>
|
||||
<attribute name="optional" value="true"/>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>common-configuration-scanner</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
@ -0,0 +1 @@
|
||||
|
@ -0,0 +1,6 @@
|
||||
gCube System - License
|
||||
------------------------------------------------------------
|
||||
|
||||
The gCube/gCore software is licensed as Free Open Source software conveying to the EUPL (http://ec.europa.eu/idabc/eupl).
|
||||
The software and documentation is provided by its authors/distributors "as is" and no expressed or
|
||||
implied warranty is given for its use, quality or fitness for a particular case.
|
@ -0,0 +1 @@
|
||||
* Fabio Simeoni (fabio.simeoni@fao.org), FAO of the UN, Italy
|
@ -0,0 +1,37 @@
|
||||
The gCube System - ${name}
|
||||
----------------------
|
||||
|
||||
This work has been partially supported by the following European projects: DILIGENT (FP6-2003-IST-2), D4Science (FP7-INFRA-2007-1.2.2),
|
||||
D4Science-II (FP7-INFRA-2008-1.2.2), iMarine (FP7-INFRASTRUCTURES-2011-2), and EUBrazilOpenBio (FP7-ICT-2011-EU-Brazil).
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
* Fabio Simeoni (fabio.simeoni@fao.org), FAO of the UN, Italy.
|
||||
|
||||
Version and Release Date
|
||||
------------------------
|
||||
${version}
|
||||
|
||||
Description
|
||||
-----------
|
||||
${description}
|
||||
|
||||
Download information
|
||||
--------------------
|
||||
|
||||
Source code is available from SVN:
|
||||
${scm.url}
|
||||
|
||||
Binaries can be downloaded from:
|
||||
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
Documentation is available on-line from the Projects Documentation Wiki:
|
||||
https://gcube.wiki.gcube-system.org/gcube/index.php
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
||||
This software is licensed under the terms you may find in the file named "LICENSE" in this directory.
|
@ -0,0 +1,5 @@
|
||||
<ReleaseNotes>
|
||||
<Changeset component="${build.finalName}" date="2013-1-27">
|
||||
<Change>First Release</Change>
|
||||
</Changeset>
|
||||
</ReleaseNotes>
|
@ -0,0 +1,42 @@
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
|
||||
<id>servicearchive</id>
|
||||
<formats>
|
||||
<format>tar.gz</format>
|
||||
</formats>
|
||||
<baseDirectory>/</baseDirectory>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${distroDirectory}</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<useDefaultExcludes>true</useDefaultExcludes>
|
||||
<includes>
|
||||
<include>README</include>
|
||||
<include>LICENSE</include>
|
||||
<include>INSTALL</include>
|
||||
<include>MAINTAINERS</include>
|
||||
<include>changelog.xml</include>
|
||||
</includes>
|
||||
<fileMode>755</fileMode>
|
||||
<filtered>true</filtered>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
<files>
|
||||
<file>
|
||||
<source>${distroDirectory}/profile.xml</source>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
<filtered>true</filtered>
|
||||
</file>
|
||||
<file>
|
||||
<source>target/${build.finalName}.jar</source>
|
||||
<outputDirectory>/${artifactId}</outputDirectory>
|
||||
</file>
|
||||
<file>
|
||||
<source>${distroDirectory}/svnpath.txt</source>
|
||||
<outputDirectory>/${artifactId}</outputDirectory>
|
||||
<filtered>true</filtered>
|
||||
</file>
|
||||
</files>
|
||||
</assembly>
|
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<ID />
|
||||
<Type>Service</Type>
|
||||
<Profile>
|
||||
<Description>${description}</Description>
|
||||
<Class>Common</Class>
|
||||
<Name>${artifactId}</Name>
|
||||
<Version>1.0.0</Version>
|
||||
<Packages>
|
||||
<Software>
|
||||
<Name>${artifactId}</Name>
|
||||
<Version>${version}</Version>
|
||||
<MavenCoordinates>
|
||||
<groupId>${groupId}</groupId>
|
||||
<artifactId>${artifactId}</artifactId>
|
||||
<version>${version}</version>
|
||||
</MavenCoordinates>
|
||||
<Files>
|
||||
<File>${build.finalName}.jar</File>
|
||||
</Files>
|
||||
</Software>
|
||||
</Packages>
|
||||
</Profile>
|
||||
</Resource>
|
||||
|
@ -0,0 +1 @@
|
||||
${scm.url}
|
@ -0,0 +1,101 @@
|
||||
<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/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.gcube.tools</groupId>
|
||||
<artifactId>maven-parent</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>org.gcube.core</groupId>
|
||||
<artifactId>common-configuration-scanner</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<distroDirectory>distro</distroDirectory>
|
||||
</properties>
|
||||
|
||||
<scm>
|
||||
<connection>scm:svn:http://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId}</connection>
|
||||
<developerConnection>scm:svn:https://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId}</developerConnection>
|
||||
<url>http://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId}</url>
|
||||
</scm>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.6.4</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>1.6.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<plugins>
|
||||
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-resources-plugin</artifactId>
|
||||
<version>2.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-profile</id>
|
||||
<phase>install</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>target</outputDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${distroDirectory}</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>profile.xml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>${distroDirectory}/descriptor.xml</descriptor>
|
||||
</descriptors>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>servicearchive</id>
|
||||
<phase>install</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,25 @@
|
||||
package org.gcube.common.scan;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.gcube.common.scan.matchers.ResourceMatcher;
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
|
||||
/**
|
||||
* Scans archives of classpath resources and extracts those that satify given conditions.
|
||||
* <p>
|
||||
* The archives scanned over are properties of implementations.
|
||||
*
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public interface ClasspathScanner {
|
||||
|
||||
/**
|
||||
* Returns {@link ClasspathResource}s that match a given {@link ResourceMatcher}.
|
||||
* @param matcher the matcher
|
||||
* @return the matching resources
|
||||
*/
|
||||
Collection<ClasspathResource> scan(ResourceMatcher matcher);
|
||||
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package org.gcube.common.scan;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
|
||||
|
||||
/**
|
||||
* Creates {@link ClasspathScanner}s for given URLs.
|
||||
*
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class ClasspathScannerFactory {
|
||||
|
||||
private static ClasspathScanner scanner;
|
||||
|
||||
/**
|
||||
* Returns a {@link ClasspathScanner} defined over all the URLs visible to the context classloader and its parents, up to the application
|
||||
* classloader.
|
||||
* @return the scanner
|
||||
*/
|
||||
public synchronized static ClasspathScanner scanner() {
|
||||
if (scanner==null)
|
||||
scanner = new DefaultScanner();
|
||||
return scanner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ClasspathScanner} defined over a given collection of URLs.
|
||||
* @param the URLs
|
||||
* @return the scanner
|
||||
*/
|
||||
public synchronized static ClasspathScanner scanner(Collection<URL> urls) {
|
||||
if (scanner==null)
|
||||
scanner = new DefaultScanner(urls);
|
||||
return scanner;
|
||||
}
|
||||
|
||||
//test facility
|
||||
/**
|
||||
* Sets the scanner to return from {@link #scanner()} and {@link #scanner(Collection)} for testing purposes.
|
||||
* @param scanner the scanner
|
||||
*/
|
||||
public static void setScanner(ClasspathScanner scanner) {
|
||||
ClasspathScannerFactory.scanner=scanner;
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package org.gcube.common.scan;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.scan.scanners.resource.JarResourceScanner;
|
||||
import org.gcube.common.scan.scanners.resource.ResourceScanner;
|
||||
import org.gcube.common.scan.scanners.url.ExcludeScanner;
|
||||
import org.gcube.common.scan.scanners.url.DirScanner;
|
||||
import org.gcube.common.scan.scanners.url.JarFileScanner;
|
||||
import org.gcube.common.scan.scanners.url.JarJarScanner;
|
||||
import org.gcube.common.scan.scanners.url.URLScanner;
|
||||
|
||||
/**
|
||||
* Defines the configurations of {@link DefaultScanner}s
|
||||
*
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class Configuration {
|
||||
|
||||
static Set<URLScanner> urlScanners = new HashSet<URLScanner>();
|
||||
|
||||
static Set<ResourceScanner> resourceScanners = new HashSet<ResourceScanner>();
|
||||
|
||||
//registers known scanners
|
||||
static {
|
||||
//register pre-defined ones
|
||||
register(new DirScanner(),new JarFileScanner(), new JarJarScanner(), new ExcludeScanner());
|
||||
register(new JarResourceScanner());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional {@link URLScanner}s
|
||||
* @param scanners the scanners.
|
||||
*/
|
||||
public static void register(URLScanner ... scanners) {
|
||||
for (URLScanner scanner : scanners)
|
||||
urlScanners.add(scanner);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers additional {@link ResourceScanner}s
|
||||
* @param scanners the scanners.
|
||||
*/
|
||||
public static void register(ResourceScanner ... scanners) {
|
||||
for (ResourceScanner scanner : scanners)
|
||||
resourceScanners.add(scanner);
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
package org.gcube.common.scan;
|
||||
|
||||
import static org.gcube.common.scan.Configuration.*;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.scan.matchers.ResourceMatcher;
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
import org.gcube.common.scan.scanners.resource.ResourceScanner;
|
||||
import org.gcube.common.scan.scanners.url.URLScanner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ClasspathScanner}.
|
||||
*
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class DefaultScanner implements ClasspathScanner {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(DefaultScanner.class);
|
||||
|
||||
private final Collection<URL> urls;
|
||||
|
||||
/**
|
||||
* Creates an instance over all the URLs visible to the context classloader and its parents, up to the application
|
||||
* classloader.
|
||||
*/
|
||||
public DefaultScanner() {
|
||||
this(defaultClasspath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance over a given collection of URLs.
|
||||
* @param urls the urls
|
||||
*/
|
||||
DefaultScanner(Collection<URL> urls) {
|
||||
|
||||
if (urls == null)
|
||||
throw new IllegalArgumentException("no urls specified");
|
||||
|
||||
this.urls = urls;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClasspathResource> scan(ResourceMatcher matcher) {
|
||||
|
||||
if (matcher == null)
|
||||
throw new IllegalArgumentException("no matcher specified");
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
Collection<ClasspathResource> scanned = scanUrls(urls, matcher);
|
||||
|
||||
log.info("matched {} resources from {} urls in {} ms",
|
||||
new Object[] { scanned.size(), urls.size(), System.currentTimeMillis() - start });
|
||||
|
||||
return scanned;
|
||||
}
|
||||
|
||||
//helper: scan URLs
|
||||
private Collection<ClasspathResource> scanUrls(Collection<URL> urls, ResourceMatcher matcher) {
|
||||
|
||||
Collection<ClasspathResource> resources = new ArrayList<ClasspathResource>();
|
||||
|
||||
toNextUrl: for (URL url : urls) {
|
||||
|
||||
for (URLScanner scanner : urlScanners)
|
||||
|
||||
if (scanner.handles(url)) {
|
||||
|
||||
try {
|
||||
scanUrl(resources,url,scanner, matcher);
|
||||
} catch (Exception e) {
|
||||
log.error("error scanning " + url, e);
|
||||
}
|
||||
|
||||
continue toNextUrl;
|
||||
}
|
||||
|
||||
log.warn("no handler for {}", url);
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
//helper: scan a single URL (and those additionally associated with it)
|
||||
private void scanUrl(Collection<ClasspathResource> results, URL url, URLScanner scanner, ResourceMatcher matcher)
|
||||
throws Exception {
|
||||
|
||||
// scan this url
|
||||
Collection<ClasspathResource> scanned = scanner.scan(url);
|
||||
|
||||
// scan resources in this url
|
||||
results.addAll(scanResources(scanned, matcher));
|
||||
|
||||
// repeat recursively for any additional urls (e.g. classpath manifest entries in jars)
|
||||
Set<URL> additionalUrls = scanner.additional(url);
|
||||
|
||||
results.addAll(scanUrls(additionalUrls, matcher));
|
||||
|
||||
}
|
||||
|
||||
//helper: scan resources
|
||||
private Collection<ClasspathResource> scanResources(Collection<ClasspathResource> resources, ResourceMatcher matcher) {
|
||||
|
||||
Collection<ClasspathResource> closure = new ArrayList<ClasspathResource>();
|
||||
|
||||
// check we need to scan this resource further (e.g. jar resources)
|
||||
toNextResource: for (ClasspathResource resource : resources) {
|
||||
|
||||
boolean handled = false;
|
||||
|
||||
for (ResourceScanner scanner : resourceScanners)
|
||||
|
||||
if (scanner.handles(resource)) {
|
||||
|
||||
handled = true;
|
||||
|
||||
try {
|
||||
|
||||
Collection<ClasspathResource> scanned = scanResource(resource, scanner, matcher);
|
||||
|
||||
// match resources
|
||||
for (ClasspathResource r : scanned)
|
||||
if (matcher.match(r))
|
||||
closure.add(r);
|
||||
} catch (Exception e) {
|
||||
log.warn("error scanning " + resource);
|
||||
}
|
||||
|
||||
continue toNextResource;
|
||||
}
|
||||
|
||||
// nobody to further scan this resource, add it as it is
|
||||
if (!handled && matcher.match(resource))
|
||||
closure.add(resource);
|
||||
}
|
||||
|
||||
return closure;
|
||||
}
|
||||
|
||||
//helper: scans a single resource (and all those derived from it)
|
||||
private Collection<ClasspathResource> scanResource(ClasspathResource resource, ResourceScanner scanner,
|
||||
ResourceMatcher matcher) throws Exception {
|
||||
|
||||
// scan this resource
|
||||
Collection<ClasspathResource> scanned = scanner.scan(resource);
|
||||
|
||||
// repeat recursively
|
||||
return scanResources(scanned, matcher);
|
||||
}
|
||||
|
||||
//helper: obains the URL of the current classpath
|
||||
private static Set<URL> defaultClasspath() {
|
||||
final Set<URL> result = new HashSet<URL>();
|
||||
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
while (classLoader != null) {
|
||||
if (classLoader instanceof URLClassLoader) {
|
||||
URL[] urls = ((URLClassLoader) classLoader).getURLs();
|
||||
if (urls != null) {
|
||||
result.addAll(new HashSet<URL>(Arrays.asList(urls)));
|
||||
}
|
||||
}
|
||||
classLoader = classLoader.getParent();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
System.out.println(defaultClasspath());
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.gcube.common.scan.matchers;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
|
||||
|
||||
public class NameMatcher implements ResourceMatcher {
|
||||
|
||||
private final Pattern regexp;
|
||||
|
||||
public NameMatcher(String regexp) {
|
||||
this.regexp=Pattern.compile(regexp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(ClasspathResource resource) {
|
||||
return regexp.matcher(resource.name()).matches();
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package org.gcube.common.scan.matchers;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
|
||||
|
||||
public class PathMatcher implements ResourceMatcher {
|
||||
|
||||
private final Pattern regexp;
|
||||
|
||||
public PathMatcher(String regexp) {
|
||||
this.regexp=Pattern.compile(regexp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean match(ClasspathResource resource) {
|
||||
return regexp.matcher(resource.path()).matches();
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package org.gcube.common.scan.matchers;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
|
||||
public interface ResourceMatcher {
|
||||
|
||||
boolean match(ClasspathResource resource);
|
||||
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
package org.gcube.common.scan.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Models a {@link ClasspathResource} contained in some archive thereof included in a classpath.
|
||||
*
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public interface ClasspathResource {
|
||||
|
||||
/**
|
||||
* Returns the name of the resource.
|
||||
* @return
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Returns the path of the resource, relatively to the containing archive.
|
||||
* @return
|
||||
*/
|
||||
String path();
|
||||
|
||||
/**
|
||||
* Returns the resource as a stream.
|
||||
* @return the stream
|
||||
* @throws Exception if the stream cannot be returned
|
||||
*/
|
||||
InputStream stream() throws Exception;
|
||||
|
||||
/**
|
||||
* Returns the resource as a file
|
||||
* @return the file
|
||||
* @throws Exception if the file cannot be returned
|
||||
*/
|
||||
File file() throws Exception;
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.gcube.common.scan.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A {@link ClasspathResource} that lives in a directory archive.
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class FileResource implements ClasspathResource {
|
||||
|
||||
private final String relativePath;
|
||||
private final String rootPath;
|
||||
|
||||
/**
|
||||
* Creates an instance from its absolute path on the file system, and from the its path relative to archive
|
||||
* that contains it.
|
||||
*
|
||||
* @param absolutePath the absolute path
|
||||
* @param relativePath the relative path
|
||||
*/
|
||||
public FileResource(String absolutePath, String relativePath) {
|
||||
this.relativePath=relativePath;
|
||||
this.rootPath=absolutePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return relativePath.substring(relativePath.lastIndexOf(File.separatorChar)+1);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public String path() {
|
||||
String path = relativePath;
|
||||
if (relativePath.endsWith(".class"))
|
||||
path = relativePath.replace("/",".");
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream stream() {
|
||||
try {
|
||||
return new FileInputStream(file());
|
||||
}
|
||||
catch(FileNotFoundException e) {
|
||||
throw new RuntimeException("cannot read resource after existence check",e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public File file() {
|
||||
return new File(rootPath,relativePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "file-entry:"+path();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package org.gcube.common.scan.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
public class JarEntryResource implements ClasspathResource {
|
||||
|
||||
private final ZipEntry entry;
|
||||
private final JarFile file;
|
||||
|
||||
public JarEntryResource(JarFile file,ZipEntry entry) {
|
||||
this.file=file;
|
||||
this.entry=entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
String entryName = entry.getName();
|
||||
return entryName.substring(entryName.lastIndexOf("/") + 1);
|
||||
}
|
||||
|
||||
public String path() {
|
||||
String path = entry.getName();
|
||||
if (path.endsWith(".class"))
|
||||
path = path.replace("/",".");
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream stream() throws Exception {
|
||||
return file.getInputStream(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File file() throws Exception {
|
||||
|
||||
System.out.println(this);
|
||||
//can only copy into temp file to then create jarfile on
|
||||
File file = File.createTempFile("scanned",".jarEntry");
|
||||
|
||||
FileOutputStream out = new FileOutputStream(file);
|
||||
InputStream stream = stream();
|
||||
|
||||
int read = 0;
|
||||
byte[] bytes = new byte[1024];
|
||||
while((read=stream.read(bytes))!=-1)
|
||||
out.write(bytes,0,read);
|
||||
|
||||
stream.close();
|
||||
out.close();
|
||||
out.flush();
|
||||
return file;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "jar-entry:"+path();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package org.gcube.common.scan.scanners;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
import org.gcube.common.scan.resources.JarEntryResource;
|
||||
|
||||
|
||||
public class JarScanner {
|
||||
|
||||
|
||||
public Collection<ClasspathResource> scan(JarFile file) throws Exception {
|
||||
|
||||
Collection<ClasspathResource> resources = new ArrayList<ClasspathResource>();
|
||||
|
||||
Enumeration<? extends ZipEntry> entries = file.entries();
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
if (!entry.isDirectory())
|
||||
resources.add(new JarEntryResource(file,entry));
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.gcube.common.scan.scanners.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
import org.gcube.common.scan.resources.JarEntryResource;
|
||||
import org.gcube.common.scan.scanners.JarScanner;
|
||||
|
||||
|
||||
|
||||
public class JarResourceScanner implements ResourceScanner {
|
||||
|
||||
private final JarScanner scanner = new JarScanner();
|
||||
|
||||
public boolean handles(ClasspathResource resource) {
|
||||
|
||||
//explicitly excludes nested jars
|
||||
return resource.name().endsWith(".jar") &&
|
||||
!JarEntryResource.class.isAssignableFrom(resource.getClass());
|
||||
}
|
||||
|
||||
public Collection<ClasspathResource> scan(ClasspathResource resource) throws Exception {
|
||||
return scanner.scan(new JarFile(resource.file()));
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package org.gcube.common.scan.scanners.resource;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
|
||||
|
||||
|
||||
public interface ResourceScanner {
|
||||
|
||||
boolean handles(ClasspathResource resource);
|
||||
|
||||
//can go wrong if contents at URL cannot be accessed
|
||||
Collection<ClasspathResource> scan(ClasspathResource url) throws Exception;
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package org.gcube.common.scan.scanners.url;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
import org.gcube.common.scan.scanners.JarScanner;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class AbstractJarURLScanner implements URLScanner {
|
||||
|
||||
private static Logger log = LoggerFactory.getLogger(AbstractJarURLScanner.class);
|
||||
|
||||
private final JarScanner scanner = new JarScanner();
|
||||
|
||||
@Override
|
||||
public Set<URL> additional(URL url) throws Exception {
|
||||
|
||||
//adds url entries in jar's manifest class-path attribute
|
||||
//(necessary e.g. for maven testing in forked mode)
|
||||
|
||||
|
||||
final Manifest manifest = toFile(url).getManifest();
|
||||
if (manifest != null) {
|
||||
String classPath = manifest.getMainAttributes().getValue(new Attributes.Name("Class-Path"));
|
||||
if (classPath != null) {
|
||||
Set<URL> additionals = new LinkedHashSet<URL>();
|
||||
for (String entry : classPath.split(" ")) {
|
||||
|
||||
try {
|
||||
if (URI.create(entry).getScheme()!=null)
|
||||
additionals.add(new URL(entry));
|
||||
}
|
||||
catch(Exception e) {
|
||||
log.error("cannot process Class-Path entry "+entry,e);
|
||||
}
|
||||
}
|
||||
return additionals;
|
||||
}
|
||||
}
|
||||
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ClasspathResource> scan(URL url) throws Exception {
|
||||
|
||||
return scanner.scan(toFile(url));
|
||||
}
|
||||
|
||||
protected abstract JarFile toFile(URL url) throws Exception;
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package org.gcube.common.scan.scanners.url;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
import org.gcube.common.scan.resources.FileResource;
|
||||
|
||||
/**
|
||||
* Implements {@link URLScanner} for <code>file:</code> URLs refer to directories.
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class DirScanner implements URLScanner {
|
||||
|
||||
@Override
|
||||
public boolean handles(URL url) {
|
||||
return "file".equals(url.getProtocol()) && url.toExternalForm().endsWith("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<URL> additional(URL url) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ClasspathResource> scan(URL url) throws Exception {
|
||||
|
||||
URI uri = url.toURI();
|
||||
|
||||
File dir = new File(uri.getSchemeSpecificPart());
|
||||
|
||||
if (!dir.exists() || !dir.isDirectory() || !dir.canRead())
|
||||
throw new IllegalArgumentException(dir+" is not readable or is not a directory");
|
||||
|
||||
Set<ClasspathResource> resources = new HashSet<ClasspathResource>();
|
||||
|
||||
buildClosure(dir,dir,resources);
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
private void buildClosure(File root,File dir,Set<ClasspathResource> resources) {
|
||||
|
||||
for (File f : dir.listFiles())
|
||||
if (f.isDirectory())
|
||||
buildClosure(root,f,resources);
|
||||
else
|
||||
{
|
||||
String rootPath = root.getPath();
|
||||
String path = f.getPath();
|
||||
String relativePath = path.substring(rootPath.length()+1);
|
||||
resources.add(new FileResource(rootPath,relativePath));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package org.gcube.common.scan.scanners.url;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
|
||||
/**
|
||||
* Implements {@link URLScanner} for <code>file:</code> URLs to be excluded.
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class ExcludeScanner implements URLScanner {
|
||||
|
||||
@Override
|
||||
public boolean handles(URL url) {
|
||||
String u = url.toExternalForm();
|
||||
return u.endsWith(".dylib") || u.endsWith(".zip") || u.endsWith(".jnilib");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<URL> additional(URL url) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ClasspathResource> scan(URL url) throws Exception {
|
||||
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package org.gcube.common.scan.scanners.url;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* Specialises {@link AbstractJarURLScanner} to <code>file:</code> URLs that refer to JAR files.
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class JarFileScanner extends AbstractJarURLScanner {
|
||||
|
||||
@Override
|
||||
public boolean handles(URL url) {
|
||||
return "file".equals(url.getProtocol()) && url.toExternalForm().contains(".jar");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JarFile toFile(URL url) throws Exception {
|
||||
|
||||
File file = new File(url.toURI().getSchemeSpecificPart());
|
||||
|
||||
if (file==null || !file.exists() || !file.canRead())
|
||||
throw new IllegalArgumentException(file+" does not exist or is not readable");
|
||||
|
||||
return new JarFile(file);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package org.gcube.common.scan.scanners.url;
|
||||
|
||||
import java.net.JarURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
/**
|
||||
* Specialises {@link AbstractJarURLScanner} to <code>jar:</code> URLs that refer to JAR files.
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public class JarJarScanner extends AbstractJarURLScanner {
|
||||
|
||||
@Override
|
||||
public boolean handles(URL url) {
|
||||
return "jar".equals(url.getProtocol());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JarFile toFile(URL url) throws Exception {
|
||||
JarURLConnection urlConnection = (JarURLConnection) url.openConnection();
|
||||
return urlConnection.getJarFile();
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package org.gcube.common.scan.scanners.url;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
|
||||
|
||||
/**
|
||||
* Scans URLs for {@link ClasspathResource}s.
|
||||
*
|
||||
* @author Fabio Simeoni
|
||||
*
|
||||
*/
|
||||
public interface URLScanner {
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if this handler can scan a given URL.
|
||||
* @param url the URL
|
||||
* @return <code>true</code> if this handler can scan the URL
|
||||
*/
|
||||
boolean handles(URL url);
|
||||
|
||||
/**
|
||||
* Returns additional URLs to be scanned in addition to a given URL.
|
||||
* @param url the URL
|
||||
* @return the additional URLs
|
||||
* @throws Exception if the additional URLs cannot be derived
|
||||
*/
|
||||
Set<URL> additional(URL url) throws Exception;
|
||||
|
||||
/**
|
||||
* Scans a given {@link URL} for {@link ClasspathResource}s.
|
||||
* @param url the URL
|
||||
* @return the scanned resources
|
||||
* @throws Exception if the URL cannot be scanned
|
||||
*/
|
||||
Collection<ClasspathResource> scan(URL url) throws Exception;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package inner;
|
||||
|
||||
public class ClassResource {
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package org.acme;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
import static org.acme.TestUtils.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
import org.gcube.common.scan.resources.FileResource;
|
||||
import org.gcube.common.scan.scanners.resource.JarResourceScanner;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ResourceScannerTest {
|
||||
|
||||
@Test
|
||||
public void scanJar() throws Exception {
|
||||
|
||||
JarResourceScanner scanner = new JarResourceScanner();
|
||||
ClasspathResource resource = new FileResource("src/test/resources","test.jar");
|
||||
Collection<ClasspathResource> resources = scanner.scan(resource);
|
||||
|
||||
assertTrue(contains(resources,"jartest.resource","nested.jar"));
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package org.acme;
|
||||
|
||||
import static org.acme.TestUtils.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.gcube.common.scan.ClasspathScanner;
|
||||
import org.gcube.common.scan.ClasspathScannerFactory;
|
||||
import org.gcube.common.scan.matchers.NameMatcher;
|
||||
import org.gcube.common.scan.matchers.ResourceMatcher;
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ScanTest {
|
||||
|
||||
@Test
|
||||
public void scanEntersFileJarsOnly() throws Exception {
|
||||
|
||||
ClasspathScanner scanner = ClasspathScannerFactory.scanner();
|
||||
|
||||
ResourceMatcher matcher = new ResourceMatcher() {
|
||||
|
||||
@Override
|
||||
public boolean match(ClasspathResource resource) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Collection<ClasspathResource> resources = scanner.scan(matcher);
|
||||
|
||||
//System.out.println(resources);
|
||||
|
||||
assertTrue(contains(resources,"jartest.resource","nested.jar"));
|
||||
assertFalse(contains(resources,"innerjartest.resource"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matcherIsPassedResources() {
|
||||
|
||||
ClasspathScanner scanner = ClasspathScannerFactory.scanner();
|
||||
|
||||
ResourceMatcher matcher = new NameMatcher("test.resource");
|
||||
|
||||
Collection<ClasspathResource> matches = scanner.scan(matcher);
|
||||
|
||||
System.out.println(matches);
|
||||
|
||||
assertEquals(1, matches.size());
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package org.acme;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
public static boolean contains(Collection<ClasspathResource> resources, String ... names) {
|
||||
|
||||
Set<String> resourceNames = new HashSet<String>();
|
||||
|
||||
for (ClasspathResource r : resources)
|
||||
resourceNames.add(r.name());
|
||||
|
||||
boolean result = true;
|
||||
for (String name : names)
|
||||
result = result && resourceNames.contains(name);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,72 @@
|
||||
package org.acme;
|
||||
|
||||
import static junit.framework.Assert.*;
|
||||
import static org.acme.TestUtils.*;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.gcube.common.scan.resources.ClasspathResource;
|
||||
import org.gcube.common.scan.scanners.url.DirScanner;
|
||||
import org.gcube.common.scan.scanners.url.JarFileScanner;
|
||||
import org.gcube.common.scan.scanners.url.JarJarScanner;
|
||||
import org.junit.Test;
|
||||
|
||||
public class URLScannerTest {
|
||||
|
||||
@Test
|
||||
public void scanDirUrl() throws Exception {
|
||||
|
||||
DirScanner scanner = new DirScanner();
|
||||
|
||||
URL url = new URL("file:target/test-classes/");
|
||||
|
||||
assertTrue(scanner.handles(url));
|
||||
|
||||
Collection<ClasspathResource> resources = scanner.scan(url);
|
||||
|
||||
System.out.println(resources);
|
||||
|
||||
//scanned resources include files
|
||||
assertTrue(contains(resources,"test.resource","test.jar"));
|
||||
|
||||
//scanned resources include files nested in folders
|
||||
assertTrue(contains(resources,"innertest.resource","innertest.jar"));
|
||||
|
||||
//scanned resources do not include jar file entries
|
||||
assertFalse(contains(resources,"jartest.resource","nested.jar"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scanJarFileUrl() throws Exception {
|
||||
|
||||
JarFileScanner scanner = new JarFileScanner();
|
||||
|
||||
URL url = new URL("file:src/test/resources/test.jar");
|
||||
|
||||
Collection<ClasspathResource> resources = scanner.scan(url);
|
||||
|
||||
System.out.println(resources);
|
||||
|
||||
assertTrue(contains(resources,"jartest.resource","nested.jar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void scanJarUrl() throws Exception {
|
||||
|
||||
JarJarScanner scanner = new JarJarScanner();
|
||||
|
||||
URL url = new URL("jar:file:src/test/resources/test.jar!/");
|
||||
|
||||
Collection<ClasspathResource> resources = scanner.scan(url);
|
||||
|
||||
System.out.println(resources);
|
||||
|
||||
assertTrue(contains(resources,"jartest.resource","nested.jar"));
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue