You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by al...@apache.org on 2018/10/27 01:45:20 UTC

svn commit: r1844932 - in /jackrabbit/oak/trunk: oak-run/src/main/groovy/org/apache/jackrabbit/oak/console/commands/ oak-run/src/main/java/org/apache/jackrabbit/oak/exporter/ oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/ oak-store-spi/src/...

Author: alexkli
Date: Sat Oct 27 01:45:20 2018
New Revision: 1844932

URL: http://svn.apache.org/viewvc?rev=1844932&view=rev
Log:
OAK-7832 - oak-run console export should handle exceptions such as missing segments

Added:
    jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/
    jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/NodeStateHelper.java   (with props)
Modified:
    jackrabbit/oak/trunk/oak-run/src/main/groovy/org/apache/jackrabbit/oak/console/commands/PnCommand.groovy
    jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/exporter/NodeStateSerializer.java
    jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/json/JsonSerializer.java

Modified: jackrabbit/oak/trunk/oak-run/src/main/groovy/org/apache/jackrabbit/oak/console/commands/PnCommand.groovy
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/groovy/org/apache/jackrabbit/oak/console/commands/PnCommand.groovy?rev=1844932&r1=1844931&r2=1844932&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/groovy/org/apache/jackrabbit/oak/console/commands/PnCommand.groovy (original)
+++ jackrabbit/oak/trunk/oak-run/src/main/groovy/org/apache/jackrabbit/oak/console/commands/PnCommand.groovy Sat Oct 27 01:45:20 2018
@@ -20,7 +20,7 @@ package org.apache.jackrabbit.oak.consol
 
 import groovy.transform.CompileStatic
 import org.apache.jackrabbit.oak.console.ConsoleSession
-import org.apache.jackrabbit.oak.spi.state.AbstractNodeState
+import org.apache.jackrabbit.oak.nodestate.NodeStateHelper
 import org.codehaus.groovy.tools.shell.CommandSupport
 import org.codehaus.groovy.tools.shell.Groovysh
 
