jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ang...@apache.org
Subject svn commit: r741206 - in /jackrabbit/trunk/jackrabbit-jcr-server/src: main/java/org/apache/jackrabbit/server/remoting/davex/ test/java/org/apache/jackrabbit/server/remoting/davex/
Date Thu, 05 Feb 2009 17:50:50 GMT
Author: angela
Date: Thu Feb  5 17:50:49 2009
New Revision: 741206

URL: http://svn.apache.org/viewvc?rev=741206&view=rev
Log:
- JCR-1958: Enhanced JCR remoting (work in progress)

Added:
    jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfigTest.java
  (with props)
Modified:
    jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfig.java
    jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/JcrRemotingServlet.java
    jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/TestAll.java

Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfig.java?rev=741206&r1=741205&r2=741206&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfig.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfig.java
Thu Feb  5 17:50:49 2009
@@ -37,18 +37,17 @@
 
     private static Logger log = LoggerFactory.getLogger(BatchReadConfig.class);
 
+    private static final String NAME_DEFAULT = "default";
     public static final int DEPTH_DEFAULT = 0;
     public static final int DEPTH_INFINITE = -1;
 
-    private int defaultDepth = DEPTH_INFINITE;
+    private int defaultDepth = DEPTH_DEFAULT;
     private final Map depthMap = new HashMap();
 
     /**
      * Create an empty batch-read config.
      */
