Index: dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java =================================================================== --- dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java (revision 938) +++ dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java (working copy) @@ -42,6 +42,7 @@ import org.jboss.dna.common.component.StandardClassLoaderFactory; import org.jboss.dna.common.util.CheckArg; import org.jboss.dna.common.util.Logger; +import org.jboss.dna.common.util.Reflection; import org.jboss.dna.graph.connector.federation.FederatedLexicon; import org.jboss.dna.graph.mimetype.ExtensionBasedMimeTypeDetector; import org.jboss.dna.graph.mimetype.MimeTypeDetector; @@ -528,6 +529,9 @@ * @see javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[]) */ public void handle( Callback[] callbacks ) throws UnsupportedCallbackException, IOException { + boolean userSet = false; + boolean passwordSet = false; + for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof TextOutputCallback) { @@ -563,6 +567,7 @@ } nc.setName(this.userId); + userSet = true; } else if (callbacks[i] instanceof PasswordCallback) { @@ -573,9 +578,32 @@ System.out.flush(); } pc.setPassword(this.password); + passwordSet = true; } else { - throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback"); + /* + * Jetty uses its own callback for setting the password. Since we're using Jetty for integration + * testing of the web project(s), we have to accomodate this. Rather than introducing a direct + * dependency, we'll add code to handle the case of unexpected callback handlers with a setObject method. + */ + try { + // Assume that a callback chain will ask for the user before the password + if (!userSet) { + new Reflection(callbacks[i].getClass()).invokeSetterMethodOnTarget("object", callbacks[i], this.userId); + userSet = true; + } + else if (!passwordSet) { + // Jetty also seems to eschew passing passwords as char arrays + new Reflection(callbacks[i].getClass()).invokeSetterMethodOnTarget("object", callbacks[i], new String(this.password)); + passwordSet = true; + } + // It worked - need to continue processing the callbacks + continue; + } catch (Exception ex) { + // If the property cannot be set, fall through to the failure + } + throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback: " + + callbacks[i].getClass().getName()); } } Index: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java =================================================================== --- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java (revision 938) +++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrEngine.java (working copy) @@ -23,7 +23,10 @@ */ package org.jboss.dna.jcr; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; @@ -44,6 +47,7 @@ import org.jboss.dna.graph.property.Property; import org.jboss.dna.jcr.JcrRepository.Option; import org.jboss.dna.repository.DnaEngine; +import org.jboss.dna.repository.RepositoryLibrary; import org.jboss.dna.repository.RepositoryService; import org.jboss.dna.repository.sequencer.SequencingService; @@ -103,6 +107,24 @@ } /** + * Returns a list of the names of all available JCR repositories. + *

+ * In a {@code JcrEngine}, the available repositories are {@link RepositoryLibrary#getSourceNames() all repositories} except + * for the {@link RepositoryService#getConfigurationSourceName() the configuration repository}. + *

+ * + * @return a list of all repository names. + */ + public final Collection getJcrRepositoryNames() { + List jcrRepositories = new ArrayList(); + jcrRepositories.addAll(getRepositoryService().getRepositoryLibrary().getSourceNames()); + + jcrRepositories.remove(getRepositoryService().getConfigurationSourceName()); + + return jcrRepositories; + } + + /** * Get the {@link Repository} implementation for the named repository. * * @param repositoryName the name of the repository, which corresponds to the name of a configured {@link RepositorySource} Index: extensions/dna-web-jcr-rest-war/.classpath =================================================================== --- extensions/dna-web-jcr-rest-war/.classpath (revision 0) +++ extensions/dna-web-jcr-rest-war/.classpath (revision 0) @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + Index: extensions/dna-web-jcr-rest-war/.project =================================================================== --- extensions/dna-web-jcr-rest-war/.project (revision 0) +++ extensions/dna-web-jcr-rest-war/.project (revision 0) @@ -0,0 +1,42 @@ + + + dna-web-jcr-rest-war + + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + Index: extensions/dna-web-jcr-rest-war/.settings/.jsdtscope =================================================================== --- extensions/dna-web-jcr-rest-war/.settings/.jsdtscope (revision 0) +++ extensions/dna-web-jcr-rest-war/.settings/.jsdtscope (revision 0) @@ -0,0 +1,11 @@ + + + + + + + + + + + Index: extensions/dna-web-jcr-rest-war/.settings/org.eclipse.jdt.core.prefs =================================================================== --- extensions/dna-web-jcr-rest-war/.settings/org.eclipse.jdt.core.prefs (revision 0) +++ extensions/dna-web-jcr-rest-war/.settings/org.eclipse.jdt.core.prefs (revision 0) @@ -0,0 +1,7 @@ +#Wed May 27 16:41:12 EDT 2009 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 Index: extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.common.component =================================================================== --- extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.common.component (revision 0) +++ extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.common.component (revision 0) @@ -0,0 +1,31 @@ + + + + + + + + uses + + + uses + + + uses + + + uses + + + uses + + + uses + + + uses + + + + + Index: extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.common.project.facet.core.xml =================================================================== --- extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.common.project.facet.core.xml (revision 0) +++ extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.common.project.facet.core.xml (revision 0) @@ -0,0 +1,5 @@ + + + + + Property changes on: extensions\dna-web-jcr-rest-war\.settings\org.eclipse.wst.common.project.facet.core.xml ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.jsdt.ui.superType.container =================================================================== --- extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.jsdt.ui.superType.container (revision 0) +++ extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.jsdt.ui.superType.container (revision 0) @@ -0,0 +1 @@ +org.eclipse.wst.jsdt.launching.baseBrowserLibrary \ No newline at end of file Index: extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.jsdt.ui.superType.name =================================================================== --- extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.jsdt.ui.superType.name (revision 0) +++ extensions/dna-web-jcr-rest-war/.settings/org.eclipse.wst.jsdt.ui.superType.name (revision 0) @@ -0,0 +1 @@ +Window \ No newline at end of file Index: extensions/dna-web-jcr-rest-war/.settings/org.maven.ide.eclipse.prefs =================================================================== --- extensions/dna-web-jcr-rest-war/.settings/org.maven.ide.eclipse.prefs (revision 0) +++ extensions/dna-web-jcr-rest-war/.settings/org.maven.ide.eclipse.prefs (revision 0) @@ -0,0 +1,9 @@ +#Wed May 27 16:41:08 EDT 2009 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=true +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 Index: extensions/dna-web-jcr-rest-war/pom.xml =================================================================== --- extensions/dna-web-jcr-rest-war/pom.xml (revision 0) +++ extensions/dna-web-jcr-rest-war/pom.xml (revision 0) @@ -0,0 +1,111 @@ + + 4.0.0 + + dna + org.jboss.dna + 0.5-SNAPSHOT + ../.. + + dna-web-jcr-rest-war + war + JBoss DNA JCR REST Servlet + JBoss DNA servlet that provides RESTful access to JCR items + http://labs.jboss.org/dna + + + org.jboss.dna + dna-web-jcr-rest + ${pom.version} + + + + org.slf4j + slf4j-log4j12 + 1.4.3 + runtime + + + + + junit + junit-dep + 4.4 + integration-test + + + org.jboss.resteasy + resteasy-client + 1.0-beta-8 + integration-test + + + + resources + + + + + + + + + org.codehaus.cargo + cargo-maven2-plugin + + + start-container + pre-integration-test + + start + + + + stop-container + post-integration-test + + stop + + + + + + + high + + + + + ${project.build.directory}/test-classes/jetty-dna.policy + + + false + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + surefire-it + integration-test + + test + + + false + + + + + + + + Property changes on: extensions\dna-web-jcr-rest-war\pom.xml ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest-war/src/main/webapp/META-INF/MANIFEST.MF =================================================================== --- extensions/dna-web-jcr-rest-war/src/main/webapp/META-INF/MANIFEST.MF (revision 0) +++ extensions/dna-web-jcr-rest-war/src/main/webapp/META-INF/MANIFEST.MF (revision 0) @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + Index: extensions/dna-web-jcr-rest-war/src/main/webapp/WEB-INF/web.xml =================================================================== --- extensions/dna-web-jcr-rest-war/src/main/webapp/WEB-INF/web.xml (revision 0) +++ extensions/dna-web-jcr-rest-war/src/main/webapp/WEB-INF/web.xml (revision 0) @@ -0,0 +1,65 @@ + + + + + JBoss DNA JCR RESTful Interface + + + org.jboss.dna.web.jcr.rest.REPOSITORY_PROVIDER + org.jboss.dna.web.jcr.rest.spi.DnaJcrRepositoryProvider + + + + resteasy.providers + org.jboss.dna.web.jcr.rest.JcrResources$NotFoundExceptionMapper, + org.jboss.dna.web.jcr.rest.JcrResources$JSONExceptionMapper, + org.jboss.dna.web.jcr.rest.JcrResources$RepositoryExceptionMapper + + + + + javax.ws.rs.core.Application + org.jboss.dna.web.jcr.rest.JcrApplication + + + + + org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap + + + + + org.jboss.dna.web.jcr.rest.DnaJcrDeployer + + + + Resteasy + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + + + + Resteasy + /* + + + \ No newline at end of file Property changes on: extensions\dna-web-jcr-rest-war\src\main\webapp\WEB-INF\web.xml ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/.classpath =================================================================== --- extensions/dna-web-jcr-rest/.classpath (revision 938) +++ extensions/dna-web-jcr-rest/.classpath (working copy) @@ -1,9 +1,8 @@ - - - - + + + Index: extensions/dna-web-jcr-rest/.project =================================================================== --- extensions/dna-web-jcr-rest/.project (revision 938) +++ extensions/dna-web-jcr-rest/.project (working copy) @@ -1,23 +1,36 @@ - - - dna-web-jcr-rest - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.maven.ide.eclipse.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.maven.ide.eclipse.maven2Nature - - + + + dna-web-jcr-rest + + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.maven.ide.eclipse.maven2Builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.jdt.core.javanature + org.maven.ide.eclipse.maven2Nature + org.eclipse.wst.common.project.facet.core.nature + + Index: extensions/dna-web-jcr-rest/.settings/org.eclipse.jdt.core.prefs =================================================================== --- extensions/dna-web-jcr-rest/.settings/org.eclipse.jdt.core.prefs (revision 0) +++ extensions/dna-web-jcr-rest/.settings/org.eclipse.jdt.core.prefs (revision 0) @@ -0,0 +1,7 @@ +#Wed May 27 16:41:15 EDT 2009 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.5 Index: extensions/dna-web-jcr-rest/.settings/org.eclipse.wst.common.component =================================================================== --- extensions/dna-web-jcr-rest/.settings/org.eclipse.wst.common.component (revision 0) +++ extensions/dna-web-jcr-rest/.settings/org.eclipse.wst.common.component (revision 0) @@ -0,0 +1,9 @@ + + + + + + + + + Index: extensions/dna-web-jcr-rest/.settings/org.eclipse.wst.common.project.facet.core.xml =================================================================== --- extensions/dna-web-jcr-rest/.settings/org.eclipse.wst.common.project.facet.core.xml (revision 0) +++ extensions/dna-web-jcr-rest/.settings/org.eclipse.wst.common.project.facet.core.xml (revision 0) @@ -0,0 +1,5 @@ + + + + + Property changes on: extensions\dna-web-jcr-rest\.settings\org.eclipse.wst.common.project.facet.core.xml ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/.settings/org.maven.ide.eclipse.prefs =================================================================== --- extensions/dna-web-jcr-rest/.settings/org.maven.ide.eclipse.prefs (revision 0) +++ extensions/dna-web-jcr-rest/.settings/org.maven.ide.eclipse.prefs (revision 0) @@ -0,0 +1,9 @@ +#Wed May 27 16:24:52 EDT 2009 +activeProfiles= +eclipse.preferences.version=1 +fullBuildGoals=process-test-resources +includeModules=false +resolveWorkspaceProjects=true +resourceFilterGoals=process-resources resources\:testResources +skipCompilerPlugin=true +version=1 Index: extensions/dna-web-jcr-rest/pom.xml =================================================================== --- extensions/dna-web-jcr-rest/pom.xml (revision 938) +++ extensions/dna-web-jcr-rest/pom.xml (working copy) @@ -7,9 +7,8 @@ 0.5-SNAPSHOT ../.. - org.jboss.dna dna-web-jcr-rest - war + jar JBoss DNA JCR REST Servlet JBoss DNA servlet that provides RESTful access to JCR items http://labs.jboss.org/dna @@ -19,7 +18,26 @@ resteasy-jaxrs 1.1-RC2 + + org.jboss.resteasy + resteasy-jaxb-provider + 1.1-RC2 + + + + org.jboss.dna + dna-jcr + + + + org.slf4j + slf4j-log4j12 + 1.4.3 + runtime + @@ -42,57 +60,10 @@ integration-test + + javax.xml.bind + jaxb-api + 2.1 + - - resources - - - org.codehaus.cargo - cargo-maven2-plugin - - - start-container - pre-integration-test - - start - - - - stop-container - post-integration-test - - stop - - - - - false - - - - - org.apache.maven.plugins - maven-surefire-plugin - - true - - - - surefire-it - integration-test - - test - - - false - - - - - - - Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/DnaJcrDeployer.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/DnaJcrDeployer.java (revision 0) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/DnaJcrDeployer.java (revision 0) @@ -0,0 +1,25 @@ +package org.jboss.dna.web.jcr.rest; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + + + +public class DnaJcrDeployer implements ServletContextListener { + + public static final String DEFAULT_JNDI_NAME = "java:comp/env/org/jboss/dna/Engine"; + + public static final String SYSTEM_PROPERTY_JNDI_NAME = "org.jboss.dna.dnaEngineJndiName"; + + public static final String INIT_PARAMETER_JNDI_NAME = "org.jboss.dna.dnaEngineJndiName"; + + public void contextDestroyed( ServletContextEvent event ) { + RepositoryFactory.shutdown(); + } + + /** + * Mounts a DNA engine + */ + public void contextInitialized( ServletContextEvent event ) { + RepositoryFactory.initialize(event.getServletContext()); + } +} Property changes on: extensions\dna-web-jcr-rest\src\main\java\org\jboss\dna\web\jcr\rest\DnaJcrDeployer.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/JcrResources.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/JcrResources.java (revision 938) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/JcrResources.java (working copy) @@ -23,9 +23,49 @@ */ package org.jboss.dna.web.jcr.rest; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import javax.jcr.Credentials; +import javax.jcr.Item; +import javax.jcr.Node; +import javax.jcr.NodeIterator; +import javax.jcr.PathNotFoundException; +import javax.jcr.Property; +import javax.jcr.PropertyIterator; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; +import javax.jcr.Value; +import javax.jcr.nodetype.PropertyDefinition; +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.jboss.dna.common.text.UrlEncoder; +import org.jboss.dna.web.jcr.rest.model.RepositoryEntry; +import org.jboss.dna.web.jcr.rest.model.WorkspaceEntry; +import org.jboss.resteasy.spi.NotFoundException; +import org.jboss.resteasy.spi.UnauthorizedException; /** * RESTEasy handler to provide the JCR resources at the URIs below. Please note that these URIs assume a context of {@code @@ -42,45 +82,23 @@ * GET * * - * /resources/repositories - * returns a list of accessible repositories - * GET - * - * * /resources/{repositoryName} * returns a list of accessible workspaces within that repository * GET * * - * /resources/{repositoryName}/workspaces - * returns a list of accessible workspaces within that repository - * GET - * - * * /resources/{repositoryName}/{workspaceName} * returns a list of operations within the workspace * GET * * * /resources/{repositoryName}/{workspaceName}/item/{path} - * accesses the node at the path + * accesses the item (node or property) at the path * ALL * - * - * /resources/{repositoryName}/{workspaceName}/item/{path}/@{propertyName} - * accesses the named property at the path - * ALL (except PUT) - * - * - * /resources/{repositoryName}/{workspaceName}/item/{path}/@{propertyName} - * adds the value from the body to the named property at the path - * PUT - * - * - * /resources/{repositoryName}/{workspaceName}/uuid/{uuid} + * /resources/{repositoryName}/{workspaceName}/node/{uuid} * accesses the node with the given UUID - * ALL - * + * ALL * * /resources/{repositoryName}/{workspaceName}/lock/{path} * locks the node at the path @@ -96,25 +114,543 @@ @Path( "/" ) public class JcrResources { + private static final UrlEncoder URL_ENCODER = new UrlEncoder(); + + private static final String PROPERTIES_HOLDER = "properties"; + private static final String CHILD_NODE_HOLDER = "children"; + + private static final String PRIMARY_TYPE_PROPERTY = "jcr:primaryType"; + private static final String MIXIN_TYPES_PROPERTY = "jcr:mixinTypes"; + + /** Name to be used when the repository name is empty string as {@code "//"} is not a valid path. */ + public static final String EMPTY_REPOSITORY_NAME = ""; + /** Name to be used when the workspace name is empty string as {@code "//"} is not a valid path. */ + public static final String EMPTY_WORKSPACE_NAME = ""; + /** + * Returns a reference to the named repository, if it exists. + * + * @param repositoryName the name of the repository to load + * @return the repository + * @throws RepositoryException if any other error occurs + */ + private Repository getRepository( String repositoryName ) throws RepositoryException { + return RepositoryFactory.getRepository(repositoryName); + } + + /** + * Returns an active session for the given workspace name in the named repository. + * + * @param rawRepositoryName the URL-encoded name of the repository in which the session is created + * @param rawWorkspaceName the URL-endecoded name of the workspace to which the session should be connected + * @return an active session with the given workspace in the named repository + * @throws RepositoryException if any other error occurs + */ + private Session getSession( String rawRepositoryName, + String rawWorkspaceName ) throws NotFoundException, RepositoryException { + + Repository repository; + try { + repository = getRepository(repositoryNameFor(rawRepositoryName)); + } catch (RepositoryException re) { + throw new NotFoundException(re.getMessage(), re); + } + + Credentials credentials = new SimpleCredentials("dnauser", "password".toCharArray()); + + return repository.login(credentials, workspaceNameFor(rawWorkspaceName)); + } + + /** * Returns the list of JCR repositories available on this server + * + * @param request the servlet request; may not be null * @return the list of JCR repositories available on this server */ @GET - @Path( "/repositories" ) - public String repositories() { - return "Hello, DNA!"; + @Path( "/" ) + @Produces( "application/json" ) + public Map getRepositories( @Context HttpServletRequest request ) { + assert request != null; + + Map repositories = new HashMap(); + + for (String name : RepositoryFactory.getJcrRepositoryNames()) { + if (name.trim().length() == 0) { + name = EMPTY_REPOSITORY_NAME; + } + name = URL_ENCODER.encode(name); + repositories.put(name, new RepositoryEntry(request.getContextPath(), name)); + } + + return repositories; } /** * Returns the list of workspaces available to this user within the named repository. - * @param repositoryName the name of the repository + * + * @param rawRepositoryName the name of the repository; may not be null + * @param request the servlet request; may not be null * @return the list of workspaces available to this user within the named repository. + * @throws IOException if the given repository name does not map to any repositories and there is an error writing the error + * code to the response. + * @throws RepositoryException if there is any other error accessing the list of available workspaces for the repository */ @GET - @Path( "/{repositoryName}/workspaces" ) - public String workspaces( @PathParam( "repositoryName" ) String repositoryName ) { + @Path( "/{repositoryName}" ) + @Produces( "application/json" ) + public Map getWorkspaces( @Context HttpServletRequest request, + @PathParam( "repositoryName" ) String rawRepositoryName ) + throws RepositoryException, IOException { + + assert request != null; + assert rawRepositoryName != null; + + Map workspaces = new HashMap(); + + Session session = getSession(rawRepositoryName, null); + rawRepositoryName = URL_ENCODER.encode(rawRepositoryName); + + for (String name : session.getWorkspace().getAccessibleWorkspaceNames()) { + if (name.trim().length() == 0) { + name = EMPTY_WORKSPACE_NAME; + } + name = URL_ENCODER.encode(name); + workspaces.put(name, new WorkspaceEntry(request.getContextPath(), rawRepositoryName, name)); + } + + return workspaces; + } + + /** + * Handles GET requests for an item in a workspace. + * + * @param rawRepositoryName the URL-encoded repository name + * @param rawWorkspaceName the URL-encoded workspace name + * @param path the path to the item + * @param depth the depth of the node graph that should be returned if {@code path} refers to a node. @{code 0} means return + * the requested node only. A negative value indicates that the full subgraph under the node should be returned. This + * parameter defaults to {@code 0} and is ignored if {@code path} refers to a property. + * @return the JSON-encoded version of the item (and, if the item is a node, its subgraph, depending on the value of {@code + * depth}) + * @throws NotFoundException if the named repository does not exists, the named workspace does not exist, or the user does not + * have access to the named workspace + * @throws JSONException if there is an error encoding the node + * @throws UnauthorizedException if the given login information is invalid + * @throws RepositoryException if any other error occurs + * @see #EMPTY_REPOSITORY_NAME + * @see #EMPTY_WORKSPACE_NAME + * @see Session#getItem(String) + */ + @GET + @Path( "/{repositoryName}/{workspaceName}/items{path:.*}" ) + @Produces( "application/json" ) + public String getItem( @PathParam( "repositoryName" ) String rawRepositoryName, + @PathParam( "workspaceName" ) String rawWorkspaceName, + @PathParam( "path" ) String path, + @QueryParam( "dna:depth" ) @DefaultValue( "0" ) int depth ) + throws JSONException, UnauthorizedException, RepositoryException { + assert path != null; + assert rawRepositoryName != null; + assert rawWorkspaceName != null; + + Session session = getSession(rawRepositoryName, rawWorkspaceName); + Item item; + + if ("/".equals(path) || "".equals(path)) { + item = session.getRootNode(); + } else { + try { + item = session.getItem(path); + } catch (PathNotFoundException pnfe) { + throw new NotFoundException(pnfe.getMessage(), pnfe); + } + } + + if (item instanceof Node) { + return jsonFor((Node)item, depth).toString(); + } + return jsonFor((Property)item); + } + + /** + * Returns the JSON-encoded version of the given property. If the property is single-valued, the returned string is {@code + * property.getValue().getString()} encoded as a JSON string. If the property is multi-valued with {@code N} values, this + * method returns a JSON array containing {@code property.getValues()[N].getString()} for all values of {@code N}. + * + * @param property the property to be encoded + * @return the JSON-encoded version of the property + * @throws RepositoryException if an error occurs accessing the property, its values, or its definition. + * @see Property#getDefinition() + * @see PropertyDefinition#isMultiple() + */ + private String jsonFor( Property property ) throws RepositoryException { + if (property.getDefinition().isMultiple()) { + Value[] values = property.getValues(); + List list = new ArrayList(values.length); + for (int i = 0; i < values.length; i++) { + list.add(values[i].getString()); + } + return new JSONArray(list).toString(); + } + return JSONObject.quote(property.getValue().getString()); + } + + /** + * Recursively returns the JSON-encoding of a node and its children to depth {@code toDepth}. + * + * @param node the node to be encoded + * @param toDepth the depth to which the recursion should extend; {@code 0} means no further recursion should occur. + * @return the JSON-encoding of a node and its children to depth {@code toDepth}. + * @throws JSONException if there is an error encoding the node + * @throws RepositoryException if any other error occurs + */ + private JSONObject jsonFor( Node node, + int toDepth ) throws JSONException, RepositoryException { + JSONObject jsonNode = new JSONObject(); + + JSONObject properties = new JSONObject(); + + for (PropertyIterator iter = node.getProperties(); iter.hasNext();) { + Property prop = iter.nextProperty(); + String propName = prop.getName(); + + if (prop.getDefinition().isMultiple()) { + Value[] values = prop.getValues(); + JSONArray array = new JSONArray(); + for (int i = 0; i < values.length; i++) { + array.put(values[i].getString()); + } + properties.put(propName, array); + + } else { + properties.put(propName, prop.getValue().getString()); + } + + } + if (properties.length() > 0) { + jsonNode.put(PROPERTIES_HOLDER, properties); + } + + if (toDepth == 0) { + List children = new ArrayList(); + + for (NodeIterator iter = node.getNodes(); iter.hasNext();) { + Node child = iter.nextNode(); + + children.add(child.getName()); + } + + if (children.size() > 0) { + jsonNode.put(CHILD_NODE_HOLDER, new JSONArray(children)); + } + } else { + JSONObject children = new JSONObject(); + + for (NodeIterator iter = node.getNodes(); iter.hasNext();) { + Node child = iter.nextNode(); + + children.put(child.getName(), jsonFor(child, toDepth - 1)); + } + + if (children.length() > 0) { + jsonNode.put(CHILD_NODE_HOLDER, children); + } + } + + return jsonNode; + } + + /** + * Adds the content of the request as a node (or subtree of nodes) at the location specified by {@code path}. + *

+ * The primary type and mixin type(s) may optionally be specified through the {@code jcr:primaryType} and {@code + * jcr:mixinTypes} properties. + *

+ * + * @param rawRepositoryName the URL-encoded repository name + * @param rawWorkspaceName the URL-encoded workspace name + * @param path the path to the item + * @param requestContent the JSON-encoded representation of the node or nodes to be added + * @return the JSON-encoded representation of the node or nodes that were added. This will differ from {@code requestContent} + * in that auto-created and protected properties (e.g., jcr:uuid) will be populated. + * @throws NotFoundException if the parent of the item to be added does not exist + * @throws UnauthorizedException if the user does not have the access required to create the node at this path + * @throws JSONException if there is an error encoding the node + * @throws RepositoryException if any other error occurs + */ + @POST + @Path( "/{repositoryName}/{workspaceName}/items/{path:.*}" ) + @Consumes( "application/json" ) + public Response postItem( @PathParam( "repositoryName" ) String rawRepositoryName, + @PathParam( "workspaceName" ) String rawWorkspaceName, + @PathParam( "path" ) String path, + String requestContent ) + throws NotFoundException, UnauthorizedException, RepositoryException, JSONException { + + assert rawRepositoryName != null; + assert rawWorkspaceName != null; + assert path != null; + JSONObject body = new JSONObject(requestContent); + + int lastSlashInd = path.lastIndexOf('/'); + String parentPath = lastSlashInd == -1 ? "/" : "/" + path.substring(0, lastSlashInd); + String newNodeName = lastSlashInd == -1 ? path : path.substring(lastSlashInd + 1); + + Session session = getSession(rawRepositoryName, rawWorkspaceName); + + Node parentNode = (Node)session.getItem(parentPath); + + Node newNode = addNode(parentNode, newNodeName, body); + + session.save(); + + String json = jsonFor(newNode, -1).toString(); + return Response.status(Status.CREATED).entity(json).build(); + } + + /** + * Adds the node described by {@code jsonNode} with name {@code nodeName} to the existing node {@code parentNode}. + * + * @param parentNode the parent of the node to be added + * @param nodeName the name of the node to be added + * @param jsonNode the JSON-encoded representation of the node or nodes to be added. + * @return the JSON-encoded representation of the node or nodes that were added. This will differ from {@code requestContent} + * in that auto-created and protected properties (e.g., jcr:uuid) will be populated. + * @throws JSONException if there is an error encoding the node + * @throws RepositoryException if any other error occurs + */ + private Node addNode( Node parentNode, + String nodeName, + JSONObject jsonNode ) throws RepositoryException, JSONException { + Node newNode; + + JSONObject properties = jsonNode.has(PROPERTIES_HOLDER) ? jsonNode.getJSONObject(PROPERTIES_HOLDER) : new JSONObject(); + + if (properties.has(PRIMARY_TYPE_PROPERTY)) { + String primaryType = properties.getString(PRIMARY_TYPE_PROPERTY); + newNode = parentNode.addNode(nodeName, primaryType); + } else { + newNode = parentNode.addNode(nodeName); + } + + if (properties.has(MIXIN_TYPES_PROPERTY)) { + Object rawMixinTypes = properties.get(MIXIN_TYPES_PROPERTY); + + if (rawMixinTypes instanceof JSONArray) { + JSONArray mixinTypes = (JSONArray)rawMixinTypes; + for (int i = 0; i < mixinTypes.length(); i++) { + newNode.addMixin(mixinTypes.getString(i)); + } + + } else { + newNode.addMixin(rawMixinTypes.toString()); + + } + } + + for (Iterator iter = properties.keys(); iter.hasNext();) { + String key = (String)iter.next(); + + if (PRIMARY_TYPE_PROPERTY.equals(key)) continue; + if (MIXIN_TYPES_PROPERTY.equals(key)) continue; + setPropertyOnNode(newNode, key, properties.get(key)); + } + + if (jsonNode.has(CHILD_NODE_HOLDER)) { + JSONObject children = jsonNode.getJSONObject(CHILD_NODE_HOLDER); + + for (Iterator iter = children.keys(); iter.hasNext();) { + String childName = (String)iter.next(); + JSONObject child = children.getJSONObject(childName); + + addNode(newNode, childName, child); + } + } + + return newNode; + } + + /** + * Sets the named property on the given node. This method expects {@code value} to be either a JSON string or a JSON array of + * JSON strings. If {@code value} is a JSON array, {@code Node#setProperty(String, String[]) the multi-valued property setter} + * will be used. + * + * @param node the node on which the property is to be set + * @param propName the name of the property to set + * @param value the JSON-encoded values to be set + * @throws RepositoryException if there is an error setting the property + * @throws JSONException if {@code value} cannot be decoded + */ + private void setPropertyOnNode( Node node, + String propName, + Object value ) throws RepositoryException, JSONException { + if (value instanceof JSONArray) { + JSONArray jsonValues = (JSONArray)value; + String[] values = new String[jsonValues.length()]; + + for (int i = 0; i < values.length; i++) { + values[i] = jsonValues.getString(i); + } + node.setProperty(propName, values); + } else { + node.setProperty(propName, (String)value); + } + + } + + /** + * Deletes the item at {@code path}. + * + * @param rawRepositoryName the URL-encoded repository name + * @param rawWorkspaceName the URL-encoded workspace name + * @param path the path to the item + * @throws NotFoundException if no item exists at {@code path} + * @throws UnauthorizedException if the user does not have the access required to delete the item at this path + * @throws RepositoryException if any other error occurs + */ + @DELETE + @Path( "/{repositoryName}/{workspaceName}/items{path:.*}" ) + @Consumes( "application/json" ) + public void deleteItem( @PathParam( "repositoryName" ) String rawRepositoryName, + @PathParam( "workspaceName" ) String rawWorkspaceName, + @PathParam( "path" ) String path ) + throws NotFoundException, UnauthorizedException, RepositoryException { + + assert rawRepositoryName != null; + assert rawWorkspaceName != null; + assert path != null; + + Session session = getSession(rawRepositoryName, rawWorkspaceName); + + Item item; + try { + item = session.getItem(path); + } catch (PathNotFoundException pnfe) { + throw new NotFoundException(pnfe.getMessage(), pnfe); + } + item.remove(); + session.save(); + } + + /** + * Updates the properties at the path. + *

+ * If path points to a property, this method expects the request content to be either a JSON array or a JSON string. The array + * or string will become the values or value of the property. If path points to a node, this method expects the request + * content to be a JSON object. The keys of the objects correspond to property names that will be set and the values for the + * keys correspond to the values that will be set on the properties. + *

+ * + * @param rawRepositoryName the URL-encoded repository name + * @param rawWorkspaceName the URL-encoded workspace name + * @param path the path to the item + * @param requestContent the JSON-encoded representation of the values and, possibly, properties to be set + * @return the JSON-encoded representation of the node on which the property or properties were set. + * @throws NotFoundException if the parent of the item to be added does not exist + * @throws UnauthorizedException if the user does not have the access required to create the node at this path + * @throws JSONException if there is an error encoding the node + * @throws RepositoryException if any other error occurs + */ + @PUT + @Path( "/{repositoryName}/{workspaceName}/items{path:.*}" ) + @Consumes( "application/json" ) + public String putItem( @PathParam( "repositoryName" ) String rawRepositoryName, + @PathParam( "workspaceName" ) String rawWorkspaceName, + @PathParam( "path" ) String path, + String requestContent ) throws UnauthorizedException, JSONException, RepositoryException { + + assert path != null; + assert rawRepositoryName != null; + assert rawWorkspaceName != null; + + Session session = getSession(rawRepositoryName, rawWorkspaceName); + Node node; + Item item; + if ("".equals(path) || "/".equals(path)) { + item = session.getRootNode(); + } else { + try { + item = session.getItem(path); + } catch (PathNotFoundException pnfe) { + throw new NotFoundException(pnfe.getMessage(), pnfe); + } + } + + if (item instanceof Node) { + JSONObject properties = new JSONObject(requestContent); + node = (Node)item; + + for (Iterator iter = properties.keys(); iter.hasNext();) { + String key = (String)iter.next(); + + setPropertyOnNode(node, key, properties.get(key)); + } + + } else { + /* + * The incoming content should be a JSON string or a JSON array. Wrap it into an object so it can be parsed more easily + */ + + JSONObject properties = new JSONObject("{ \"value\": " + requestContent + "}"); + Property property = (Property)item; + node = property.getParent(); + + setPropertyOnNode(node, property.getName(), properties.get("value")); + } + + return jsonFor(node, 0).toString(); + } + + private String workspaceNameFor( String rawWorkspaceName ) { + String workspaceName = URL_ENCODER.decode(rawWorkspaceName); + + if (EMPTY_WORKSPACE_NAME.equals(workspaceName)) { + workspaceName = ""; + } + + return workspaceName; + } + + private String repositoryNameFor( String rawRepositoryName ) { + String repositoryName = URL_ENCODER.decode(rawRepositoryName); + + if (EMPTY_REPOSITORY_NAME.equals(repositoryName)) { + repositoryName = ""; + } + return repositoryName; } + @Provider + public static class NotFoundExceptionMapper implements ExceptionMapper { + + public Response toResponse( NotFoundException exception ) { + return Response.status(Status.NOT_FOUND).entity(exception.getMessage()).build(); + } + + } + + @Provider + public static class JSONExceptionMapper implements ExceptionMapper { + + public Response toResponse( JSONException exception ) { + return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build(); + } + + } + + @Provider + public static class RepositoryExceptionMapper implements ExceptionMapper { + + public Response toResponse( RepositoryException exception ) { + /* + * This error code is murky - the request must have been syntactically valid to get to + * the JCR operations, but there isn't an HTTP status code for "semantically invalid." + */ + return Response.status(Status.BAD_REQUEST).entity(exception.getMessage()).build(); + } + + } + } Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java (revision 0) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java (revision 0) @@ -0,0 +1,32 @@ +package org.jboss.dna.web.jcr.rest.model; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement( name = "repository" ) +public class RepositoryEntry { + + private String name; + private RepositoryResources resources; + + public RepositoryEntry() { + resources = new RepositoryResources(); + } + + public RepositoryEntry( String contextName, + String repositoryName ) { + this.name = repositoryName; + + resources = new RepositoryResources(contextName, repositoryName); + } + + @XmlElement + public String getName() { + return name; + } + + @XmlElement + public RepositoryResources getResources() { + return resources; + } +} Property changes on: extensions\dna-web-jcr-rest\src\main\java\org\jboss\dna\web\jcr\rest\model\RepositoryEntry.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java (revision 0) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java (revision 0) @@ -0,0 +1,21 @@ +package org.jboss.dna.web.jcr.rest.model; + +import javax.xml.bind.annotation.XmlElement; + +public class RepositoryResources { + private String baseUri; + + public RepositoryResources() { + } + + public RepositoryResources( String contextName, + String repositoryName ) { + this.baseUri = contextName + "/" + repositoryName; + } + + @XmlElement( name = "workspaces" ) + public String getWorkspaces() { + return baseUri; + } +} + Property changes on: extensions\dna-web-jcr-rest\src\main\java\org\jboss\dna\web\jcr\rest\model\RepositoryResources.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java (revision 0) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java (revision 0) @@ -0,0 +1,34 @@ +package org.jboss.dna.web.jcr.rest.model; + +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement( name = "workspace" ) +public class WorkspaceEntry { + + private String name; + private WorkspaceResources resources; + + public WorkspaceEntry() { + + } + + public WorkspaceEntry( String contextName, + String repositoryName, + String workspaceName ) { + this.name = workspaceName; + + resources = new WorkspaceResources(contextName, repositoryName, workspaceName); + } + + @XmlElement + public String getName() { + return name; + } + + @XmlElement + public WorkspaceResources getResources() { + return resources; + } +} + Property changes on: extensions\dna-web-jcr-rest\src\main\java\org\jboss\dna\web\jcr\rest\model\WorkspaceEntry.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java (revision 0) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java (revision 0) @@ -0,0 +1,22 @@ +package org.jboss.dna.web.jcr.rest.model; + +import javax.xml.bind.annotation.XmlElement; + +public class WorkspaceResources { + private String baseUri; + + public WorkspaceResources() { + } + + public WorkspaceResources( String contextName, + String repositoryName, + String workspaceName ) { + this.baseUri = contextName + "/" + repositoryName + "/" + workspaceName; + } + + @XmlElement( name = "items" ) + public String getWorkspaces() { + return baseUri + "/items"; + } +} + Property changes on: extensions\dna-web-jcr-rest\src\main\java\org\jboss\dna\web\jcr\rest\model\WorkspaceResources.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/RepositoryFactory.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/RepositoryFactory.java (revision 0) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/RepositoryFactory.java (revision 0) @@ -0,0 +1,41 @@ +package org.jboss.dna.web.jcr.rest; + +import java.util.Collection; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.servlet.ServletContext; +import org.jboss.dna.web.jcr.rest.spi.RepositoryProvider; + +public class RepositoryFactory { + + public static final String PROVIDER_KEY = "org.jboss.dna.web.jcr.rest.REPOSITORY_PROVIDER"; + + private static RepositoryProvider provider; + + private RepositoryFactory() { + + } + + static void initialize( ServletContext context ) { + String className = context.getInitParameter(PROVIDER_KEY); + + try { + Class providerClass = Class.forName(className).asSubclass(RepositoryProvider.class); + provider = providerClass.newInstance(); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } + } + + public static Repository getRepository( String repositoryName ) throws RepositoryException { + return provider.getRepository(repositoryName); + } + + public static Collection getJcrRepositoryNames() { + return provider.getJcrRepositoryNames(); + } + + static void shutdown() { + provider.shutdown(); + } +} Property changes on: extensions\dna-web-jcr-rest\src\main\java\org\jboss\dna\web\jcr\rest\RepositoryFactory.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/DnaJcrRepositoryProvider.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/DnaJcrRepositoryProvider.java (revision 0) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/DnaJcrRepositoryProvider.java (revision 0) @@ -0,0 +1,46 @@ +package org.jboss.dna.web.jcr.rest.spi; + +import java.util.HashSet; +import java.util.Set; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import org.jboss.dna.graph.connector.inmemory.InMemoryRepositorySource; +import org.jboss.dna.jcr.JcrConfiguration; +import org.jboss.dna.jcr.JcrEngine; + +public class DnaJcrRepositoryProvider implements RepositoryProvider { + + private JcrEngine jcrEngine; + + public DnaJcrRepositoryProvider() { + jcrEngine = new JcrConfiguration().withConfigurationRepository() + .usingClass(InMemoryRepositorySource.class.getName()) + .loadedFromClasspath() + .describedAs("Configuration Repository") + .with("name").setTo("configuration") + .with("retryLimit") + .setTo(5) + .and() + .addRepository("Source2") + .usingClass(InMemoryRepositorySource.class.getName()) + .loadedFromClasspath() + .describedAs("description") + .with("name").setTo("JCR Repository") + .and() + .build(); + jcrEngine.start(); + + } + + public Set getJcrRepositoryNames() { + return new HashSet(jcrEngine.getJcrRepositoryNames()); + } + + public Repository getRepository( String repositoryName ) throws RepositoryException { + return jcrEngine.getRepository(repositoryName); + } + + public void shutdown() { + jcrEngine.shutdown(); + } +} Property changes on: extensions\dna-web-jcr-rest\src\main\java\org\jboss\dna\web\jcr\rest\spi\DnaJcrRepositoryProvider.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/RepositoryProvider.java =================================================================== --- extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/RepositoryProvider.java (revision 0) +++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/spi/RepositoryProvider.java (revision 0) @@ -0,0 +1,35 @@ +package org.jboss.dna.web.jcr.rest.spi; + +import java.util.Set; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; + +/** + * Interface for any class that provides access to one or more local JCR repositories. Repository providers must provide a public, + * no-argument constructor. + */ +public interface RepositoryProvider { + + /** + * Returns a reference to the named repository + * + * @param repositoryName the name of the repository to retrieve; may be null + * @return the repository with the given name; may not be null + * @throws RepositoryException if no repository with the given name exists or there is an error obtaining a reference to the + * named repository + */ + Repository getRepository( String repositoryName ) throws RepositoryException; + + /** + * Returns the available repository names + * + * @return the available repository names; may not be null + */ + Set getJcrRepositoryNames(); + + /** + * Signals the repository provider that it should complete any pending transactions, shutdown, and release + * any external resource held. + */ + void shutdown(); +} Property changes on: extensions\dna-web-jcr-rest\src\main\java\org\jboss\dna\web\jcr\rest\spi\RepositoryProvider.java ___________________________________________________________________ Added: svn:keywords + Id Revision Added: svn:eol-style + LF Index: extensions/dna-web-jcr-rest/src/main/webapp/WEB-INF/web.xml =================================================================== --- extensions/dna-web-jcr-rest/src/main/webapp/WEB-INF/web.xml (revision 938) +++ extensions/dna-web-jcr-rest/src/main/webapp/WEB-INF/web.xml (working copy) @@ -1,54 +1,65 @@ - + + JBoss DNA JCR RESTful Interface - JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA - is licensed to you under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. + + org.jboss.dna.web.jcr.rest.REPOSITORY_PROVIDER + org.jboss.dna.web.jcr.rest.spi.DnaJcrRepositoryProvider + - JBoss DNA is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + + resteasy.providers + org.jboss.dna.web.jcr.rest.JcrResources$NotFoundExceptionMapper, + org.jboss.dna.web.jcr.rest.JcrResources$JSONExceptionMapper, + org.jboss.dna.web.jcr.rest.JcrResources$RepositoryExceptionMapper + + - You should have received a copy of the GNU Lesser General Public - License along with this software; if not, write to the Free - Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - 02110-1301 USA, or see the FSF site: http://www.fsf.org. + + javax.ws.rs.core.Application + org.jboss.dna.web.jcr.rest.JcrApplication + - --> - - JBoss DNA JCR RESTful Interface + + + org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap + + - - javax.ws.rs.core.Application - org.jboss.dna.web.jcr.rest.JcrApplication - + + org.jboss.dna.web.jcr.rest.DnaJcrDeployer + - - - org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap - - - - - Resteasy - - org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher + + Resteasy + + org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher - + - - Resteasy - /* - + + Resteasy + /* + \ No newline at end of file Index: extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/JcrResourcesTest.java =================================================================== --- extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/JcrResourcesTest.java (revision 938) +++ extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/JcrResourcesTest.java (working copy) @@ -1,75 +0,0 @@ -/* - * JBoss DNA (http://www.jboss.org/dna) - * See the COPYRIGHT.txt file distributed with this work for information - * regarding copyright ownership. Some portions may be licensed - * to Red Hat, Inc. under one or more contributor license agreements. - * See the AUTHORS.txt file in the distribution for a full listing of - * individual contributors. - * - * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA - * is licensed to you under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * JBoss DNA is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.jboss.dna.web.jcr.rest; - -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import org.jboss.resteasy.client.ClientRequest; -import org.jboss.resteasy.client.ClientResponse; -import org.junit.Ignore; -import org.junit.Test; - -public class JcrResourcesTest { - - private static final String SERVER_URL = "http://localhost:8080/resources"; - - private ClientRequest request; - private ClientResponse response; - - private ClientRequest requestFor(String path) { - return new ClientRequest(SERVER_URL + path); - } - - @Ignore - @Test - public void shouldServeContentAtRoot() throws Exception { - request = requestFor("/"); - - response = request.get(); - - assertThat(response.getStatus(), is(200)); - - } - - @Test - public void shouldServeListOfRepositories() throws Exception { - request = requestFor("/repositories"); - - response = request.get(); - - assertThat(response.getStatus(), is(200)); - - } - - @Test - public void shouldServeListOfWorkspaces() throws Exception { - String validRepositoryName = "foo"; // Stub this for now - request = requestFor("/" + validRepositoryName + "/workspaces"); - - response = request.get(); - - assertThat(response.getStatus(), is(200)); - } - -}