@@ -28,18 +28,19 @@ import org.codehaus.groovy.tools.shell.G
 class PnCommand extends CommandSupport{
     public static final String COMMAND_NAME = 'print-node'
 
-    public PnCommand(Groovysh shell) {
+    PnCommand(Groovysh shell) {
         super(shell, COMMAND_NAME, 'pn')
     }
 
     @Override
     Object execute(List<String> args) {
         assertNoArguments(args)
-        io.out.println(AbstractNodeState.toString(getSession().getWorkingNode()))
+        io.out.println(NodeStateHelper.nodeStateToString(getSession().getWorkingNode()))
         return null
     }
 
     ConsoleSession getSession(){
         return (ConsoleSession)variables.session
     }
+
 }

Modified: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/exporter/NodeStateSerializer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/exporter/NodeStateSerializer.java?rev=1844932&r1=1844931&r2=1844932&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/exporter/NodeStateSerializer.java (original)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/exporter/NodeStateSerializer.java Sat Oct 27 01:45:20 2018
@@ -101,9 +101,9 @@ public class NodeStateSerializer {
     }
 
     private void serialize(JsopWriter writer, BlobSerializer blobSerializer) throws IOException {
-        JsonSerializer serializer = new JsonSerializer(writer, depth, 0, maxChildNodes, getFilter(), blobSerializer);
+        JsonSerializer serializer = new JsonSerializer(writer, depth, 0, maxChildNodes, getFilter(), blobSerializer, true);
         NodeState state = NodeStateUtils.getNode(nodeState, path);
-        serializer.serialize(state);
+        serializer.serialize(state, path);
     }
 
     private BlobSerializer createBlobSerializer(File dir) {

Added: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/NodeStateHelper.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/NodeStateHelper.java?rev=1844932&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/NodeStateHelper.java (added)
+++ jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/NodeStateHelper.java Sat Oct 27 01:45:20 2018
@@ -0,0 +1,79 @@
+/**************************************************************************
+ * 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.oak.nodestate;
+
+import static java.lang.Integer.getInteger;
+
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+public abstract class NodeStateHelper {
+
+    private static final int CHILDREN_CAP = getInteger("oak.children.cap", 100);
+
+    public static String nodeStateToString(NodeState state) {
+        if (!state.exists()) {
+            return "{N/A}";
+        }
+        StringBuilder builder = new StringBuilder("{");
+        String separator = " ";
+        for (PropertyState property : state.getProperties()) {
+            builder.append(separator);
+            separator = ", ";
+            try {
+                builder.append(property);
+            } catch (Throwable t) {
+                builder.append(property.getName());
+                builder.append(" = { ERROR on property: ");
+                builder.append(t.getMessage());
+                builder.append(" }");
+            }
+        }
+        int count = CHILDREN_CAP;
+        for (ChildNodeEntry entry : state.getChildNodeEntries()) {
+            if (count-- == 0) {
+                builder.append("...");
+                break;
+            }
+            builder.append(separator);
+            separator = ", ";
+            try {
+                builder.append(childNodeEntryToString(entry));
+            } catch (Throwable t) {
+                builder.append(entry.getName());
+                builder.append(" = { ERROR on node: ");
+                builder.append(t.getMessage());
+                builder.append(" }");
+            }
+        }
+        builder.append(" }");
+        return builder.toString();
+    }
+
+    public static String childNodeEntryToString(ChildNodeEntry entry) {
+        String name = entry.getName();
+        NodeState state = entry.getNodeState();
+        if (state.getChildNodeCount(1) == 0) {
+            return name + " : " + nodeStateToString(state);
+        } else {
+            return name + " = { ... }";
+        }
+    }
+}

Propchange: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/NodeStateHelper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/oak/trunk/oak-run/src/main/java/org/apache/jackrabbit/oak/nodestate/NodeStateHelper.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev URL

Modified: jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/json/JsonSerializer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/json/JsonSerializer.java?rev=1844932&r1=1844931&r2=1844932&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/json/JsonSerializer.java (original)
+++ jackrabbit/oak/trunk/oak-store-spi/src/main/java/org/apache/jackrabbit/oak/json/JsonSerializer.java Sat Oct 27 01:45:20 2018
@@ -25,9 +25,12 @@ import static org.apache.jackrabbit.oak.
 import static org.apache.jackrabbit.oak.api.Type.NAMES;
 import static org.apache.jackrabbit.oak.api.Type.STRING;
 
+import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.regex.Pattern;
 
+import org.jetbrains.annotations.NotNull;
 import javax.jcr.PropertyType;
 
 import com.google.common.collect.ImmutableList;
@@ -38,19 +41,31 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.json.JsopTokenizer;
 import org.apache.jackrabbit.oak.commons.json.JsopWriter;
+import org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState;
 import org.apache.jackrabbit.oak.plugins.memory.MemoryChildNodeEntry;
+import org.apache.jackrabbit.oak.plugins.memory.StringPropertyState;
+import org.apache.jackrabbit.oak.spi.state.AbstractNodeState;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.spi.state.ReadOnlyBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Utility class for serializing node and property states to JSON.
  */
 public class JsonSerializer {
+    private static final Logger log = LoggerFactory.getLogger(JsonSerializer.class);
+
     public static final String DEFAULT_FILTER_EXPRESSION =
         "{\"properties\":[\"*\", \"-:childNodeCount\"]}";
 
     private static final JsonFilter DEFAULT_FILTER = new JsonFilter(DEFAULT_FILTER_EXPRESSION);
 
+    private static final String ERROR_JSON_KEY = "_error";
+    private static final String ERROR_JSON_VALUE_PREFIX = "ERROR: ";
+
     private final JsopWriter json;
 
     private final int depth;
@@ -63,86 +78,167 @@ public class JsonSerializer {
 
     private final BlobSerializer blobs;
 
+    private final boolean catchExceptions;
+
     private JsonSerializer(
             JsopWriter json, int depth, long offset, int maxChildNodes,
-            JsonFilter filter, BlobSerializer blobs) {
+            JsonFilter filter, BlobSerializer blobs, boolean catchExceptions) {
         this.json = checkNotNull(json);
         this.depth = depth;
         this.offset = offset;
         this.maxChildNodes = maxChildNodes;
         this.filter = checkNotNull(filter);
         this.blobs = checkNotNull(blobs);
+        this.catchExceptions = catchExceptions;
     }
 
     public JsonSerializer(
             int depth, long offset, int maxChildNodes,
             String filter, BlobSerializer blobs) {
         this(new JsopBuilder(), depth, offset, maxChildNodes,
-                new JsonFilter(filter), blobs);
+                new JsonFilter(filter), blobs, false);
     }
 
     public JsonSerializer(JsopWriter json,
             int depth, long offset, int maxChildNodes,
             String filter, BlobSerializer blobs) {
         this(json, depth, offset, maxChildNodes,
-                new JsonFilter(filter), blobs);
+                new JsonFilter(filter), blobs, false);
+    }
+
+    public JsonSerializer(JsopWriter json,
+                          int depth, long offset, int maxChildNodes,
+                          String filter, BlobSerializer blobs, boolean catchExceptions) {
+        this(json, depth, offset, maxChildNodes,
+            new JsonFilter(filter), blobs, catchExceptions);
     }
 
     public JsonSerializer(JsopWriter json, BlobSerializer blobs) {
         this(json, Integer.MAX_VALUE, 0, Integer.MAX_VALUE,
-                DEFAULT_FILTER, blobs);
+                DEFAULT_FILTER, blobs, false);
     }
 
     public JsonSerializer(JsopWriter json, String filter, BlobSerializer blobs) {
         this(json, Integer.MAX_VALUE, 0, Integer.MAX_VALUE,
-                new JsonFilter(filter), blobs);
+                new JsonFilter(filter), blobs, false);
     }
 
     protected JsonSerializer getChildSerializer() {
         return new JsonSerializer(
-                json, depth - 1, 0, maxChildNodes, filter, blobs);
+                json, depth - 1, 0, maxChildNodes, filter, blobs, catchExceptions);
     }
 
     public void serialize(NodeState node) {
-        json.object();
+        serialize(node, "");
+    }
 
