commit 50835f635d8867626a6c72f2b96563e340e55751 Author: fabio.simeoni Date: Thu Oct 24 11:31:06 2013 +0000 branched for 1.x releases git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/branches/common/common-gcube-calls/1.0@83987 82a268e6-3cf1-43bd-a215-b396298e98cf diff --git a/.classpath b/.classpath new file mode 100644 index 0000000..534b5e5 --- /dev/null +++ b/.classpath @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..a815190 --- /dev/null +++ b/.project @@ -0,0 +1,23 @@ + + + common-gcube-calls + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..83dab3a --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,7 @@ +#Fri Oct 11 15:08:46 CEST 2013 +eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/main/resources=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 +encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..6b3352d --- /dev/null +++ b/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,13 @@ +#Fri Oct 11 15:08:46 CEST 2013 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs new file mode 100644 index 0000000..d929c2c --- /dev/null +++ b/.settings/org.eclipse.m2e.core.prefs @@ -0,0 +1,5 @@ +#Wed Oct 09 11:35:36 CEST 2013 +activeProfiles= +eclipse.preferences.version=1 +resolveWorkspaceProjects=true +version=1 diff --git a/distro/INSTALL b/distro/INSTALL new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/distro/INSTALL @@ -0,0 +1 @@ + diff --git a/distro/LICENSE b/distro/LICENSE new file mode 100644 index 0000000..630ba97 --- /dev/null +++ b/distro/LICENSE @@ -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. diff --git a/distro/MAINTAINERS b/distro/MAINTAINERS new file mode 100644 index 0000000..02d640e --- /dev/null +++ b/distro/MAINTAINERS @@ -0,0 +1,2 @@ +* Lucio Lelii (lucio.lelii@isti.cnr.it), CNR, Italy +* Fabio Simeoni (fabio.simeoni@fao.org), FAO of the UN, Italy \ No newline at end of file diff --git a/distro/README b/distro/README new file mode 100644 index 0000000..8ba3d75 --- /dev/null +++ b/distro/README @@ -0,0 +1,39 @@ +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 +------- + +* Lucio Lelii (lucio.lelii@isti.cnr.it), CNR, Italy +* 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. diff --git a/distro/changelog.xml b/distro/changelog.xml new file mode 100644 index 0000000..a4d71f9 --- /dev/null +++ b/distro/changelog.xml @@ -0,0 +1,5 @@ + + + First Release + + \ No newline at end of file diff --git a/distro/descriptor.xml b/distro/descriptor.xml new file mode 100644 index 0000000..52cb8a5 --- /dev/null +++ b/distro/descriptor.xml @@ -0,0 +1,42 @@ + + servicearchive + + tar.gz + + / + + + ${distroDirectory} + / + true + + README + LICENSE + INSTALL + MAINTAINERS + changelog.xml + + 755 + true + + + + + ${distroDirectory}/profile.xml + /etc + true + + + target/${build.finalName}.jar + /${artifactId} + + + ${distroDirectory}/svnpath.txt + /${artifactId} + true + + + \ No newline at end of file diff --git a/distro/profile.xml b/distro/profile.xml new file mode 100644 index 0000000..91c49e4 --- /dev/null +++ b/distro/profile.xml @@ -0,0 +1,26 @@ + + + + Service + + ${description} + Common + ${artifactId} + 1.0.0 + + + ${artifactId} + ${version} + + ${groupId} + ${artifactId} + ${version} + + + ${build.finalName}.jar + + + + + + diff --git a/distro/svnpath.txt b/distro/svnpath.txt new file mode 100644 index 0000000..f416f9d --- /dev/null +++ b/distro/svnpath.txt @@ -0,0 +1 @@ +${scm.url} diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..7c36ca1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,91 @@ + + 4.0.0 + + + org.gcube.tools + maven-parent + 1.0.0 + + + org.gcube.core + common-gcube-calls + 1.0.0-SNAPSHOT + + + distro + + + + scm:svn:http://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId} + scm:svn:https://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId} + http://svn.d4science.research-infrastructures.eu/gcube/trunk/Common/${project.artifactId} + + + + + org.gcube.core + common-scope + [1.1.0-SNAPSHOT,2.0.0-SNAPSHOT) + + + org.slf4j + slf4j-api + 1.7.5 + + + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.5 + + + copy-profile + install + + copy-resources + + + target + + + ${distroDirectory} + true + + profile.xml + + + + + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + ${distroDirectory}/descriptor.xml + + + + + servicearchive + install + + single + + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/common/calls/Call.java b/src/main/java/org/gcube/common/calls/Call.java new file mode 100644 index 0000000..dc866ae --- /dev/null +++ b/src/main/java/org/gcube/common/calls/Call.java @@ -0,0 +1,13 @@ +package org.gcube.common.calls; + +import java.util.HashMap; +import java.util.Map; + +public class Call { + + private Map properties = new HashMap(); + + public Map properties() { + return properties; + } +} diff --git a/src/main/java/org/gcube/common/calls/Interceptor.java b/src/main/java/org/gcube/common/calls/Interceptor.java new file mode 100644 index 0000000..41f36ac --- /dev/null +++ b/src/main/java/org/gcube/common/calls/Interceptor.java @@ -0,0 +1,9 @@ +package org.gcube.common.calls; + +public interface Interceptor { + + void handleRequest(Request context, Call callContext); + + void handleResponse(Response context, Call callContext); + +} diff --git a/src/main/java/org/gcube/common/calls/Interceptors.java b/src/main/java/org/gcube/common/calls/Interceptors.java new file mode 100644 index 0000000..c4c2a20 --- /dev/null +++ b/src/main/java/org/gcube/common/calls/Interceptors.java @@ -0,0 +1,50 @@ +package org.gcube.common.calls; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceLoader; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class Interceptors { + + private static final Logger log = LoggerFactory.getLogger(Interceptors.class); + + private final static List interceptors = new ArrayList(); + + static { + ServiceLoader loader = ServiceLoader.load(Interceptor.class); + Iterator it = loader.iterator(); + while (it.hasNext()) + try { + Interceptor handler = it.next(); + log.info("loaded interceptor {}",handler); + interceptors.add(handler); + } + catch(Error e) { + log.error("could not load interceptors",e); + } + } + + public static List getInterceptors(){ + return interceptors; + } + + public static Request executeRequestChain(Call call){ + log.trace("executing request chain"); + Request context = new Request(); + for (Interceptor interceptor : interceptors) + interceptor.handleRequest(context, call); + return context; + } + + public static Response executeResponseChain(Call call){ + Response context = new Response(); + for (Interceptor interceptor : interceptors) + interceptor.handleResponse(context, call); + return context; + } +} diff --git a/src/main/java/org/gcube/common/calls/Message.java b/src/main/java/org/gcube/common/calls/Message.java new file mode 100644 index 0000000..b7c5839 --- /dev/null +++ b/src/main/java/org/gcube/common/calls/Message.java @@ -0,0 +1,22 @@ +package org.gcube.common.calls; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.Map.Entry; + +public abstract class Message { + + private Map headers = new HashMap(); + + public void addHeader(String key, String value){ + headers.put(key, value); + } + + public Set> getHeaders(){ + return Collections.unmodifiableSet(headers.entrySet()); + } + + +} diff --git a/src/main/java/org/gcube/common/calls/Request.java b/src/main/java/org/gcube/common/calls/Request.java new file mode 100644 index 0000000..cc75ca5 --- /dev/null +++ b/src/main/java/org/gcube/common/calls/Request.java @@ -0,0 +1,5 @@ +package org.gcube.common.calls; + +public class Request extends Message { + +} diff --git a/src/main/java/org/gcube/common/calls/Response.java b/src/main/java/org/gcube/common/calls/Response.java new file mode 100644 index 0000000..34165f8 --- /dev/null +++ b/src/main/java/org/gcube/common/calls/Response.java @@ -0,0 +1,5 @@ +package org.gcube.common.calls; + +public class Response extends Message{ + +} diff --git a/src/main/java/org/gcube/common/calls/ServiceCache.java b/src/main/java/org/gcube/common/calls/ServiceCache.java new file mode 100644 index 0000000..daca473 --- /dev/null +++ b/src/main/java/org/gcube/common/calls/ServiceCache.java @@ -0,0 +1,120 @@ +package org.gcube.common.calls; + +import java.util.LinkedHashMap; +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Privately used by a {@link StubFactory}, caches {@link Service} instances for services with given names. + *