-    public BatchReadConfig() {
-
-    }
+    BatchReadConfig() {}
 
     /**
      * Load the batch read configuration.
@@ -62,16 +61,29 @@
         add(props);
     }
 
+    /**
+     * Add the configuration entries present in the given properties.
+     *
+     * @param props
+     */
     public void add(Properties props) {
         for (Enumeration en = props.propertyNames(); en.hasMoreElements();) {
             String name = en.nextElement().toString();
-            String depth = props.getProperty(name);
+            String depthStr = props.getProperty(name);
             try {
-                Integer intg = new Integer(depth);
-                depthMap.put(name, intg);
+                int depth = Integer.parseInt(depthStr);
+                if (depth < DEPTH_INFINITE) {
+                    log.warn("invalid depth " + depthStr + " -> ignoring.");
+                    continue;
+                }
+                if (NAME_DEFAULT.equals(name)) {
+                    setDefaultDepth(depth);
+                } else {
+                    setDepth(name, depth);
+                }
             } catch (NumberFormatException e) {
                 // invalid entry in the properties file -> ignore
-                log.warn("Invalid depth value for name " + name + ". " + depth + " cannot
be parsed into an integer.");
+                log.warn("Invalid depth value for name " + name + ". " + depthStr + " cannot
be parsed into an integer.");
             }
         }
     }
@@ -92,14 +104,13 @@
         if (depthMap.containsKey(ntName)) {
             return ((Integer) (depthMap.get(ntName))).intValue();
         } else {
-            return DEPTH_DEFAULT;
+            return defaultDepth;
         }
     }
 
     /**
-     * Return the depth for the given node or the
-     * {@link #DEPTH_DEFAULT default value} if the config does not provide
-     * an specific entry for the given node..
+     * Return the depth for the given node or the default depth if the config
+     * does not provide an specific entry for the given node.
      *
      * @param node The node for with depth information should be retrieved.
      * @return {@link #DEPTH_INFINITE -1} If all child infos should be return or
@@ -107,7 +118,7 @@
      * subtree should be returned.
      */
     public int getDepth(Node node) {
-        int depth = DEPTH_DEFAULT;
+        int depth = defaultDepth;
         try {
             String ntName = node.getPrimaryNodeType().getName();
             if (depthMap.containsKey(ntName)) {

Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/JcrRemotingServlet.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/JcrRemotingServlet.java?rev=741206&r1=741205&r2=741206&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/JcrRemotingServlet.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/server/remoting/davex/JcrRemotingServlet.java
Thu Feb  5 17:50:49 2009
@@ -50,7 +50,133 @@
 import java.io.InputStream;
 import java.util.Iterator;
 
-/** <code>JcrRemotingServlet</code>... */
+/**
+ * <code>JcrRemotingServlet</code> is an extended version of the
+ * {@link org.apache.jackrabbit.webdav.jcr.JCRWebdavServerServlet JCR Remoting Servlet}
+ * that provides improved
+ * <ul>
+ * <li><a href="#bread">Batch read</a></li>
+ * <li><a href="#bwrite">Batch write</a></li>
+ * </ul>
+ * functionality and supports cross workspace copy and cloning.
+ * </p>
+ * 
+ * <h3><a name="bread">Batch Read</a></h3>
+ *
+ * Upon RepositoryService.getItemInfos a JSON object is composed containing
+ * the information for the requested node and its child items up to a
+ * specified or configuration determined depth.
+ * <p/>
+ * Batch read is triggered by adding a '.json' extension to the resource href.
+ * Optionally the client may explicitely specify the desired batch read depth
+ * by appending '.depth.json' extension. If no json extension is present the
+ * GET request is processed by the base servlet.
+ * <p/>
+ * The JSON writer applies the following rules:
+ * 
+ * <pre>
+ * - Each Node has its properties included as JSON key/value pairs.
+ *
+ * - Child nodes are equally treated as long a maximal depths is not reached.
+ * 
+ * - Nodes without any child nodes get a special JSON member named
+ *   ::NodeIteratorSize, whose value is zero.
+ *
+ * - If the maximal depth is reached only name, index and unique id of the
+ *   direct child are included (incomplete node info). In order to obtain
+ *   the complete information another GET with .json extension will be sent
+ *   by the client.
+ * </pre>
+ * 
+ * Same name sibling nodes and properties whose type cannot be unambiguously be
+ * extracted from the JSON on the client side need some special handling:
+ * 
+ * <pre>
+ * - Node with index > 1, get a JSON key consisting of
+ *   Node.getName() + "[" + Node.getIndex() + "]" 
+ *
+ * - Binary Property
+ *   JSON value = length of the JCR value.
+ *   The JCR value must be retrieved separately.
+ *
+ * - Name, Path, Reference and Date Property
+ *   The JSON member representing the Property (name, value) is preceeded by a
+ *   special member consisting of
+ *   JSON key = ":" + Property.getName()
+ *   JSON value = PropertyType.nameFromValue(Property.getType())
+ *
+ * - Multi valued properties with Property.getValues().length == 0 will be
+ *   treated as special property types above (extra property indicating the
+ *   type of the property).
+ *
+ * - Double Property
+ *   JSON value must not have any trailing ".0" removed.
+ * </pre>
+ *
+ * <h3><a name="bwrite">Batch Write</a></h3>
+ *
+ * The complete SPI Batch is sent to the server in a single request, currently a
+ * POST request containing a custom ":diff" parameter.
+ * <br>
+ * <i>NOTE</i> that this is targeted to be replaced by a PATCH request.
+ *
+ * <h4>Diff format</h4>
+ *
+ * The diff parameter currently consists of a JSON object with the following
+ * special requirements:
+ *
+ * <pre>
+ *   diff       ::= "{" members "}"
+ *   members    ::= pair | pairs
+ *   pair       ::= key " : " value
+ *   pairs      ::= pair line-end pair | pair line-end pairs
+ *   line-end   ::= "\r\n" | "\n" | "\r"
+ *   key        ::= diffchar path
+ *   diffchar   ::= "+" | "^" | "-" | ">"
+ *   path       ::= abspath | relpath
+ *   abspath    ::= * absolute path to an item *
+ *   relpath    ::= * relpath from item at request URI to an item *
+ *   value      ::= value+ | value- | value^ | value>
+ *   value+     ::= * a JSON object *
+ *   value-     ::= ""
+ *   value^     ::= * any JSON value except JSON object *
+ *   value>     ::= path | path "#before" | path "#after" | "#first" | "#last"
+ * </pre>
+ *
+ * In other words:
+ * <ul>
+ * <li>diff is a JSON object consisting of key-value pairs</li>
+ * <li>key must start with a diffchar followed by a rel. or abs. item path</li>
+ * <li>diffchar being any of "+", "^", "-" or ">" representing the transient
+ * item modifications as follows
+ * <pre>
+ *   "+" addNode
+ *   "^" setProperty / setValue / removeProperty
+ *   "-" remove Item
+ *   ">" move / reorder Nodes
+ * </pre>
+ * </li>
+ * <li>key must be separated from the value by a ":" surrounded by whitespace.</li>
+ * <li>two pairs must be separated by a line end</li>
+ * <li>the format of the value depends on the diffchar</li>
+ * <li>for moving around node the value must consist of a abs. or rel. path.
+ * in contrast reordering of existing nodes is achieved by appending a trailing
+ * order position hint (#first, #last, #before or #after)</li>
+ * </ul>
+ *
+ * <i>NOTE</i> the following special handling of JCR properties of type
+ * Binary, Name, Path, Date and Reference:
+ * <ul>
+ * <li>the JSON value must be missing</li>
+ * <li>the POST request is expected to contain extra multipart(s) or request
+ * parameter(s) for the property value(s)</li>
+ * <li>the content type of the extra parts/params must reflect the property
+ * type:"jcr-value/" + PropertyType.nameFromValue(Property.getType).toLowerCase()</li>
+ * </ul>
+ * 
+ * @see <a href="http://www.json.org/">www.json.org</a> for the definition of
+ * JSON object and JSON value.
+ */
 public abstract class JcrRemotingServlet extends JCRWebdavServerServlet {
 
     private static Logger log = LoggerFactory.getLogger(JcrRemotingServlet.class);
@@ -86,9 +212,9 @@
         brConfig = new BatchReadConfig();
         String brConfigParam = getServletConfig().getInitParameter(INIT_PARAM_BATCHREAD_CONFIG);
         if (brConfigParam == null) {
+            // TODO: define default values.
             log.debug("batchread-config missing -> initialize defaults.");
             brConfig.setDepth("nt:file", BatchReadConfig.DEPTH_INFINITE);
-            brConfig.setDepth("nt:folder", 1);
             brConfig.setDefaultDepth(5);
         } else {
             try {
@@ -97,15 +223,15 @@
                     brConfig.load(in);
                 }
             } catch (IOException e) {
-                log.debug("Unable to build resource filter provider.");
+                log.debug("Unable to build BatchReadConfig from " + brConfigParam + ".");
             }
         }
 
         // setup home directory
         String paramHome = getServletConfig().getInitParameter(INIT_PARAM_HOME);
         if (paramHome == null) {
-            log.debug("missing init-param " + INIT_PARAM_HOME + ". using default: jr_home");
-            paramHome = "jr_home";
+            log.debug("missing init-param " + INIT_PARAM_HOME + ". using default: 'jackrabbit'");
+            paramHome = "jackrabbit";
         }
         File home;
         try {
@@ -117,12 +243,12 @@
 
         String tmp = getServletConfig().getInitParameter(INIT_PARAM_TMP_DIRECTORY);
         if (tmp == null) {
-            log.warn("No " + INIT_PARAM_TMP_DIRECTORY + " specified. using 'tmp'");
+            log.debug("No " + INIT_PARAM_TMP_DIRECTORY + " specified. using 'tmp'");
             tmp = "tmp";
         }
         File tmpDirectory = new File(home, tmp);
         tmpDirectory.mkdirs();
-        log.info("  temp-directory = " + tmpDirectory.getPath());
+        log.debug("  temp-directory = " + tmpDirectory.getPath());
         getServletContext().setAttribute(ATTR_TMP_DIRECTORY, tmpDirectory);
 
         // force usage of custom locator factory.

Added: jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfigTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfigTest.java?rev=741206&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfigTest.java
(added)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfigTest.java
Thu Feb  5 17:50:49 2009
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.server.remoting.davex;
+
+import junit.framework.TestCase;
+
+import java.util.Properties;
+
+/**
+ * <code>BatchReadConfigTest</code>...
+ */
+public class BatchReadConfigTest extends TestCase {
+
+    public void testDefaultDepth() {
+        BatchReadConfig cnf = new BatchReadConfig();
+
+        assertEquals(BatchReadConfig.DEPTH_DEFAULT, cnf.getDefaultDepth());
+        assertEquals(cnf.getDefaultDepth(), cnf.getDepth("nt:base"));
+
+        cnf.setDefaultDepth(5);
+        assertEquals(5, cnf.getDefaultDepth());
+        assertEquals(cnf.getDefaultDepth(), cnf.getDepth("nt:base"));
+
+        cnf.setDefaultDepth(BatchReadConfig.DEPTH_INFINITE);
+        assertEquals(BatchReadConfig.DEPTH_INFINITE, cnf.getDefaultDepth());
+        assertEquals(cnf.getDefaultDepth(), cnf.getDepth("nt:base"));
+
+        try {
+            cnf.setDefaultDepth(-12);
+            fail("Invalid depth");
+        } catch (IllegalArgumentException e) {
+            //ok
+        }
+    }
+
+    public void testDepth() {
+        BatchReadConfig cnf = new BatchReadConfig();
+
+        cnf.setDepth("nt:file", 15);
+        assertEquals(15, cnf.getDepth("nt:file"));
+        assertEquals(cnf.getDefaultDepth(), cnf.getDepth("nt:base"));
+
+        cnf.setDepth("nt:file", BatchReadConfig.DEPTH_INFINITE);
+        assertEquals(BatchReadConfig.DEPTH_INFINITE, cnf.getDepth("nt:file"));
+        assertEquals(cnf.getDefaultDepth(), cnf.getDepth("nt:base"));
+
+        try {
+            cnf.setDepth("nt:file",-12);
+            fail("Invalid depth");
+        } catch (IllegalArgumentException e) {
+            //ok
+        }
+    }
+
+    public void testAdd() {
+        Properties props = new Properties();
+        props.setProperty("nt:file", "15");
+        props.setProperty("default", "-1");
+
+        BatchReadConfig cnf = new BatchReadConfig();
+        cnf.add(props);
+
+        assertEquals(15, cnf.getDepth("nt:file"));
+        assertEquals(BatchReadConfig.DEPTH_INFINITE, cnf.getDefaultDepth());
+        assertEquals(cnf.getDefaultDepth(), cnf.getDepth("nt:base"));
+
+        cnf.setDefaultDepth(BatchReadConfig.DEPTH_DEFAULT);
+        assertEquals(15, cnf.getDepth("nt:file"));
+        assertEquals(BatchReadConfig.DEPTH_DEFAULT, cnf.getDefaultDepth());
+        assertEquals(cnf.getDefaultDepth(), cnf.getDepth("nt:base"));
+    }
+}
\ No newline at end of file

Propchange: jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfigTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/BatchReadConfigTest.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/TestAll.java?rev=741206&r1=741205&r2=741206&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/TestAll.java
(original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/test/java/org/apache/jackrabbit/server/remoting/davex/TestAll.java
Thu Feb  5 17:50:49 2009
@@ -33,6 +33,7 @@
         TestSuite suite = new TestSuite("org.apache.jackrabbit.server.remoting.davex tests");
 
         suite.addTestSuite(DiffParserTest.class);
+        suite.addTestSuite(BatchReadConfigTest.class);
 
         return suite;
     }



Mime
View raw message