javax.servlet,
javax.servlet.http,
javax.servlet.resources,
+ org.argeo.jcr.mvc,
org.argeo.security.core,
org.argeo.security.jcr,
org.argeo.slc.aether.spring,
org.springframework.security.ui;version="2.0.6.RELEASE",
org.springframework.security.ui.basicauth;version="2.0.6.RELEASE",
org.springframework.security.ui.logout;version="2.0.6.RELEASE",
- org.springframework.security.ui.rememberme;version="2.0.6.RELEASE",
- org.springframework.security.userdetails;version="2.0.6.RELEASE",
org.springframework.security.util;version="2.0.6.RELEASE",
org.springframework.security.vote;version="2.0.6.RELEASE",
org.springframework.security.wrapper;version="2.0.6.RELEASE",
</property>
</bean>
- <bean id="mavenProxyService" class="org.argeo.slc.repo.maven.proxy.MavenProxyServiceImpl"
- init-method="init" destroy-method="destroy">
- <property name="jcrRepository" ref="jcrRepository" />
- <property name="defaultRepositories" ref="defaultMavenRepositories" />
- </bean>
-
- <bean id="mavenProxyServlet" class="org.argeo.slc.repo.maven.proxy.MavenProxyServlet">
+ <bean id="mavenProxyServlet" class="org.argeo.jcr.mvc.ResourceProxyServlet">
<property name="jcrSession" ref="jcrSession" />
- <property name="proxyService" ref="mavenProxyService" />
+ <property name="proxy" ref="mavenProxy" />
</bean>
<bean id="jcrSession" class="org.argeo.security.jcr.SecureThreadBoundSession">
<property name="repository" ref="jcrRepository" />
- <property name="defaultUsername" value="root" />
- <property name="defaultPassword" value="demo" />
</bean>
-
- <bean
- class="org.argeo.security.core.AuthenticatedApplicationContextInitialization">
- <property name="authenticationManager" ref="authenticationManager" />
- </bean>
-
- <!-- Remote repositories -->
- <util:list id="defaultMavenRepositories">
- <ref local="central" />
- <ref local="com.springsource.repository.bundles.external" />
- <ref local="com.springsource.repository.bundles.release" />
- <ref local="argeo" />
- <ref local="argeo-snapshots" />
- </util:list>
-
- <bean id="central" class="org.argeo.slc.aether.spring.RemoteRepositoryFactory">
- <property name="url" value="http://repo1.maven.org/maven2" />
- </bean>
- <bean id="com.springsource.repository.bundles.release" class="org.argeo.slc.aether.spring.RemoteRepositoryFactory">
- <property name="url"
- value="http://repository.springsource.com/maven/bundles/release" />
- </bean>
- <bean id="com.springsource.repository.bundles.external" class="org.argeo.slc.aether.spring.RemoteRepositoryFactory">
- <property name="url"
- value="http://repository.springsource.com/maven/bundles/external" />
- </bean>
- <bean id="argeo" class="org.argeo.slc.aether.spring.RemoteRepositoryFactory">
- <property name="url" value="http://maven.argeo.org/argeo/" />
- </bean>
- <bean id="argeo-snapshots" class="org.argeo.slc.aether.spring.RemoteRepositoryFactory">
- <property name="url" value="http://dev.argeo.org/maven/argeo-snapshots/" />
- </bean>
-
</beans>
\ No newline at end of file
<!-- Security -->\r
<reference id="authenticationManager"\r
interface="org.springframework.security.AuthenticationManager" />\r
- <reference id="userDetailsService"\r
- interface="org.springframework.security.userdetails.UserDetailsService" />\r
\r
<!-- JCR -->\r
<reference id="jcrRepository" interface="javax.jcr.Repository"\r
filter="(argeo.jcr.repository.alias=slc)" />\r
+\r
+ <!-- Maven -->\r
+ <reference id="mavenProxy" interface="org.argeo.slc.repo.maven.proxy.MavenProxyService" />\r
+\r
</beans:beans>
\ No newline at end of file
<!-- URL redirected to after logout -->
<constructor-arg>
<list>
- <ref bean="rememberMeServices" />
<bean
class="org.springframework.security.ui.logout.SecurityContextLogoutHandler" />
</list>
<bean id="securityContextHolderAwareRequestFilter"
class="org.springframework.security.wrapper.SecurityContextHolderAwareRequestFilter" />
- <!-- Use the remember me cookie to authenticate -->
- <bean id="rememberMeProcessingFilter"
- class="org.springframework.security.ui.rememberme.RememberMeProcessingFilter">
- <property name="authenticationManager" ref="authenticationManager" />
- <property name="rememberMeServices" ref="rememberMeServices" />
- </bean>
-
- <bean id="rememberMeServices"
- class="org.springframework.security.ui.rememberme.TokenBasedRememberMeServices">
- <property name="userDetailsService" ref="userDetailsService" />
- <property name="key" value="${argeo.security.systemKey}" />
- </bean>
-
<!-- Basic authentication -->
<bean id="basicProcessingFilter"
class="org.springframework.security.ui.basicauth.BasicProcessingFilter">
<property name="authenticationEntryPoint">
<ref local="basicProcessingFilterEntryPoint" />
</property>
- <property name="rememberMeServices" ref="rememberMeServices" />
</bean>
<!-- Activate basic auth when needed -->
<bean id="basicProcessingFilterEntryPoint"
class="org.springframework.security.ui.basicauth.BasicProcessingFilterEntryPoint">
<property name="realmName">
- <value>Argeo</value>
+ <value>Argeo Repository</value>
</property>
</bean>
Import-Package: javax.jcr;version="2.0.0",
org.argeo.jackrabbit,
org.argeo.jcr,
+ org.argeo.security.core,
+ org.argeo.security.jcr,
org.argeo.slc.aether,
org.argeo.slc.aether.spring,
+ org.argeo.slc.repo,
org.argeo.slc.repo.maven,
- org.sonatype.aether;version="1.9.0"
+ org.argeo.slc.repo.maven.proxy,
+ org.sonatype.aether;version="1.9.0",
+ org.springframework.security;version="2.0.6.RELEASE"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
\r
- <bean id="jcrSession" class="org.argeo.jcr.ThreadBoundJcrSessionFactory">\r
+ <bean id="jcrSession" class="org.argeo.security.jcr.SecureThreadBoundSession">\r
<property name="repository" ref="jcrRepository" />\r
- <property name="workspace" value="slc_repo" />\r
- <property name="forceDefaultCredentials" value="true"/>\r
</bean>\r
</beans>
\ No newline at end of file
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
">
-
+<!--
<bean class="org.argeo.slc.repo.maven.ImportMavenDependencies" init-method="run">
<property name="rootCoordinates"
value="org.argeo.dep:versions-all:pom:1.1.3-SNAPSHOT" />
</set>
</property>
</bean>
-
+ -->
+
<bean id="mavenAetherTemplate" class="org.argeo.slc.aether.AetherTemplate">
<property name="repositorySystem" ref="mavenRepositorySystem" />
<property name="repositorySystemSession" ref="mavenRepositorySystemSession" />
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\r
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">\r
\r
+ <!-- REFERENCES -->\r
+ <!-- Security -->\r
+ <reference id="authenticationManager"\r
+ interface="org.springframework.security.AuthenticationManager" />\r
<reference id="jcrRepository" interface="javax.jcr.Repository"\r
filter="(argeo.jcr.repository.alias=slc)" />\r
\r
filter="(aether.repositorySystemType=maven)" />\r
<reference id="mavenRepositorySystemSession" interface="org.sonatype.aether.RepositorySystemSession"\r
filter="(aether.repositorySystemType=maven)" />\r
+\r
+ <!-- SERVICES -->\r
+ <service ref="mavenProxyService" interface="org.argeo.slc.repo.maven.proxy.MavenProxyService" />\r
</beans:beans>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
+ ">
+
+ <bean id="repo" class="org.argeo.slc.repo.RepoImpl" init-method="init" destroy-method="destroy">
+ <property name="jcrRepository" ref="jcrRepository" />
+ <property name="nodeIndexers">
+ <list>
+ <bean class="org.argeo.slc.repo.ArtifactIndexer" />
+ <bean class="org.argeo.slc.repo.JarFileIndexer" />
+ </list>
+ </property>
+ </bean>
+
+ <bean id="mavenProxyService" class="org.argeo.slc.repo.maven.proxy.MavenProxyServiceImpl"
+ init-method="init" destroy-method="destroy">
+ <property name="jcrRepository" ref="jcrRepository" />
+ <property name="defaultRepositories" ref="defaultMavenRepositories" />
+ </bean>
+
+ <bean
+ class="org.argeo.security.core.AuthenticatedApplicationContextInitialization">
+ <property name="authenticationManager" ref="authenticationManager" />
+ </bean>
+
+
+</beans>
\ No newline at end of file
--- /dev/null
+package org.argeo.slc.repo;
+
+import javax.jcr.Node;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.aether.AetherUtils;
+import org.argeo.slc.jcr.SlcNames;
+import org.argeo.slc.jcr.SlcTypes;
+import org.sonatype.aether.artifact.Artifact;
+
+/**
+ * Add {@link Artifact} properties to a {@link Node}. Does nothing if the node
+ * name doesn't start with the artifact id (in order to skip Maven metadata XML
+ * files and other non artifact files).
+ */
+public class ArtifactIndexer implements NodeIndexer {
+ private Log log = LogFactory.getLog(ArtifactIndexer.class);
+
+ public Boolean support(String path) {
+ String relativePath = getRelativePath(path);
+ if (relativePath == null)
+ return false;
+ Artifact artifact = null;
+ try {
+ artifact = AetherUtils.convertPathToArtifact(relativePath, null);
+ } catch (Exception e) {
+ if (log.isTraceEnabled())
+ log.trace("Malformed path " + path + ", skipping silently", e);
+ }
+ return artifact != null;
+ }
+
+ public void index(Node fileNode) {
+ Artifact artifact = null;
+ try {
+ if (!fileNode.isNodeType(NodeType.NT_FILE))
+ return;
+
+ String relativePath = getRelativePath(fileNode.getPath());
+ if (relativePath == null)
+ return;
+ artifact = AetherUtils.convertPathToArtifact(relativePath, null);
+ // support() guarantees that artifact won't be null, no NPE check
+ fileNode.addMixin(SlcTypes.SLC_ARTIFACT);
+ fileNode.setProperty(SlcNames.SLC_ARTIFACT_ID,
+ artifact.getArtifactId());
+ fileNode.setProperty(SlcNames.SLC_GROUP_ID, artifact.getGroupId());
+ fileNode.setProperty(SlcNames.SLC_ARTIFACT_VERSION,
+ artifact.getVersion());
+ fileNode.setProperty(SlcNames.SLC_ARTIFACT_EXTENSION,
+ artifact.getExtension());
+ // can be null but ok for JCR API
+ fileNode.setProperty(SlcNames.SLC_ARTIFACT_CLASSIFIER,
+ artifact.getClassifier());
+
+ // set higher levels
+ Node artifactVersionBase = fileNode.getParent();
+ if (!artifactVersionBase
+ .isNodeType(SlcTypes.SLC_ARTIFACT_VERSION_BASE)) {
+ artifactVersionBase
+ .addMixin(SlcTypes.SLC_ARTIFACT_VERSION_BASE);
+ artifactVersionBase.setProperty(SlcNames.SLC_ARTIFACT_VERSION,
+ artifact.getBaseVersion());
+ artifactVersionBase.setProperty(SlcNames.SLC_ARTIFACT_ID,
+ artifact.getArtifactId());
+ artifactVersionBase.setProperty(SlcNames.SLC_GROUP_ID,
+ artifact.getGroupId());
+ }
+ Node artifactBase = artifactVersionBase.getParent();
+ if (!artifactBase.isNodeType(SlcTypes.SLC_ARTIFACT_BASE)) {
+ artifactBase.addMixin(SlcTypes.SLC_ARTIFACT_BASE);
+ artifactBase.setProperty(SlcNames.SLC_ARTIFACT_ID,
+ artifact.getArtifactId());
+ artifactBase.setProperty(SlcNames.SLC_GROUP_ID,
+ artifact.getGroupId());
+ }
+ Node groupBase = artifactBase.getParent();
+ if (!groupBase.isNodeType(SlcTypes.SLC_GROUP_BASE)) {
+ groupBase.addMixin(SlcTypes.SLC_GROUP_BASE);
+ groupBase.setProperty(SlcNames.SLC_GROUP_ID,
+ artifact.getGroupId());
+ }
+
+ if (log.isTraceEnabled())
+ log.trace("Indexed artifact " + artifact + " on " + fileNode);
+ } catch (Exception e) {
+ throw new SlcException("Cannot index artifact " + artifact
+ + " metadata on node " + fileNode, e);
+ }
+ }
+
+ private String getRelativePath(String nodePath) {
+ String basePath = RepoConstants.ARTIFACTS_BASE_PATH;
+ if (!nodePath.startsWith(basePath))
+ return null;
+ String relativePath = nodePath.substring(basePath.length());
+ return relativePath;
+ }
+}
--- /dev/null
+package org.argeo.slc.repo;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.Attributes.Name;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+import javax.jcr.Binary;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.SlcException;
+import org.argeo.slc.jcr.SlcNames;
+import org.argeo.slc.jcr.SlcTypes;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+
+/**
+ * Indexes jar file, currently supports standard J2SE and OSGi metadata (both
+ * from MANIFEST)
+ */
+public class JarFileIndexer implements NodeIndexer {
+ private final static Log log = LogFactory.getLog(JarFileIndexer.class);
+
+ public Boolean support(String path) {
+ return FilenameUtils.getExtension(path).equals("jar");
+ }
+
+ public void index(Node fileNode) {
+ Binary fileBinary = null;
+ JarInputStream jarIn = null;
+ ByteArrayOutputStream bo = null;
+ ByteArrayInputStream bi = null;
+ Binary manifestBinary = null;
+ try {
+ if (!fileNode.isNodeType(NodeType.NT_FILE))
+ return;
+
+ Session jcrSession = fileNode.getSession();
+ Node contentNode = fileNode.getNode(Node.JCR_CONTENT);
+ fileBinary = contentNode.getProperty(Property.JCR_DATA).getBinary();
+ // jar file
+ // if (!FilenameUtils.isExtension(fileNode.getName(), "jar")) {
+ // return;
+ // }
+
+ jarIn = new JarInputStream(fileBinary.getStream());
+ Manifest manifest = jarIn.getManifest();
+ if(manifest==null){
+ log.error(fileNode+" has no MANIFEST");
+ return;
+ }
+ bo = new ByteArrayOutputStream();
+ manifest.write(bo);
+ bi = new ByteArrayInputStream(bo.toByteArray());
+ manifestBinary = jcrSession.getValueFactory().createBinary(bi);
+
+ // standard jar file
+ fileNode.addMixin(SlcTypes.SLC_JAR_FILE);
+ fileNode.setProperty(SlcNames.SLC_MANIFEST, manifestBinary);
+ Attributes attrs = manifest.getMainAttributes();
+ if (log.isTraceEnabled())
+ for (Object key : attrs.keySet())
+ log.trace(key + ": " + attrs.getValue(key.toString()));
+
+ // standard J2SE MANIFEST attributes
+ addAttr(Attributes.Name.MANIFEST_VERSION, fileNode, attrs);
+ addAttr(Attributes.Name.SIGNATURE_VERSION, fileNode, attrs);
+ addAttr(Attributes.Name.CLASS_PATH, fileNode, attrs);
+ addAttr(Attributes.Name.MAIN_CLASS, fileNode, attrs);
+ addAttr(Attributes.Name.EXTENSION_NAME, fileNode, attrs);
+ addAttr(Attributes.Name.IMPLEMENTATION_VERSION, fileNode, attrs);
+ addAttr(Attributes.Name.IMPLEMENTATION_VENDOR, fileNode, attrs);
+ addAttr(Attributes.Name.IMPLEMENTATION_VENDOR_ID, fileNode, attrs);
+ addAttr(Attributes.Name.SPECIFICATION_TITLE, fileNode, attrs);
+ addAttr(Attributes.Name.SPECIFICATION_VERSION, fileNode, attrs);
+ addAttr(Attributes.Name.SPECIFICATION_VENDOR, fileNode, attrs);
+ addAttr(Attributes.Name.SEALED, fileNode, attrs);
+
+ // OSGi
+ if (attrs.containsKey(new Name(Constants.BUNDLE_SYMBOLICNAME))) {
+ addOsgiMetadata(fileNode, attrs);
+ if (log.isTraceEnabled())
+ log.trace("Indexed OSGi bundle " + fileNode);
+ } else {
+ if (log.isTraceEnabled())
+ log.trace("Indexed JAR file " + fileNode);
+ }
+ } catch (Exception e) {
+ throw new SlcException("Cannot index jar " + fileNode, e);
+ } finally {
+ IOUtils.closeQuietly(bi);
+ IOUtils.closeQuietly(bo);
+ IOUtils.closeQuietly(jarIn);
+ JcrUtils.closeQuietly(manifestBinary);
+ JcrUtils.closeQuietly(fileBinary);
+ }
+
+ }
+
+ protected void addOsgiMetadata(Node fileNode, Attributes attrs)
+ throws RepositoryException {
+ fileNode.addMixin(SlcTypes.SLC_BUNDLE_ARTIFACT);
+
+ // symbolic name
+ String symbolicName = attrs.getValue(Constants.BUNDLE_SYMBOLICNAME);
+ // make sure there is no directive
+ symbolicName = symbolicName.split(";")[0];
+ fileNode.setProperty(SlcNames.SLC_SYMBOLIC_NAME, symbolicName);
+
+ // direct mapping
+ addAttr(Constants.BUNDLE_SYMBOLICNAME, fileNode, attrs);
+ addAttr(Constants.BUNDLE_NAME, fileNode, attrs);
+ addAttr(Constants.BUNDLE_DESCRIPTION, fileNode, attrs);
+ addAttr(Constants.BUNDLE_MANIFESTVERSION, fileNode, attrs);
+ addAttr(Constants.BUNDLE_CATEGORY, fileNode, attrs);
+ addAttr(Constants.BUNDLE_ACTIVATIONPOLICY, fileNode, attrs);
+ addAttr(Constants.BUNDLE_COPYRIGHT, fileNode, attrs);
+ addAttr(Constants.BUNDLE_VENDOR, fileNode, attrs);
+ addAttr("Bundle-License", fileNode, attrs);
+ addAttr(Constants.BUNDLE_DOCURL, fileNode, attrs);
+ addAttr(Constants.BUNDLE_CONTACTADDRESS, fileNode, attrs);
+ addAttr(Constants.BUNDLE_ACTIVATOR, fileNode, attrs);
+ addAttr(Constants.BUNDLE_UPDATELOCATION, fileNode, attrs);
+ addAttr(Constants.BUNDLE_LOCALIZATION, fileNode, attrs);
+
+ // required execution environment
+ if (attrs.containsKey(new Name(
+ Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)))
+ fileNode.setProperty(SlcNames.SLC_
+ + Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT, attrs
+ .getValue(Constants.BUNDLE_REQUIREDEXECUTIONENVIRONMENT)
+ .split(","));
+
+ // bundle classpath
+ if (attrs.containsKey(new Name(Constants.BUNDLE_CLASSPATH)))
+ fileNode.setProperty(SlcNames.SLC_ + Constants.BUNDLE_CLASSPATH,
+ attrs.getValue(Constants.BUNDLE_CLASSPATH).split(","));
+
+ // version
+ Version version = new Version(attrs.getValue(Constants.BUNDLE_VERSION));
+ fileNode.setProperty(SlcNames.SLC_BUNDLE_VERSION, version.toString());
+ cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.BUNDLE_VERSION);
+ Node bundleVersionNode = fileNode.addNode(SlcNames.SLC_
+ + Constants.BUNDLE_VERSION, SlcTypes.SLC_OSGI_VERSION);
+ mapOsgiVersion(version, bundleVersionNode);
+
+ // fragment
+ cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.FRAGMENT_HOST);
+ if (attrs.containsKey(new Name(Constants.FRAGMENT_HOST))) {
+ String fragmentHost = attrs.getValue(Constants.FRAGMENT_HOST);
+ String[] tokens = fragmentHost.split(";");
+ Node node = fileNode.addNode(SlcNames.SLC_
+ + Constants.FRAGMENT_HOST, SlcTypes.SLC_FRAGMENT_HOST);
+ node.setProperty(SlcNames.SLC_SYMBOLIC_NAME, tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i].startsWith(Constants.BUNDLE_VERSION_ATTRIBUTE)) {
+ node.setProperty(SlcNames.SLC_BUNDLE_VERSION,
+ attributeValue(tokens[i]));
+ }
+ }
+ }
+
+ // imported packages
+ cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.IMPORT_PACKAGE);
+ if (attrs.containsKey(new Name(Constants.IMPORT_PACKAGE))) {
+ String importPackages = attrs.getValue(Constants.IMPORT_PACKAGE);
+ List<String> packages = parsePackages(importPackages);
+ for (String pkg : packages) {
+ String[] tokens = pkg.split(";");
+ Node node = fileNode.addNode(SlcNames.SLC_
+ + Constants.IMPORT_PACKAGE,
+ SlcTypes.SLC_IMPORTED_PACKAGE);
+ node.setProperty(SlcNames.SLC_NAME, tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
+ node.setProperty(SlcNames.SLC_VERSION,
+ attributeValue(tokens[i]));
+ } else if (tokens[i]
+ .startsWith(Constants.RESOLUTION_DIRECTIVE)) {
+ node.setProperty(
+ SlcNames.SLC_OPTIONAL,
+ directiveValue(tokens[i]).equals(
+ Constants.RESOLUTION_OPTIONAL));
+ }
+ }
+ }
+ }
+
+ // dynamic import package
+ cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.DYNAMICIMPORT_PACKAGE);
+ if (attrs.containsKey(new Name(Constants.DYNAMICIMPORT_PACKAGE))) {
+ String importPackages = attrs
+ .getValue(Constants.DYNAMICIMPORT_PACKAGE);
+ List<String> packages = parsePackages(importPackages);
+ for (String pkg : packages) {
+ String[] tokens = pkg.split(";");
+ Node node = fileNode.addNode(SlcNames.SLC_
+ + Constants.DYNAMICIMPORT_PACKAGE,
+ SlcTypes.SLC_DYNAMIC_IMPORTED_PACKAGE);
+ node.setProperty(SlcNames.SLC_NAME, tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
+ node.setProperty(SlcNames.SLC_VERSION,
+ attributeValue(tokens[i]));
+ }
+ }
+ }
+ }
+
+ // exported packages
+ cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.EXPORT_PACKAGE);
+ if (attrs.containsKey(new Name(Constants.EXPORT_PACKAGE))) {
+ String exportPackages = attrs.getValue(Constants.EXPORT_PACKAGE);
+ List<String> packages = parsePackages(exportPackages);
+ for (String pkg : packages) {
+ String[] tokens = pkg.split(";");
+ Node node = fileNode.addNode(SlcNames.SLC_
+ + Constants.EXPORT_PACKAGE,
+ SlcTypes.SLC_EXPORTED_PACKAGE);
+ node.setProperty(SlcNames.SLC_NAME, tokens[0]);
+ // TODO: are these cleans really necessary?
+ cleanSubNodes(node, SlcNames.SLC_USES);
+ cleanSubNodes(node, SlcNames.SLC_VERSION);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i].startsWith(Constants.VERSION_ATTRIBUTE)) {
+ String versionStr = attributeValue(tokens[i]);
+ Node versionNode = node.addNode(SlcNames.SLC_VERSION,
+ SlcTypes.SLC_OSGI_VERSION);
+ mapOsgiVersion(new Version(versionStr), versionNode);
+ } else if (tokens[i].startsWith(Constants.USES_DIRECTIVE)) {
+ String usedPackages = directiveValue(tokens[i]);
+ // log.debug("uses='" + usedPackages + "'");
+ for (String usedPackage : usedPackages.split(",")) {
+ // log.debug("usedPackage='" +
+ // usedPackage +
+ // "'");
+ Node usesNode = node.addNode(SlcNames.SLC_USES,
+ SlcTypes.SLC_JAVA_PACKAGE);
+ usesNode.setProperty(SlcNames.SLC_NAME, usedPackage);
+ }
+ }
+ }
+ }
+ }
+
+ // required bundle
+ cleanSubNodes(fileNode, SlcNames.SLC_ + Constants.REQUIRE_BUNDLE);
+ if (attrs.containsKey(new Name(Constants.REQUIRE_BUNDLE))) {
+ String requireBundle = attrs.getValue(Constants.REQUIRE_BUNDLE);
+ String[] bundles = requireBundle.split(",");
+ for (String bundle : bundles) {
+ String[] tokens = bundle.split(";");
+ Node node = fileNode.addNode(SlcNames.SLC_
+ + Constants.REQUIRE_BUNDLE,
+ SlcTypes.SLC_REQUIRED_BUNDLE);
+ node.setProperty(SlcNames.SLC_SYMBOLIC_NAME, tokens[0]);
+ for (int i = 1; i < tokens.length; i++) {
+ if (tokens[i]
+ .startsWith(Constants.BUNDLE_VERSION_ATTRIBUTE)) {
+ node.setProperty(SlcNames.SLC_BUNDLE_VERSION,
+ attributeValue(tokens[i]));
+ } else if (tokens[i]
+ .startsWith(Constants.RESOLUTION_DIRECTIVE)) {
+ node.setProperty(
+ SlcNames.SLC_OPTIONAL,
+ directiveValue(tokens[i]).equals(
+ Constants.RESOLUTION_OPTIONAL));
+ }
+ }
+ }
+ }
+
+ }
+
+ private void addAttr(String key, Node node, Attributes attrs)
+ throws RepositoryException {
+ addAttr(new Name(key), node, attrs);
+ }
+
+ private void addAttr(Name key, Node node, Attributes attrs)
+ throws RepositoryException {
+ if (attrs.containsKey(key)) {
+ String value = attrs.getValue(key);
+ node.setProperty(SlcNames.SLC_ + key, value);
+ }
+ }
+
+ private void cleanSubNodes(Node node, String name)
+ throws RepositoryException {
+ if (node.hasNode(name)) {
+ NodeIterator nit = node.getNodes(name);
+ while (nit.hasNext())
+ nit.nextNode().remove();
+ }
+ }
+
+ private String attributeValue(String str) {
+ return extractValue(str, "=");
+ }
+
+ private String directiveValue(String str) {
+ return extractValue(str, ":=");
+ }
+
+ private String extractValue(String str, String eq) {
+ String[] tokens = str.split(eq);
+ // String key = tokens[0];
+ String value = tokens[1].trim();
+ // TODO: optimize?
+ if (value.startsWith("\""))
+ value = value.substring(1);
+ if (value.endsWith("\""))
+ value = value.substring(0, value.length() - 1);
+ return value;
+ }
+
+ /** Parse package list with nested directive with ',' */
+ private List<String> parsePackages(String str) {
+ List<String> res = new ArrayList<String>();
+ StringBuffer curr = new StringBuffer("");
+ boolean in = false;
+ for (char c : str.toCharArray()) {
+ if (c == ',') {
+ if (!in) {
+ res.add(curr.toString());
+ curr = new StringBuffer("");
+ }
+ } else if (c == '\"') {
+ in = !in;
+ curr.append(c);
+ } else {
+ curr.append(c);
+ }
+ }
+ res.add(curr.toString());
+ // log.debug(res);
+ return res;
+ }
+
+ protected void mapOsgiVersion(Version version, Node versionNode)
+ throws RepositoryException {
+ versionNode.setProperty(SlcNames.SLC_AS_STRING, version.toString());
+ versionNode.setProperty(SlcNames.SLC_MAJOR, version.getMajor());
+ versionNode.setProperty(SlcNames.SLC_MINOR, version.getMinor());
+ versionNode.setProperty(SlcNames.SLC_MICRO, version.getMicro());
+ if (!version.getQualifier().equals(""))
+ versionNode.setProperty(SlcNames.SLC_QUALIFIER,
+ version.getQualifier());
+ }
+
+}
--- /dev/null
+package org.argeo.slc.repo;
+
+import javax.jcr.Node;
+import javax.jcr.observation.EventListener;
+
+/**
+ * Adds metadata to an existing node, ideally via observation after it has been
+ * added. THere is a similar concept in ModeShape with which this abstraction
+ * may be merged in the future.
+ */
+public interface NodeIndexer {
+ /**
+ * Whether the node at this path will be supported. This is typically use in
+ * an {@link EventListener} before the node is loaded, and would apply on
+ * information contained in the path / file name: file extension, base path,
+ * etc. If the node needs to be loaded, the recommended approach is to
+ * return <code>true</code> here and wait for index to be called, possibly
+ * returning without processing if the node should node be indexed. While
+ * not stricly a requirements, this avoids to open sessions in the indexer,
+ * centrlaizing such tasks in the caller.
+ */
+ public Boolean support(String path);
+
+ /**
+ * Adds the metadata. This is the responsibility of the caller to save the
+ * udnerlying session.
+ */
+ public void index(Node node);
+}
--- /dev/null
+package org.argeo.slc.repo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.observation.Event;
+import javax.jcr.observation.EventIterator;
+import javax.jcr.observation.EventListener;
+
+import org.argeo.jcr.JcrUtils;
+import org.argeo.slc.SlcException;
+
+/** Repository backend, maintain the JCR repository, mainly through listeners */
+public class RepoImpl {
+
+ private Repository jcrRepository;
+ private Session adminSession;
+
+ private ArtifactListener artifactListener;
+
+ /** order may be important */
+ private List<NodeIndexer> nodeIndexers = new ArrayList<NodeIndexer>();
+
+ public void init() {
+ try {
+ adminSession = jcrRepository.login();
+ artifactListener = new ArtifactListener();
+ adminSession
+ .getWorkspace()
+ .getObservationManager()
+ .addEventListener(artifactListener, Event.NODE_ADDED,
+ RepoConstants.ARTIFACTS_BASE_PATH, true, null,
+ null, true);
+ } catch (RepositoryException e) {
+ throw new SlcException("Cannot initialize repository backend", e);
+ }
+ }
+
+ public void destroy() {
+ JcrUtils.logoutQuietly(adminSession);
+ }
+
+ public void setJcrRepository(Repository jcrRepository) {
+ this.jcrRepository = jcrRepository;
+ }
+
+ public void setNodeIndexers(List<NodeIndexer> nodeIndexers) {
+ this.nodeIndexers = nodeIndexers;
+ }
+
+ class ArtifactListener implements EventListener {
+
+ public void onEvent(EventIterator events) {
+ while (events.hasNext()) {
+ Event event = events.nextEvent();
+ try {
+ String newNodePath = event.getPath();
+ Node newNode = null;
+ for (NodeIndexer nodeIndexer : nodeIndexers) {
+ try {
+ if (nodeIndexer.support(newNodePath)) {
+ if (newNode == null)
+ newNode = adminSession.getNode(newNodePath);
+ nodeIndexer.index(newNode);
+ }
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ throw e;
+ }
+ }
+ if (newNode != null)
+ adminSession.save();
+ } catch (RepositoryException e) {
+ throw new SlcException("Cannot process event " + event, e);
+ } finally {
+ JcrUtils.discardQuietly(adminSession);
+ }
+ }
+
+ }
+
+ }
+
+}
import org.argeo.slc.aether.AetherTemplate;
import org.argeo.slc.jcr.SlcNames;
import org.argeo.slc.jcr.SlcTypes;
+import org.argeo.slc.repo.ArtifactIndexer;
import org.argeo.slc.repo.RepoConstants;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
private String distributionsBasePath = "/slc/repo/distributions";
private String distributionName;
+ private ArtifactIndexer artifactIndexer = new ArtifactIndexer();
+
public void run() {
log.debug(jcrSession.getUserID());
Set<Artifact> artifacts = resolveDistribution();
} else {
fileNode = parentNode.getNode(file.getName());
}
- processArtifact(fileNode, artifact);
+
+ if (artifactIndexer.support(fileNode.getPath()))
+ artifactIndexer.index(fileNode);
if (fileNode.isNodeType(SlcTypes.SLC_JAR_FILE)) {
processOsgiBundle(fileNode);
}
}
}
- protected void processArtifact(Node fileNode, Artifact artifact) {
- try {
- fileNode.addMixin(SlcTypes.SLC_ARTIFACT);
- fileNode.setProperty(SlcNames.SLC_ARTIFACT_ID,
- artifact.getArtifactId());
- fileNode.setProperty(SlcNames.SLC_GROUP_ID, artifact.getGroupId());
- fileNode.setProperty(SlcNames.SLC_ARTIFACT_VERSION,
- artifact.getVersion());
- fileNode.setProperty(SlcNames.SLC_ARTIFACT_EXTENSION,
- artifact.getExtension());
- fileNode.setProperty(SlcNames.SLC_ARTIFACT_CLASSIFIER,
- artifact.getClassifier());
- } catch (RepositoryException e) {
- throw new SlcException("Cannot process artifact " + artifact
- + " on node " + fileNode, e);
- }
-
- }
-
protected File artifactToFile(Artifact artifact) {
return new File(System.getProperty("user.home")
+ File.separator
package org.argeo.slc.repo.maven.proxy;
-/** Synchronizes JCR and Maven repositories */
-public interface MavenProxyService {
- public String getNodePath(String path);
+import org.argeo.jcr.proxy.ResourceProxy;
- public String proxyFile(String path);
+/** Marker interface (useful for OSGi servcies references), maybe extended later */
+public interface MavenProxyService extends ResourceProxy {
}
package org.argeo.slc.repo.maven.proxy;
-import java.io.InputStream;
-import java.net.URL;
import java.util.ArrayList;
import java.util.List;
-import javax.jcr.Binary;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
-import javax.jcr.Property;
-import javax.jcr.Repository;
import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.nodetype.NodeType;
-import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.argeo.jcr.ArgeoNames;
import org.argeo.jcr.JcrUtils;
+import org.argeo.jcr.proxy.AbstractUrlProxy;
import org.argeo.slc.SlcException;
import org.argeo.slc.jcr.SlcNames;
import org.argeo.slc.repo.RepoConstants;
import org.sonatype.aether.repository.RemoteRepository;
/** Synchronizes the node repository with remote Maven repositories */
-public class MavenProxyServiceImpl implements MavenProxyService, ArgeoNames,
- SlcNames {
+public class MavenProxyServiceImpl extends AbstractUrlProxy implements
+ MavenProxyService, ArgeoNames, SlcNames {
private final static Log log = LogFactory
.getLog(MavenProxyServiceImpl.class);
- private Repository jcrRepository;
- private Session jcrAdminSession;
private List<RemoteRepository> defaultRepositories = new ArrayList<RemoteRepository>();
- public void init() {
- try {
- jcrAdminSession = jcrRepository.login();
-
- JcrUtils.mkdirs(jcrAdminSession, RepoConstants.ARTIFACTS_BASE_PATH);
- Node proxiedRepositories = JcrUtils.mkdirs(jcrAdminSession,
- RepoConstants.PROXIED_REPOSITORIES);
- for (RemoteRepository repository : defaultRepositories) {
- if (!proxiedRepositories.hasNode(repository.getId())) {
- Node proxiedRepository = proxiedRepositories
- .addNode(repository.getId());
- proxiedRepository.setProperty(SLC_URL, repository.getUrl());
- proxiedRepository.setProperty(SLC_TYPE,
- repository.getContentType());
- }
+ @Override
+ protected void beforeInitSessionSave() throws RepositoryException {
+ JcrUtils.mkdirs(getJcrAdminSession(), RepoConstants.ARTIFACTS_BASE_PATH);
+ Node proxiedRepositories = JcrUtils.mkdirs(getJcrAdminSession(),
+ RepoConstants.PROXIED_REPOSITORIES);
+ for (RemoteRepository repository : defaultRepositories) {
+ if (!proxiedRepositories.hasNode(repository.getId())) {
+ Node proxiedRepository = proxiedRepositories.addNode(repository
+ .getId());
+ proxiedRepository.setProperty(SLC_URL, repository.getUrl());
+ proxiedRepository.setProperty(SLC_TYPE,
+ repository.getContentType());
}
- jcrAdminSession.save();
- } catch (RepositoryException e) {
- JcrUtils.discardQuietly(jcrAdminSession);
- throw new SlcException("Cannot initialize Maven proxy", e);
}
}
- public void destroy() {
- JcrUtils.logoutQuietly(jcrAdminSession);
- }
-
/**
* Retrieve and add this file to the repository
*/
- public synchronized String proxyFile(String path) {
+ protected String retrieve(String path) {
try {
Node node = null;
- proxiedRepositories: for (NodeIterator nit = jcrAdminSession
- .getNode(RepoConstants.PROXIED_REPOSITORIES).getNodes(); nit
- .hasNext();) {
- Node proxiedRepository = nit.nextNode();
- String repoUrl = proxiedRepository.getProperty(SLC_URL)
- .getString();
- String remoteUrl = repoUrl + path;
- if (log.isTraceEnabled())
- log.trace("remoteUrl=" + remoteUrl);
- InputStream in = null;
- try {
- URL u = new URL(remoteUrl);
- in = u.openStream();
- node = importFile(getNodePath(path), in);
- if (log.isDebugEnabled())
- log.debug("Imported " + remoteUrl + " to " + node);
- break proxiedRepositories;
- } catch (Exception e) {
- if (log.isDebugEnabled())
- log.debug("Cannot read " + remoteUrl + ", skipping... "
- + e.getMessage());
- // e.printStackTrace();
- } finally {
- IOUtils.closeQuietly(in);
- }
+ baseUrls: for (String baseUrl : getBaseUrls()) {
+ node = proxyUrl(baseUrl, path);
+ if (node != null)
+ break baseUrls;
}
if (node != null)
}
}
- /** The JCR path where this file could be found */
- public String getNodePath(String path) {
- return RepoConstants.ARTIFACTS_BASE_PATH + path;
- }
-
- protected Node importFile(String nodePath, InputStream in) {
- Binary binary = null;
- try {
- Node node = JcrUtils.mkdirs(jcrAdminSession, nodePath,
- NodeType.NT_FILE, NodeType.NT_FOLDER, false);
- Node content = node.addNode(Node.JCR_CONTENT, NodeType.NT_RESOURCE);
- binary = jcrAdminSession.getValueFactory().createBinary(in);
- content.setProperty(Property.JCR_DATA, binary);
- jcrAdminSession.save();
- return node;
- } catch (RepositoryException e) {
- JcrUtils.discardQuietly(jcrAdminSession);
- throw new SlcException("Cannot initialize Maven proxy", e);
- } finally {
- JcrUtils.closeQuietly(binary);
+ protected synchronized List<String> getBaseUrls()
+ throws RepositoryException {
+ List<String> baseUrls = new ArrayList<String>();
+ for (NodeIterator nit = getJcrAdminSession().getNode(
+ RepoConstants.PROXIED_REPOSITORIES).getNodes(); nit.hasNext();) {
+ Node proxiedRepository = nit.nextNode();
+ String repoUrl = proxiedRepository.getProperty(SLC_URL).getString();
+ baseUrls.add(repoUrl);
}
+ return baseUrls;
}
- public void setJcrRepository(Repository jcrRepository) {
- this.jcrRepository = jcrRepository;
+ /** The JCR path where this file could be found */
+ public String getNodePath(String path) {
+ return RepoConstants.ARTIFACTS_BASE_PATH + path;
}
public void setDefaultRepositories(
+++ /dev/null
-package org.argeo.slc.repo.maven.proxy;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.jcr.Binary;
-import javax.jcr.Node;
-import javax.jcr.Property;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.slc.SlcException;
-import org.argeo.slc.jcr.SlcNames;
-
-/**
- * Expose the SLC repository as a regular Maven repository, proxying third party
- * repositories as well.
- */
-public class MavenProxyServlet extends HttpServlet implements ArgeoNames,
- SlcNames {
- private static final long serialVersionUID = 5296857859305486588L;
-
- private final static Log log = LogFactory.getLog(MavenProxyServlet.class);
-
- private MavenProxyService proxyService;
-
- private Session jcrSession;
- private String contentTypeCharset = "UTF-8";
-
- @Override
- protected void doGet(HttpServletRequest request,
- HttpServletResponse response) throws ServletException, IOException {
- String path = request.getPathInfo();
-
- String nodePath = proxyService.getNodePath(path);
- if (log.isTraceEnabled())
- log.trace("path=" + path + ", nodePath=" + nodePath);
-
- try {
- Node node;
- if (!jcrSession.itemExists(nodePath)) {
- String nodeIdentifier = proxyService.proxyFile(path);
- if (nodeIdentifier == null) {
- //log.warn("Could not proxy " + path);
- response.sendError(404);
- return;
- } else {
- node = jcrSession.getNodeByIdentifier(nodeIdentifier);
- }
- } else {
- node = jcrSession.getNode(nodePath);
- }
- processResponse(nodePath, node, response);
- } catch (RepositoryException e) {
- throw new SlcException("Cannot proxy " + request, e);
- }
- //super.doGet(request, response);
- }
-
- /** Retrieve the content of the node. */
- protected void processResponse(String path, Node node,
- HttpServletResponse response) {
- Binary binary = null;
- InputStream in = null;
- try {
- String fileName = node.getName();
- String ext = FilenameUtils.getExtension(fileName);
-
- // TODO use a more generic / standard approach
- // see http://svn.apache.org/viewvc/tomcat/trunk/conf/web.xml
- String contentType;
- if ("xml".equals(ext))
- contentType = "text/xml;charset=" + contentTypeCharset;
- else if ("jar".equals(ext))
- contentType = "application/java-archive";
- else if ("zip".equals(ext))
- contentType = "application/zip";
- else if ("gz".equals(ext))
- contentType = "application/x-gzip";
- else if ("tar".equals(ext))
- contentType = "application/x-tar";
- else
- contentType = "application/octet-stream";
- contentType = contentType + ";name=\"" + fileName + "\"";
- response.setHeader("Content-Disposition", "attachment; filename=\""
- + fileName + "\"");
- response.setHeader("Expires", "0");
- response.setHeader("Cache-Control", "no-cache, must-revalidate");
- response.setHeader("Pragma", "no-cache");
-
- response.setContentType(contentType);
-
- binary = node.getNode(Property.JCR_CONTENT)
- .getProperty(Property.JCR_DATA).getBinary();
- in = binary.getStream();
- IOUtils.copy(in, response.getOutputStream());
- } catch (Exception e) {
- throw new SlcException("Cannot download " + node, e);
- } finally {
- IOUtils.closeQuietly(in);
- JcrUtils.closeQuietly(binary);
- }
- }
-
- public void setJcrSession(Session jcrSession) {
- this.jcrSession = jcrSession;
- }
-
- public void setProxyService(MavenProxyService proxyService) {
- this.proxyService = proxyService;
- }
-
-}
- slc:artifactExtension (STRING) m
- slc:artifactClassifier (STRING) ='' m a
+[slc:artifactVersionBase] > nt:base
+mixin
+- slc:artifactId (STRING) primary m
+- slc:groupId (STRING) m
+- slc:artifactVersion (STRING) m
+
+[slc:artifactBase] > nt:base
+mixin
+- slc:artifactId (STRING) primary m
+- slc:groupId (STRING) m
+
+[slc:groupBase] > nt:base
+mixin
+- slc:groupId (STRING) primary m
+
[slc:jarFile] > nt:base
mixin
- 'slc:manifest' (BINARY) m
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src/main/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
-source.. = src/main/java/
+source.. = src/main/java/,\
+ src/test/java/
output.. = target/classes/
bin.includes = META-INF/,\
.
+additional.bundles = com.springsource.junit,\
+ com.springsource.slf4j.api,\
+ com.springsource.slf4j.log4j,\
+ com.springsource.org.apache.log4j,\
+ com.springsource.slf4j.org.apache.commons.logging
+
\ No newline at end of file
package org.argeo.slc.aether;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FilenameUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.argeo.slc.SlcException;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
/** Utilities related to Aether */
public class AetherUtils {
+ public final static String SNAPSHOT = "SNAPSHOT";
+ // hacked from aether
+ public static final Pattern SNAPSHOT_TIMESTAMP = Pattern
+ .compile("^(.*-)?([0-9]{8}.[0-9]{6}-[0-9]+)$");
+
private final static Log log = LogFactory.getLog(AetherUtils.class);
/** Logs a dependency node and its transitive dependencies as a tree. */
}
}
+ /**
+ * Converts a path (relative to a repository root) to an {@link Artifact}.
+ *
+ * @param path
+ * the relative path
+ * @param type
+ * the layout type, currently ignored because only the 'default'
+ * Maven 2 layout is currently supported:
+ * /my/group/id/artifactId/
+ * version/artifactId-version[-classifier].extension
+ * @return the related artifact or null if the file is not an artifact
+ * (Maven medata data XML files, check sums, etc.)
+ */
+ public static Artifact convertPathToArtifact(String path, String type) {
+ // TODO rewrite it with regexp (unit tests first!)
+
+ // normalize
+ if (path.startsWith("/"))
+ path = path.substring(1);
+
+ // parse group id
+ String[] tokensSlash = path.split("/");
+ if (tokensSlash.length < 4)
+ return null;
+ StringBuffer groupId = new StringBuffer(path.length());
+ for (int i = 0; i < tokensSlash.length - 3; i++) {
+ if (i != 0)
+ groupId.append('.');
+ groupId.append(tokensSlash[i]);
+ }
+ String artifactId = tokensSlash[tokensSlash.length - 3];
+ String baseVersion = tokensSlash[tokensSlash.length - 2];
+ String fileName = tokensSlash[tokensSlash.length - 1];
+
+ if (!fileName.startsWith(artifactId))
+ return null;
+ // FIXME make it configurable? (via an argument?)
+ if (FilenameUtils.isExtension(fileName, new String[] { "sha1", "md5" }))
+ return null;
+
+ String extension = FilenameUtils.getExtension(fileName);
+ String baseName = FilenameUtils.getBaseName(fileName);
+
+ // check since we assume hereafter
+ if (!baseName.startsWith(artifactId))
+ throw new SlcException("Base name '" + baseName
+ + " does not start with artifact id '" + artifactId
+ + "' in " + path);
+
+ boolean isSnapshot = baseVersion.endsWith("-" + SNAPSHOT);
+ String baseBaseVersion = isSnapshot ? baseVersion.substring(0,
+ baseVersion.length() - SNAPSHOT.length() - 1) : baseVersion;
+ int artifactAndBaseBaseVersionLength = artifactId.length() + 1
+ + baseBaseVersion.length() + 1;
+ String classifier = null;
+ if (baseName.length() > artifactAndBaseBaseVersionLength) {
+ String dashRest = baseName
+ .substring(artifactAndBaseBaseVersionLength);
+ String[] dashes = dashRest.split("-");
+
+ if (isSnapshot) {
+ if (dashes[0].equals(SNAPSHOT)) {
+ if (dashRest.length() > SNAPSHOT.length() + 1)
+ classifier = dashRest.substring(SNAPSHOT.length() + 1);
+
+ } else {
+ if (dashes.length > 2)// assume no '-' in classifier
+ classifier = dashes[2];
+ }
+ } else {
+ if (dashes.length > 0)
+ classifier = dashes[0];
+ }
+ }
+
+ // classifier
+ // String classifier = null;
+ // int firstDash = baseName.indexOf('-');
+ // int classifierDash = baseName.lastIndexOf('-');
+ // if (classifierDash > 0 && classifierDash != firstDash) {
+ // classifier = baseName.substring(classifierDash + 1);
+ // }
+ // if (isSnapshot && classifier != null) {
+ // if (classifier.equals(SNAPSHOT))
+ // classifier = null;
+ // else
+ // try {
+ // Long.parseLong(classifier); // build number
+ // // if not failed this is a timestamped version
+ // classifier = null;
+ // } catch (NumberFormatException e) {
+ // // silent
+ // }
+ // }
+
+ // version
+ String version = baseName.substring(artifactId.length() + 1);
+ if (classifier != null)
+ version = version.substring(0,
+ version.length() - classifier.length() - 1);
+
+ // consistency checks
+ if (!isSnapshot && !version.equals(baseVersion))
+ throw new SlcException("Base version '" + baseVersion
+ + "' and version '" + version + "' not in line in " + path);
+ if (!isSnapshot && isSnapshotVersion(version))
+ throw new SlcException("SNAPSHOT base version '" + baseVersion
+ + "' and version '" + version + "' not in line in " + path);
+
+ DefaultArtifact artifact = new DefaultArtifact(groupId.toString(),
+ artifactId, classifier, extension, version);
+ return artifact;
+ }
+
+ /** Hacked from aether */
+ public static boolean isSnapshotVersion(String version) {
+ return version.endsWith(SNAPSHOT)
+ || SNAPSHOT_TIMESTAMP.matcher(version).matches();
+ }
+
}
--- /dev/null
+package org.argeo.slc.aether;
+
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.util.artifact.DefaultArtifact;
+
+import junit.framework.TestCase;
+
+public class AetherUtilsTest extends TestCase {
+ public void testConvertPathToArtifact() throws Exception {
+ checkPathConversion("my.group.id:my-artifactId:pom:1.2.3",
+ "/my/group/id/my-artifactId/1.2.3/my-artifactId-1.2.3.pom");
+ checkPathConversion("my.group.id:my-artifactId:pom:1.2.3-SNAPSHOT",
+ "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-1.2.3-SNAPSHOT.pom");
+ checkPathConversion("my.group.id:my-artifactId:pom:myClassifier:1.2.3",
+ "/my/group/id/my-artifactId/1.2.3/my-artifactId-1.2.3-myClassifier.pom");
+ checkPathConversion(
+ "my.group.id:my-artifactId:pom:myClassifier:1.2.3-SNAPSHOT",
+ "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-1.2.3-SNAPSHOT-myClassifier.pom");
+ checkPathConversion(
+ "my.group.id:my-artifactId:pom:myClassifier:20110828.223836-2",
+ "/my/group/id/my-artifactId/1.2.3-SNAPSHOT/my-artifactId-20110828.223836-2-myClassifier.pom");
+ }
+
+ public void testConvertPathToArtifactRealLife() throws Exception {
+ checkPathConversion(
+ "org.apache.maven.plugins:maven-antrun-plugin:pom:1.1",
+ "org/apache/maven/plugins/maven-antrun-plugin/1.1/maven-antrun-plugin-1.1.pom");
+ checkPathConversion(
+ "org.apache.maven.plugins:maven-plugin-parent:pom:2.0.1",
+ "org/apache/maven/plugins/maven-plugin-parent/2.0.1/maven-plugin-parent-2.0.1.pom");
+ checkPathConversion(
+ "org.apache.avalon.framework:avalon-framework-impl:pom:4.3.1",
+ "org/apache/avalon/framework/avalon-framework-impl/4.3.1/avalon-framework-impl-4.3.1.pom");
+ checkPathConversion(
+ "org.apache.maven.shared:maven-dependency-tree:pom:1.2",
+ "org/apache/maven/shared/maven-dependency-tree/1.2/maven-dependency-tree-1.2.pom");
+ checkPathConversion(
+ "org.argeo.maven.plugins:maven-argeo-osgi-plugin:pom:1.0.33",
+ "org/argeo/maven/plugins/maven-argeo-osgi-plugin/1.0.33/maven-argeo-osgi-plugin-1.0.33.pom");
+ checkPathConversion(
+ "org.apache.maven.plugins:maven-clean-plugin:pom:2.4.1",
+ "org/apache/maven/plugins/maven-clean-plugin/2.4.1/maven-clean-plugin-2.4.1.pom");
+ }
+
+ protected void checkPathConversion(String expectedArtifact, String path) {
+ Artifact artifact = AetherUtils.convertPathToArtifact(path, null);
+ if (expectedArtifact == null)
+ assertNull(artifact);
+ else
+ assertEquals(new DefaultArtifact(expectedArtifact), artifact);
+ }
+}
http://www.springframework.org/schema/beans \r
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">\r
\r
+ <!-- SERVICES -->\r
<service ref="mavenRepositorySystem" interface="org.sonatype.aether.RepositorySystem">\r
<service-properties>\r
<beans:entry key="aether.repositorySystemType" value="maven" />\r