+ * The cache is LRU and bounded at a maximum size of {@link LRUCache#max}. It is also thread-safe, though synchronisation + * occurs on a per-key basis. + * + * @author Fabio Simeoni, Lucio Lelii + * @see ServiceCache + */ +class ServiceCache { + + private static final Logger log = LoggerFactory.getLogger(ServiceCache.class); + + private volatile LRUCache cache = new LRUCache(); + + //holds key locks for LRU map + private ConcurrentHashMap nameLocks = new ConcurrentHashMap(); + + void clear(Call name) { + + //obtain a lock for current key + Lock nameLock = lockFor(name); + + nameLock.lock(); + + try { + cache.remove(name); + } + finally { + nameLock.unlock(); + } + + } + + + T get(Call name,Callable task) { + + //obtain a lock for current key + Lock nameLock = lockFor(name); + + nameLock.lock(); + + try { + + T service = cache.get(name); + + if (service==null) + try { + service= task.call(); + log.trace("caching stub for "+name); + cache.put(name,service); + } + catch(Exception e) { + throw new RuntimeException("could not build service",e); + } + else { + log.trace("using cached stub for "+name); + } + + return service; + } + finally { + nameLock.unlock(); + } + } + + //helper + private Lock lockFor(Call name) { + + Lock nameLock = nameLocks.get(name); + + //no need to create a new lock a priori + if (nameLock==null) { + + Lock newLock = new ReentrantLock(); + + //get name lock, creating it if it doesn't exist + //this is where we first synchronise: second-come thread waits for new one to have put a lock + //then it gets that same shared lock + nameLock = nameLocks.putIfAbsent(name,newLock); + + nameLock = nameLock == null? newLock : nameLock; + } + + return nameLock; + } + + private class LRUCache extends LinkedHashMap { + + private static final long serialVersionUID = 1L; + + public static final int max = 50; + + public LRUCache() { + //use defaults, but indicate accessor-order as 3rd parameter (rather than default insertion order) + super(16,.75f,true); + } + + @Override + protected boolean removeEldestEntry(java.util.Map.Entry eldest) { + if (size()>=max) { + nameLocks.remove(eldest.getKey()); + return true; + } + + return false; + } + } + +} diff --git a/src/main/java/org/gcube/common/calls/interceptors/ScopeInterceptor.java b/src/main/java/org/gcube/common/calls/interceptors/ScopeInterceptor.java new file mode 100644 index 0000000..0e1d2b6 --- /dev/null +++ b/src/main/java/org/gcube/common/calls/interceptors/ScopeInterceptor.java @@ -0,0 +1,34 @@ +package org.gcube.common.calls.interceptors; + +import org.gcube.common.calls.Call; +import org.gcube.common.calls.Interceptor; +import org.gcube.common.calls.Request; +import org.gcube.common.calls.Response; +import org.gcube.common.scope.api.ScopeProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ScopeInterceptor implements Interceptor { + + private Logger logger = LoggerFactory.getLogger(ScopeInterceptor.class); + + public static final String scope_header="gcube-scope"; + + public void handleRequest(Request request, Call call) { + + String scope = ScopeProvider.instance.get(); + + if (scope==null) + throw new RuntimeException("call is unscoped"); + + request.addHeader(scope_header, scope); + + logger.trace("scope set in the header is "+scope); + + } + + public void handleResponse(Response context, Call callContext) {} + + + +} diff --git a/src/main/resources/META-INF/services/org.gcube.common.calls.Interceptor b/src/main/resources/META-INF/services/org.gcube.common.calls.Interceptor new file mode 100644 index 0000000..2aff37d --- /dev/null +++ b/src/main/resources/META-INF/services/org.gcube.common.calls.Interceptor @@ -0,0 +1 @@ +org.gcube.common.calls.interceptors.ScopeInterceptor \ No newline at end of file