Index: dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java
===================================================================
--- dna-graph/src/main/java/org/jboss/dna/graph/ExecutionContext.java (revision 923)
+++ 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 923)
+++ 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: dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java
===================================================================
--- dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java (revision 923)
+++ dna-jcr/src/main/java/org/jboss/dna/jcr/JcrRepository.java (working copy)
@@ -415,4 +415,10 @@
JcrWorkspace workspace = new JcrWorkspace(this, workspaceName, execContext, sessionAttributes);
return workspace.getSession();
}
+
+ public Set getAvailableWorkspaces() {
+ Graph graph = Graph.create(sourceName, connectionFactory, executionContext);
+ return graph.getWorkspaces();
+
+ }
}
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 923)
+++ extensions/dna-web-jcr-rest/src/main/java/org/jboss/dna/web/jcr/rest/JcrResources.java (working copy)
@@ -23,9 +23,53 @@
*/
package org.jboss.dna.web.jcr.rest;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+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.LoginException;
+import javax.jcr.NoSuchWorkspaceException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+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.servlet.http.HttpServletResponse;
+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.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.jcr.JcrRepository;
+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 +86,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 +118,572 @@
@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 uri the full URI for the request used to load the repository; only used for error message
+ * @param repositoryName the name of the repository to load
+ * @return the repository
+ * @throws NotFoundException if there is no repository with the given name
+ * @throws RepositoryException if any other error occurs
+ */
+ private Repository getRepository( String uri,
+ String repositoryName ) throws NotFoundException, RepositoryException {
+ try {
+ return RepositoryFactory.getRepository(repositoryName);
+ } catch (RepositoryException re) {
+ throw new NotFoundException(uri);
+ }
+ }
+
+ /**
+ * Returns an active session for the given workspace name in the named repository.
+ *
+ * @param uri the full URI for the request used to load the repository; only used for error message
+ * @param repositoryName the name of the repository in which the session is created
+ * @param workspaceName the name of the workspace to which the session should be connected
+ * @return an active session with the given workspace in the named repository
+ * @throws NotFoundException if no repository with the given name exists, no workspace with the given workspace name exists,
+ * or the workspace exists but the user does not have access to it.
+ * @throws RepositoryException if any other error occurs
+ */
+ private Session getSession( String uri,
+ String repositoryName,
+ String workspaceName ) throws NotFoundException, RepositoryException {
+ Repository repository = getRepository(uri, repositoryName);
+
+ Credentials credentials = new SimpleCredentials("dnauser", "password".toCharArray());
+
+ try {
+ Session session = repository.login(credentials, workspaceName);
+
+ return session;
+ } catch (NoSuchWorkspaceException ne) {
+ throw new NotFoundException(uri);
+ } catch (LoginException le) {
+ throw new UnauthorizedException(uri);
+ }
+ }
+
+ /**
+ * Returns the URI for the request relative to the servlet context.
+ *
+ * @param request the request
+ * @return the component of the request URI beginning after the servlet context path. E.g., the request URI {@code
+ * "/resources/repository/workspace"} would become {@code "/repository/workspace"}.
+ */
+ private String relativeUriFor( HttpServletRequest request ) {
+ return request.getRequestURI().substring(request.getContextPath().length());
+ }
+
+ 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;
+ }
+
+ /**
* 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 ) {
- return 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;
+
+ // Need to handle URL decoding
+ String repositoryName = repositoryNameFor(rawRepositoryName);
+ JcrRepository repository = (JcrRepository)getRepository(relativeUriFor(request), repositoryName);
+
+ Map workspaces = new HashMap();
+ repositoryName = URL_ENCODER.encode(repositoryName);
+
+ for (String name : repository.getAvailableWorkspaces()) {
+ if (name.trim().length() == 0) {
+ name = EMPTY_WORKSPACE_NAME;
+ }
+ name = URL_ENCODER.encode(name);
+ workspaces.put(name, new WorkspaceEntry(request.getContextPath(), repositoryName, name));
+ }
+
+ return workspaces;
}
+ /**
+ * Handles GET requests for the root item in a workspace.
+ *
+ * @param request the servlet request; may not be null
+ * @param rawRepositoryName the URL-encoded repository name
+ * @param rawWorkspaceName the URL-encoded workspace name
+ * @param depth the depth of the node graph that should be returned. @{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}.
+ * @return the JSON-encoded version of the root item (and 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 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#getRootNode()
+ */
+ @GET
+ @Path( "/{repositoryName}/{workspaceName}/items" )
+ @Produces( "application/json" )
+ public String getItem( @Context HttpServletRequest request,
+ @PathParam( "repositoryName" ) String rawRepositoryName,
+ @PathParam( "workspaceName" ) String rawWorkspaceName,
+ @QueryParam( "dna:depth" ) @DefaultValue( "0" ) int depth )
+ throws NotFoundException, UnauthorizedException, RepositoryException {
+ return wrapItemWithJson(request, rawRepositoryName, rawWorkspaceName, null, depth);
+ }
+
+ /**
+ * Handles GET requests for an item in a workspace.
+ *
+ * @param request the servlet request; may not be null
+ * @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 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( @Context HttpServletRequest request,
+ @PathParam( "repositoryName" ) String rawRepositoryName,
+ @PathParam( "workspaceName" ) String rawWorkspaceName,
+ @PathParam( "path" ) String path,
+ @QueryParam( "dna:depth" ) @DefaultValue( "0" ) int depth )
+ throws NotFoundException, UnauthorizedException, RepositoryException {
+ return wrapItemWithJson(request, rawRepositoryName, rawWorkspaceName, path, depth);
+ }
+
+ /**
+ * Looks up the node at {@code path} in the named workspace and repository and wraps it in a JSON string.
+ *
+ * @param request the servlet request; may not be null
+ * @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 UnauthorizedException if the given login information is invalid
+ * @throws RepositoryException if any other error occurs
+ * @see #repositoryNameFor(String)
+ * @see #workspaceNameFor(String)
+ * @see Session#getItem(String)
+ */
+ private String wrapItemWithJson( HttpServletRequest request,
+ String rawRepositoryName,
+ String rawWorkspaceName,
+ String path,
+ int depth ) throws NotFoundException, UnauthorizedException, RepositoryException {
+ assert rawRepositoryName != null;
+ assert rawWorkspaceName != null;
+
+ String uri = relativeUriFor(request);
+ String repositoryName = repositoryNameFor(rawRepositoryName);
+ String workspaceName = workspaceNameFor(rawWorkspaceName);
+
+ Session session = getSession(relativeUriFor(request), repositoryName, workspaceName);
+ try {
+ Item item;
+ if (path == null) {
+ item = session.getRootNode();
+ } else {
+ item = session.getItem("/" + path);
+ }
+
+ if (item instanceof Node) {
+ return jsonFor((Node)item, depth).toString();
+ }
+ return jsonStringFor((Property)item);
+ } catch (JSONException je) {
+ throw new NotFoundException(uri);
+ } catch (RepositoryException re) {
+ throw new NotFoundException(uri);
+ }
+
+ }
+
+ /**
+ * 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 jsonStringFor( 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 request the servlet request; may not be null
+ * @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" )
+ // @Produces( "application/json" )
+ public Response postItem( @Context HttpServletRequest request,
+ @Context HttpServletResponse response,
+ @PathParam( "repositoryName" ) String rawRepositoryName,
+ @PathParam( "workspaceName" ) String rawWorkspaceName,
+ @PathParam( "path" ) String path,
+ String requestContent )
+ throws NotFoundException, UnauthorizedException, RepositoryException, JSONException {
+
+ assert request != null;
+ assert rawRepositoryName != null;
+ assert rawWorkspaceName != null;
+ assert path != null;
+ JSONObject body = new JSONObject(requestContent);
+
+ String uri = relativeUriFor(request);
+ String repositoryName = repositoryNameFor(rawRepositoryName);
+ String workspaceName = workspaceNameFor(rawWorkspaceName);
+
+ int lastSlashInd = path.lastIndexOf('/');
+ String parentPath = lastSlashInd == -1 ? "/" : "/" + path.substring(0, lastSlashInd);
+ String newNodeName = lastSlashInd == -1 ? path : path.substring(lastSlashInd + 1);
+
+ Session session = getSession(uri, repositoryName, workspaceName);
+
+ 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;
+ Object value = properties.get(key);
+
+ 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);
+ }
+ newNode.setProperty(key, values);
+ } else {
+ newNode.setProperty(key, (String)value);
+ }
+
+ }
+
+ 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;
+ }
+
+ /**
+ * Deletes the item at {@code path}.
+ *
+ * @param request the servlet request; may not be null
+ * @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" )
+ // @Produces( "application/json" )
+ public void deleteItem( @Context HttpServletRequest request,
+ @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;
+
+ String uri = relativeUriFor(request);
+ String repositoryName = repositoryNameFor(rawRepositoryName);
+ String workspaceName = workspaceNameFor(rawWorkspaceName);
+
+ Session session = getSession(relativeUriFor(request), repositoryName, workspaceName);
+ Item item;
+
+ // If we can't find the item, this should bubble out as a NotFoundException (404)
+ try {
+ item = session.getItem("/" + path);
+ } catch (RepositoryException re) {
+ throw new NotFoundException(uri);
+ }
+
+ // If the item exists, but cannot be deleted, this is a RepositoryException (406)
+ item.remove();
+ session.save();
+ }
+
+ @Provider
+ public static class NotFoundExceptionMapper implements ExceptionMapper {
+
+ public Response toResponse( NotFoundException exception ) {
+ try {
+ URI uri = new URI(URL_ENCODER.encode(exception.getMessage()));
+ return Response.status(Status.NOT_FOUND).contentLocation(uri).build();
+ } catch (URISyntaxException use) {
+ 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/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,49 @@
+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.graph.connector.inmemory.InMemoryRepositorySource;
+import org.jboss.dna.jcr.JcrConfiguration;
+import org.jboss.dna.jcr.JcrEngine;
+
+public class RepositoryFactory {
+
+ private static JcrEngine jcrEngine;
+
+ private RepositoryFactory() {
+
+ }
+
+ static void initialize(ServletContext context) {
+ 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 static Repository getRepository(String repositoryName) throws RepositoryException {
+ return jcrEngine.getRepository(repositoryName);
+ }
+
+ public static Collection getJcrRepositoryNames() {
+ return jcrEngine.getJcrRepositoryNames();
+ }
+
+ static void shutdown() {
+ jcrEngine.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/webapp/WEB-INF/web.xml
===================================================================
--- extensions/dna-web-jcr-rest/src/main/webapp/WEB-INF/web.xml (revision 923)
+++ extensions/dna-web-jcr-rest/src/main/webapp/WEB-INF/web.xml (working copy)
@@ -1,54 +1,60 @@
-
+
+ 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.
+
+ 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
+
+
- 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.
+
+ javax.ws.rs.core.Application
+ org.jboss.dna.web.jcr.rest.JcrApplication
+
- 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.
+
+
+ org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
+
+
- -->
-
- JBoss DNA JCR RESTful Interface
+
+ org.jboss.dna.web.jcr.rest.DnaJcrDeployer
+
-
- javax.ws.rs.core.Application
- org.jboss.dna.web.jcr.rest.JcrApplication
-
-
-
-
- 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 923)
+++ extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/JcrResourcesTest.java (working copy)
@@ -24,52 +24,634 @@
package org.jboss.dna.web.jcr.rest;
import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.hamcrest.core.IsNull.notNullValue;
import static org.junit.Assert.assertThat;
-import org.jboss.resteasy.client.ClientRequest;
-import org.jboss.resteasy.client.ClientResponse;
-import org.junit.Ignore;
+import static org.junit.Assert.assertTrue;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.HashSet;
+import java.util.Set;
+import javax.ws.rs.core.MediaType;
+import org.codehaus.jettison.json.JSONArray;
+import org.codehaus.jettison.json.JSONObject;
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);
+ private static final String SERVER_CONTEXT = "/resources";
+ private static final String SERVER_URL = "http://admin:admin@localhost:8080" + SERVER_CONTEXT;
+ private static final String SERVER_URL_NO_CREDS = "http://localhost:8080" + SERVER_CONTEXT;
+
+ private String getResponseFor( HttpURLConnection connection ) throws IOException {
+ StringBuffer buff = new StringBuffer();
+
+ InputStream stream = connection.getInputStream();
+ int bytesRead;
+ byte[] bytes = new byte[1024];
+ while (-1 != (bytesRead = stream.read(bytes, 0, 1024))) {
+ buff.append(new String(bytes, 0, bytesRead));
+ }
+
+ return buff.toString();
}
-
- @Ignore
+
@Test
public void shouldServeContentAtRoot() throws Exception {
- request = requestFor("/");
+ URL postUrl = new URL(SERVER_URL + "/");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+ String body = getResponseFor(connection);
+
+ JSONObject objFromResponse = new JSONObject(body);
+ JSONObject expected = new JSONObject(
+ "{\"JCR%20Repository\":{\"repository\":{\"name\":\"JCR%20Repository\",\"resources\":{\"workspaces\":\"/resources/JCR%20Repository\"}}}}");
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ assertThat(objFromResponse.toString(), is(expected.toString()));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldServeListOfWorkspacesForValidRepository() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+ String body = getResponseFor(connection);
+
+ JSONObject objFromResponse = new JSONObject(body);
+ JSONObject expected = new JSONObject(
+ "{\"%3cdefault%3e\":{\"workspace\":{\"name\":\"%3cdefault%3e\",\"resources\":{\"items\":\"/resources/JCR%20Repository/%3cdefault%3e/items\"}}}}");
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ assertThat(objFromResponse.toString(), is(expected.toString()));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldReturnErrorForInvalidWorkspace() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/XXX");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NOT_FOUND));
+ assertThat(connection.getHeaderField("content-location"), is(SERVER_URL_NO_CREDS + "/XXX"));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldRetrieveRootNodeForValidRepository() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ JSONObject body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(2));
+
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(2));
+ assertThat(properties.getString("jcr:primaryType"), is("dna:root"));
+ assertThat(properties.get("jcr:uuid"), is(notNullValue()));
+
+ JSONArray children = body.getJSONArray("children");
+ assertThat(children.length(), is(1));
+ assertThat(children.getString(0), is("jcr:system"));
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldRetrieveRootNodeAndChildrenWhenDepthSet() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items?dna:depth=1");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+ JSONObject body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(2));
+
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(2));
+ assertThat(properties.getString("jcr:primaryType"), is("dna:root"));
+ assertThat(properties.get("jcr:uuid"), is(notNullValue()));
+
+ JSONObject children = body.getJSONObject("children");
+ assertThat(children.length(), is(1));
+
+ JSONObject system = children.getJSONObject("jcr:system");
+ assertThat(system.length(), is(2));
+
+ properties = system.getJSONObject("properties");
+ assertThat(properties.length(), is(1));
+ assertThat(properties.getString("jcr:primaryType"), is("dna:system"));
+
+ JSONArray namespaces = system.getJSONArray("children");
+ assertThat(namespaces.length(), is(1));
+ assertThat(namespaces.getString(0), is("dna:namespaces"));
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldRetrieveNodeAndChildrenWhenDepthSet() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/jcr:system?dna:depth=1");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+ JSONObject body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(2));
+
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(1));
+ assertThat(properties.getString("jcr:primaryType"), is("dna:system"));
+
+ JSONObject children = body.getJSONObject("children");
+ assertThat(children.length(), is(1));
+
+ JSONObject namespaces = children.getJSONObject("dna:namespaces");
+ assertThat(namespaces.length(), is(2));
+
+ properties = namespaces.getJSONObject("properties");
+ assertThat(properties.length(), is(1));
+ assertThat(properties.getString("jcr:primaryType"), is("dna:namespaces"));
+
+ JSONArray namespace = namespaces.getJSONArray("children");
+ assertThat(namespace.length(), is(10));
+ Set prefixes = new HashSet(namespace.length());
+
+ for (int i = 0; i < namespace.length(); i++) {
+ prefixes.add(namespace.getString(i));
+ }
+
+ String[] expectedNamespaces = new String[] {"dna", "jcr", "nt", "mix", "sv", "xml", "dnaint", "xmlns", "xsi", "xsd"};
+ for (int i = 0; i < expectedNamespaces.length; i++) {
+ assertTrue(prefixes.contains(expectedNamespaces[i]));
+ }
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldNotRetrieveNonExistentNode() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/foo");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NOT_FOUND));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldNotRetrieveNonExistentProperty() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/jcr:system/foobar");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NOT_FOUND));
+ assertThat(connection.getHeaderField("content-location"), is(SERVER_URL_NO_CREDS
+ + "/JCR%20Repository/%3cdefault%3e/items/jcr:system/foobar"));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldRetrieveProperty() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/jcr:system/jcr:primaryType");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String body = getResponseFor(connection);
+ assertThat(body, is("\"dna:system\""));
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldPostNodeToValidPathWithPrimaryType() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/nodeA");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String payload = "{ \"properties\": {\"jcr:primaryType\": \"nt:unstructured\", \"testProperty\": \"testValue\", \"multiValuedProperty\": [\"value1\", \"value2\"]}}";
+ connection.getOutputStream().write(payload.getBytes());
- response = request.get();
+ JSONObject body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(1));
+
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(3));
+ assertThat(properties.getString("jcr:primaryType"), is("nt:unstructured"));
+ assertThat(properties.getString("testProperty"), is("testValue"));
+ assertThat(properties.get("multiValuedProperty"), instanceOf(JSONArray.class));
+
+ JSONArray values = properties.getJSONArray("multiValuedProperty");
+ assertThat(values, is(notNullValue()));
+ assertThat(values.length(), is(2));
+ assertThat(values.getString(0), is("value1"));
+ assertThat(values.getString(1), is("value2"));
- assertThat(response.getStatus(), is(200));
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_CREATED));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldPostNodeToValidPathWithoutPrimaryType() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/noPrimaryType");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String payload = "{}";
+ connection.getOutputStream().write(payload.getBytes());
+ JSONObject body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(1));
+
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(1));
+ assertThat(properties.getString("jcr:primaryType"), is("nt:base"));
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_CREATED));
+ connection.disconnect();
}
@Test
- public void shouldServeListOfRepositories() throws Exception {
- request = requestFor("/repositories");
+ public void shouldPostNodeToValidPathWithMixinTypes() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/withMixinType");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String payload = "{ \"properties\": {\"jcr:mixinTypes\": \"mix:referenceable\"}}";
+ connection.getOutputStream().write(payload.getBytes());
- response = request.get();
+ JSONObject body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(1));
- assertThat(response.getStatus(), is(200));
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(3));
+ assertThat(properties.getString("jcr:primaryType"), is("nt:base"));
+ assertThat(properties.getString("jcr:uuid"), is(notNullValue()));
+
+ JSONArray values = properties.getJSONArray("jcr:mixinTypes");
+ assertThat(values, is(notNullValue()));
+ assertThat(values.length(), is(1));
+ assertThat(values.getString(0), is("mix:referenceable"));
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_CREATED));
+ connection.disconnect();
+
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/withMixinType");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ // Make sure that we can retrieve the node with a GET
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+ body = new JSONObject(getResponseFor(connection));
+
+ assertThat(body.length(), is(1));
+
+ properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(3));
+ assertThat(properties.getString("jcr:primaryType"), is("nt:base"));
+ assertThat(properties.getString("jcr:uuid"), is(notNullValue()));
+
+ values = properties.getJSONArray("jcr:mixinTypes");
+ assertThat(values, is(notNullValue()));
+ assertThat(values.length(), is(1));
+ assertThat(values.getString(0), is("mix:referenceable"));
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+
}
@Test
- public void shouldServeListOfWorkspaces() throws Exception {
- String validRepositoryName = "foo"; // Stub this for now
- request = requestFor("/" + validRepositoryName + "/workspaces");
+ public void shouldNotPostNodeAtInvalidParentPath() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/foo/bar");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NOT_FOUND));
+ connection.disconnect();
+
+ }
+
+ @Test
+ public void shouldNotPostNodeWithInvalidPrimaryType() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/invalidPrimaryType");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String payload = "{ \"properties\": {\"jcr:primaryType\": \"invalidType\", \"testProperty\": \"testValue\", \"multiValuedProperty\": [\"value1\", \"value2\"]}}";
+ connection.getOutputStream().write(payload.getBytes());
- response = request.get();
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_BAD_REQUEST));
+ connection.disconnect();
- assertThat(response.getStatus(), is(200));
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/invalidPrimaryType");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NOT_FOUND));
+ connection.disconnect();
+
}
+ @Test
+ public void shouldPostNodeHierarchy() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/nestedPost");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String payload = "{ \"properties\": {\"jcr:primaryType\": \"nt:unstructured\", \"testProperty\": \"testValue\", \"multiValuedProperty\": [\"value1\", \"value2\"]},"
+ + " \"children\": { \"childNode\" : { \"properties\": {\"nestedProperty\": \"nestedValue\"}}}}";
+ connection.getOutputStream().write(payload.getBytes());
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_CREATED));
+ connection.disconnect();
+
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/nestedPost?dna:depth=1");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ // Make sure that we can retrieve the node with a GET
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+ JSONObject body = new JSONObject(getResponseFor(connection));
+
+ assertThat(body.length(), is(2));
+
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(3));
+ assertThat(properties.getString("jcr:primaryType"), is("nt:unstructured"));
+ assertThat(properties.getString("testProperty"), is("testValue"));
+ assertThat(properties.get("multiValuedProperty"), instanceOf(JSONArray.class));
+
+ JSONArray values = properties.getJSONArray("multiValuedProperty");
+ assertThat(values, is(notNullValue()));
+ assertThat(values.length(), is(2));
+ assertThat(values.getString(0), is("value1"));
+ assertThat(values.getString(1), is("value2"));
+
+ JSONObject children = body.getJSONObject("children");
+ assertThat(children, is(notNullValue()));
+ assertThat(children.length(), is(1));
+
+ JSONObject child = children.getJSONObject("childNode");
+ assertThat(child, is(notNullValue()));
+ assertThat(child.length(), is(1));
+
+ properties = child.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(2));
+ // Parent primary type is nt:unstructured, so this should default to nt:unstructured primary type
+ assertThat(properties.getString("jcr:primaryType"), is("nt:unstructured"));
+ assertThat(properties.getString("nestedProperty"), is("nestedValue"));
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+
+ }
+
+ @Test
+ public void shouldFailWholeTransactionIfOneNodeIsBad() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/invalidNestedPost");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String payload = "{ \"properties\": {\"jcr:primaryType\": \"nt:unstructured\", \"testProperty\": \"testValue\", \"multiValuedProperty\": [\"value1\", \"value2\"]},"
+ + " \"children\": { \"childNode\" : { \"properties\": {\"jcr:primaryType\": \"invalidType\"}}}}";
+ connection.getOutputStream().write(payload.getBytes());
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_BAD_REQUEST));
+ connection.disconnect();
+
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/invalidNestedPost?dna:depth=1");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ // Make sure that we can retrieve the node with a GET
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NOT_FOUND));
+ connection.disconnect();
+
+ }
+
+ @Test
+ public void shouldNotDeleteNonExistentItem() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/invalidItemForDelete");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("DELETE");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NOT_FOUND));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldDeleteExtantNode() throws Exception {
+
+ // Create the node
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/nodeForDeletion");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String payload = "{ \"properties\": {\"jcr:primaryType\": \"nt:unstructured\", \"testProperty\": \"testValue\", \"multiValuedProperty\": [\"value1\", \"value2\"]}}";
+ connection.getOutputStream().write(payload.getBytes());
+
+ JSONObject body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(1));
+
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(3));
+ assertThat(properties.getString("jcr:primaryType"), is("nt:unstructured"));
+ assertThat(properties.getString("testProperty"), is("testValue"));
+ assertThat(properties.get("multiValuedProperty"), instanceOf(JSONArray.class));
+
+ JSONArray values = properties.getJSONArray("multiValuedProperty");
+ assertThat(values, is(notNullValue()));
+ assertThat(values.length(), is(2));
+ assertThat(values.getString(0), is("value1"));
+ assertThat(values.getString(1), is("value2"));
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_CREATED));
+ connection.disconnect();
+
+ // Confirm that it exists
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/nodeForDeletion");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+
+ // Delete the node
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/nodeForDeletion");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("DELETE");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NO_CONTENT));
+ connection.disconnect();
+
+ // Confirm that it no longer exists
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/nodeForDeletion");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NOT_FOUND));
+ connection.disconnect();
+ }
+
+ @Test
+ public void shouldDeleteExtantProperty() throws Exception {
+ URL postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/propertyForDeletion");
+ HttpURLConnection connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ String payload = "{ \"properties\": {\"jcr:primaryType\": \"nt:unstructured\", \"testProperty\": \"testValue\", \"multiValuedProperty\": [\"value1\", \"value2\"]}}";
+ connection.getOutputStream().write(payload.getBytes());
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_CREATED));
+ connection.disconnect();
+
+ // Confirm that it exists
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/propertyForDeletion");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ JSONObject body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(1));
+
+ JSONObject properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(3));
+ assertThat(properties.getString("jcr:primaryType"), is("nt:unstructured"));
+ assertThat(properties.getString("testProperty"), is("testValue"));
+ assertThat(properties.get("multiValuedProperty"), instanceOf(JSONArray.class));
+
+ JSONArray values = properties.getJSONArray("multiValuedProperty");
+ assertThat(values, is(notNullValue()));
+ assertThat(values.length(), is(2));
+ assertThat(values.getString(0), is("value1"));
+ assertThat(values.getString(1), is("value2"));
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+
+ // Delete the property
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/propertyForDeletion/multiValuedProperty");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("DELETE");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_NO_CONTENT));
+ connection.disconnect();
+
+ // Confirm that it no longer exists
+ postUrl = new URL(SERVER_URL + "/JCR%20Repository/%3cdefault%3e/items/propertyForDeletion");
+ connection = (HttpURLConnection)postUrl.openConnection();
+
+ connection.setDoOutput(true);
+ connection.setRequestMethod("GET");
+ connection.setRequestProperty("Content-Type", MediaType.APPLICATION_JSON);
+
+ body = new JSONObject(getResponseFor(connection));
+ assertThat(body.length(), is(1));
+
+ properties = body.getJSONObject("properties");
+ assertThat(properties, is(notNullValue()));
+ assertThat(properties.length(), is(2));
+ assertThat(properties.getString("jcr:primaryType"), is("nt:unstructured"));
+ assertThat(properties.getString("testProperty"), is("testValue"));
+
+ assertThat(connection.getResponseCode(), is(HttpURLConnection.HTTP_OK));
+ connection.disconnect();
+
+ }
+
}
Index: extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java
===================================================================
--- extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/model/RepositoryEntry.java (revision 0)
+++ extensions/dna-web-jcr-rest/src/test/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\test\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/test/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java
===================================================================
--- extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/model/RepositoryResources.java (revision 0)
+++ extensions/dna-web-jcr-rest/src/test/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\test\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/test/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java
===================================================================
--- extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/model/WorkspaceEntry.java (revision 0)
+++ extensions/dna-web-jcr-rest/src/test/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\test\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/test/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java
===================================================================
--- extensions/dna-web-jcr-rest/src/test/java/org/jboss/dna/web/jcr/rest/model/WorkspaceResources.java (revision 0)
+++ extensions/dna-web-jcr-rest/src/test/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\test\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/test/resources/dna-test-users.props
===================================================================
--- extensions/dna-web-jcr-rest/src/test/resources/dna-test-users.props (revision 0)
+++ extensions/dna-web-jcr-rest/src/test/resources/dna-test-users.props (revision 0)
@@ -0,0 +1 @@
+dnauser=password,readwrite
Index: extensions/dna-web-jcr-rest/src/test/resources/jetty-dna.policy
===================================================================
--- extensions/dna-web-jcr-rest/src/test/resources/jetty-dna.policy (revision 0)
+++ extensions/dna-web-jcr-rest/src/test/resources/jetty-dna.policy (revision 0)
@@ -0,0 +1,5 @@
+dna-jcr {
+ org.mortbay.jetty.plus.jaas.spi.PropertyFileLoginModule optional
+ debug="true"
+ file="target/test-classes/dna-test-users.props";
+};
Index: extensions/dna-web-jcr-rest/src/test/resources/jetty-jaas.xml
===================================================================
--- extensions/dna-web-jcr-rest/src/test/resources/jetty-jaas.xml (revision 0)
+++ extensions/dna-web-jcr-rest/src/test/resources/jetty-jaas.xml (revision 0)
@@ -0,0 +1,9 @@
+
+
+
+ xyzrealm
+ dna-jcr
+
+
+
+
Property changes on: extensions\dna-web-jcr-rest\src\test\resources\jetty-jaas.xml
___________________________________________________________________
Added: svn:keywords
+ Id Revision
Added: svn:eol-style
+ LF
Index: extensions/dna-web-jcr-rest/src/test/resources/log4j.properties
===================================================================
--- extensions/dna-web-jcr-rest/src/test/resources/log4j.properties (revision 0)
+++ extensions/dna-web-jcr-rest/src/test/resources/log4j.properties (revision 0)
@@ -0,0 +1,13 @@
+log4j.rootLogger = DEBUG, stdout
+
+log4j.category.org.apache=INFO
+log4j.category.org.jboss.resteasy=INFO
+log4j.category.org.mortbay=DEBUG
+log4j.category.org.slf4j.impl.JCLLoggerAdapter=INFO
+log4j.category.org.springframework=INFO
+
+log4j.appender.stdout = org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Threshold = DEBUG
+log4j.appender.stdout.Target = System.out
+log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern = [%-5p] [%C{1}] : %m%n