-        for (PropertyState property : node.getProperties()) {
-            String name = property.getName();
-            if (filter.includeProperty(name)) {
-                json.key(name);
-                serialize(property);
-            }
-        }
+    public void serialize(NodeState node, String basePath) {
+        json.object();
 
-        int index = 0;
-        int count = 0;
-        for (ChildNodeEntry child : getChildNodeEntries(node)) {
-            String name = child.getName();
-            if (filter.includeNode(name) && index++ >= offset) {
-                if (count++ >= maxChildNodes) {
-                    break;
+        try {
+            for (PropertyState property : node.getProperties()) {
+                String name = property.getName();
+                if (filter.includeProperty(name)) {
+                    json.key(name);
+                    try {
+                        serialize(property);
+                    } catch (Throwable t) {
+                        if (catchExceptions) {
+                            String message = "Cannot read property value " + basePath + "/" + name + " : " + t.getMessage();
+                            log.error(message);
+                            json.value(ERROR_JSON_VALUE_PREFIX + message);
+                        } else {
+                            throw t;
+                        }
+                    }
                 }
+            }
 
-                json.key(name);
-                if (depth > 0) {
-                    getChildSerializer().serialize(child.getNodeState());
-                } else {
-                    json.object();
-                    json.endObject();
+            int index = 0;
+            int count = 0;
+            for (ChildNodeEntry child : getChildNodeEntries(node, basePath)) {
+                String name = child.getName();
+                if (filter.includeNode(name) && index++ >= offset) {
+                    if (count++ >= maxChildNodes) {
+                        break;
+                    }
+
+                    json.key(name);
+                    if (depth > 0) {
+                        getChildSerializer().serialize(child.getNodeState(), basePath + "/" + name);
+                    } else {
+                        json.object();
+                        json.endObject();
+                    }
                 }
             }
+        } catch (Throwable t) {
+            if (catchExceptions) {
+                String message = "Cannot read node " + basePath + " : " + t.getMessage();
+                log.error(message);
+                json.key(ERROR_JSON_KEY);
+                json.value(ERROR_JSON_VALUE_PREFIX + message);
+            } else {
+                throw t;
+            }
         }
 
         json.endObject();
     }
 
-    private Iterable<? extends ChildNodeEntry> getChildNodeEntries(NodeState node) {
+    private Iterable<? extends ChildNodeEntry> getChildNodeEntries(NodeState node, String basePath) {
         PropertyState order = node.getProperty(":childOrder");
         if (order != null) {
             List<String> names = ImmutableList.copyOf(order.getValue(NAMES));
             List<ChildNodeEntry> entries = Lists.newArrayListWithCapacity(names.size());
             for (String name : names) {
-                entries.add(new MemoryChildNodeEntry(name, node.getChildNode(name)));
+                try {
+                    entries.add(new MemoryChildNodeEntry(name, node.getChildNode(name)));
+                } catch (Throwable t) {
+                    if (catchExceptions) {
+                        String message = "Cannot read node " + basePath + "/" + name + " : " + t.getMessage();
+                        log.error(message);
+
+                        // return a placeholder child node entry for tracking the error into the JSON
+                        entries.add(new MemoryChildNodeEntry(name, new AbstractNodeState() {
+                            @Override
+                            public boolean exists() {
+                                return true;
+                            }
+
+                            @NotNull
+                            @Override
+                            public Iterable<? extends PropertyState> getProperties() {
+                                return Collections.singleton(new StringPropertyState(ERROR_JSON_KEY, ERROR_JSON_VALUE_PREFIX + message));
+                            }
+
+                            @Override
+                            public boolean hasChildNode(@NotNull String name) {
+                                return false;
+                            }
+
+                            @NotNull
+                            @Override
+                            public NodeState getChildNode(@NotNull String name) throws IllegalArgumentException {
+                                return EmptyNodeState.MISSING_NODE;
+                            }
+
+                            @NotNull
+                            @Override
+                            public Iterable<? extends ChildNodeEntry> getChildNodeEntries() {
+                                return Collections.EMPTY_LIST;
+                            }
+
+                            @NotNull
+                            @Override
+                            public NodeBuilder builder() {
+                                return new ReadOnlyBuilder(this);
+                            }
+                        }));
+                    } else {
+                        throw t;
+                    }
+                }
             }
             return entries;
         }