You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by sa...@apache.org on 2016/12/13 20:06:48 UTC

lucene-solr:apiv2: SOLR-8029: Api spec parsing: Recursively handle '#include' directives in all JSON objects; replace repeated analyzer definitions in the addFieldType spec with a single file included for each of the different types of analyzers; add mul

Repository: lucene-solr
Updated Branches:
  refs/heads/apiv2 338b8d594 -> 6aa57e891


SOLR-8029: Api spec parsing: Recursively handle '#include' directives in all JSON objects; replace repeated analyzer definitions in the addFieldType spec with a single file included for each of the different types of analyzers; add multiTermAnalyzer key to addFieldType spec.


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/6aa57e89
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/6aa57e89
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/6aa57e89

Branch: refs/heads/apiv2
Commit: 6aa57e891aca031b598c085a10d26c1d82e99343
Parents: 338b8d5
Author: Steve Rowe <sa...@apache.org>
Authored: Tue Dec 13 15:06:39 2016 -0500
Committer: Steve Rowe <sa...@apache.org>
Committed: Tue Dec 13 15:06:39 2016 -0500

----------------------------------------------------------------------
 .../src/java/org/apache/solr/api/ApiBag.java    | 52 +------------
 .../core.SchemaEdit.addFieldType.analyzers.json | 51 +++++++++++++
 .../apispec/core.SchemaEdit.addFieldType.json   | 78 ++------------------
 .../solr/common/util/ValidatingJsonMap.java     | 52 +++++++++++--
 4 files changed, 107 insertions(+), 126 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/6aa57e89/solr/core/src/java/org/apache/solr/api/ApiBag.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/api/ApiBag.java b/solr/core/src/java/org/apache/solr/api/ApiBag.java
index 9a1da62..143792e 100644
--- a/solr/core/src/java/org/apache/solr/api/ApiBag.java
+++ b/solr/core/src/java/org/apache/solr/api/ApiBag.java
@@ -18,7 +18,6 @@
 package org.apache.solr.api;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.Reader;
 import java.lang.invoke.MethodHandles;
 import java.util.ArrayList;
@@ -59,27 +58,6 @@ public class ApiBag {
 
   private final Map<String, PathTrie<Api>> apis = new ConcurrentHashMap<>();
 
-  public static ValidatingJsonMap getResource(String name) {
-    InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(name);
-    if (is == null)
-      throw new RuntimeException("invalid API spec :" + name );
-    ValidatingJsonMap map1 = null;
-    try {
-      map1 = ValidatingJsonMap.fromJSON(is);
-    } catch (Exception e) {
-      log.error("Error in JSON : " + name, e);
-      if (e instanceof RuntimeException) {
-        throw (RuntimeException) e;
-      }
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
-    }
-    if (map1 == null) throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Empty value for " + name);
-
-    return ValidatingJsonMap.getDeepCopy(map1, 5, false);
-  }
-
-
-
   public synchronized void register(Api api, Map<String, String> nameSubstitutes) {
     try {
       validateAndRegister(api, nameSubstitutes);
@@ -208,36 +186,8 @@ public class ApiBag {
 
   public static SpecProvider getSpec(final String name) {
     return () -> {
-      String jsonName = APISPEC_LOCATION + name + ".json";
-      ValidatingJsonMap map = getResource(jsonName);
-      ValidatingJsonMap result = map;
-      ValidatingJsonMap cmds = result.getMap("commands", null);
-      if (cmds != null) {
-        Map  commands2BReplaced = new ValidatingJsonMap();
-        for (Object o : cmds.keySet()) {
-          Object val = cmds.get(o);
-          Map m = (Map) val;
-          String include = (String) m.get("#include");
-          if (include != null) {
-            ValidatingJsonMap cmdSpec = getResource(APISPEC_LOCATION + include + ".json");
-            m = ValidatingJsonMap.getDeepCopy(m, 4, true);
-            m.remove("#include");
-            m.putAll(cmdSpec);
-            commands2BReplaced.put(o.toString(), m);
-          }
-        }
-
-        if (!commands2BReplaced.isEmpty()) {
-          ValidatingJsonMap mapCopy = ValidatingJsonMap.getDeepCopy(result, 4, true);
-          mapCopy.getMap("commands", NOT_NULL).putAll(commands2BReplaced);
-          result = ValidatingJsonMap.getDeepCopy(mapCopy, 4, false);
-        }
-      }
-
-      return result;
+      return ValidatingJsonMap.parse(APISPEC_LOCATION + name + ".json", APISPEC_LOCATION);
     };
-
-
   }
 
   public static class ReqHandlerToApi extends Api implements PermissionNameProvider {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/6aa57e89/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.analyzers.json
----------------------------------------------------------------------
diff --git a/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.analyzers.json b/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.analyzers.json
new file mode 100644
index 0000000..2974a60
--- /dev/null
+++ b/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.analyzers.json
@@ -0,0 +1,51 @@
+{
+  "type": "object",
+  "properties": {
+    "class": {
+      "type": "string"
+    },
+    "charFilters": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "properties": {
+          "class": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "class"
+        ],
+        "additionalProperties": true
+      }
+    },
+    "tokenizer": {
+      "type": "object",
+      "properties": {
+        "class": {
+          "type": "string"
+        }
+      },
+      "required": [
+        "class"
+      ],
+      "additionalProperties": true
+    },
+    "filters": {
+      "type": "array",
+      "items": {
+        "type": "object",
+        "properties": {
+          "class": {
+            "type": "string"
+          }
+        },
+        "required": [
+          "class"
+        ],
+        "additionalProperties": true
+      }
+    }
+  },
+  "additionalProperties": true
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/6aa57e89/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.json
----------------------------------------------------------------------
diff --git a/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.json b/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.json
index 3a44f6e..e24572e 100644
--- a/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.json
+++ b/solr/core/src/resources/apispec/core.SchemaEdit.addFieldType.json
@@ -28,83 +28,21 @@
       "description": "Defines a custom PostingsFormat to use for fields of this type. A custom PostingsFormat requires that a schema-aware codec has also been configured in solrconfig.xml."
     },
     "queryAnalyzer": {
-      "type": "object",
       "description": "A query analyzer section defines how incoming queries to Solr will be analyzed for a field of this type.",
-      "properties":{
-         "tokenizer": {
-            "type": "object",
-            "properties": {
-               "class": {
-                  "type": "string"
-             }
-          },
-           "additionalProperties": true
-         }
-      },
-      "additionalProperties": true
+      "#include": "core.SchemaEdit.addFieldType.analyzers"
     },
     "indexAnalyzer": {
-      "type": "object",
       "description": "An index analyzer section defines how incoming text in documents will be analyzed for a field of this type.",
-      "properties": {
-        "tokenizer": {
-          "type": "object",
-          "description": "",
-          "properties": {
-            "class": {
-              "type": "string"
-            }
-          },
-          "additionalProperties": true
-        }
-      },
-      "additionalProperties": true
+      "#include": "core.SchemaEdit.addFieldType.analyzers"
+    },
+    "multiTermAnalyzer": {
+      "description": "A multiterm analyzer section defines how incoming queries that results in Multi-Term expansion will be analyzed for a field of this type.",
+      "documentation": "https://cwiki.apache.org/confluence/display/solr/Analyzers#Analyzers-AnalysisforMulti-TermExpansion",
+      "#include": "core.SchemaEdit.addFieldType.analyzers"
     },
     "analyzer": {
-      "type": "object",
       "description": "An analyzer defines how both incoming text in documents and queries are analyzed for a field of this type. If a query analyzer and an index analyzer have both been defined, a general analyzer does not need to be defined for this type.",
-      "properties": {
-        "class": {
-          "type": "string"
-        },
-        "tokenizer":{
-          "type":"object",
-          "properties":{
-            "class":{
-              "type":"string"
-            }
-          },
-          "required":["class"],
-          "additionalProperties":true
-        },
-        "charFilters":{
-          "type":"array",
-          "items":{
-            "type":"object",
-            "properties":{
-              "class":{
-                "type":"string"
-              }
-            },
-            "required":["class"],
-            "additionalProperties":true
-          }
-        },
-        "filters":{
-          "type":"array",
-          "items":{
-            "type":"object",
-            "properties":{
-              "class":{
-                "type":"string"
-              }
-            },
-            "required":["class"],
-            "additionalProperties":true
-          }
-        }
-      },
-      "additionalProperties": true
+      "#include": "core.SchemaEdit.addFieldType.analyzers"
     }
   },
   "additionalProperties": true,

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/6aa57e89/solr/solrj/src/java/org/apache/solr/common/util/ValidatingJsonMap.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/ValidatingJsonMap.java b/solr/solrj/src/java/org/apache/solr/common/util/ValidatingJsonMap.java
index 3ea11bf..95318af 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/ValidatingJsonMap.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/ValidatingJsonMap.java
@@ -30,15 +30,20 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.solr.common.SolrException;
 import org.noggit.JSONParser;
 import org.noggit.ObjectBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.Collections.unmodifiableList;
 import static java.util.Collections.unmodifiableSet;
 
 public class ValidatingJsonMap implements Map<String, Object> {
-
+  private static final Logger log = LoggerFactory.getLogger(ValidatingJsonMap.class);
+  private static final String INCLUDE = "#include";
+  private static final String RESOURCE_EXTENSION = ".json";
   public static final PredicateWithErrMsg<Object> NOT_NULL = o -> {
     if (o == null) return " Must not be NULL";
     return null;
@@ -237,18 +242,37 @@ public class ValidatingJsonMap implements Map<String, Object> {
 
   }
 
-  public static ValidatingJsonMap fromJSON(InputStream is) {
-    return fromJSON(new InputStreamReader(is, UTF_8));
+  public static ValidatingJsonMap fromJSON(InputStream is,  String includeLocation) {
+    return fromJSON(new InputStreamReader(is, UTF_8), includeLocation);
   }
 
-  public static ValidatingJsonMap fromJSON(Reader s) {
+  public static ValidatingJsonMap fromJSON(Reader s, String includeLocation) {
     try {
-      return (ValidatingJsonMap) (getObjectBuilder(new JSONParser(s)).getObject());
+      ValidatingJsonMap map = (ValidatingJsonMap)getObjectBuilder(new JSONParser(s)).getObject();
+      handleIncludes(map, includeLocation);
+      return map;
     } catch (IOException e) {
       throw new RuntimeException();
     }
   }
 
+  /** 
+   * In the given map, recursively replace "#include":"resource-name" with the key/value pairs 
+   * parsed from the resource at {location}/{resource-name}.json
+   */
+  private static void handleIncludes(ValidatingJsonMap map, String location) {
+    final String loc = location == null ? "" // trim trailing slash
+        : (location.endsWith("/") ? location.substring(0, location.length() - 1) : location); 
+    String resourceToInclude = (String)map.get(INCLUDE);
+    if (resourceToInclude != null) {
+      ValidatingJsonMap includedMap = parse(loc + "/" + resourceToInclude + RESOURCE_EXTENSION, loc);
+      map.remove(INCLUDE);
+      map.putAll(includedMap);
+    }
+    map.entrySet().stream().filter(e->e.getValue() instanceof Map).map(Map.Entry::getValue)
+        .forEach(m->handleIncludes((ValidatingJsonMap)m, loc));
+  }
+
   public static ValidatingJsonMap getDeepCopy(Map map, int maxDepth, boolean mutable) {
     if (map == null) return null;
     if (maxDepth < 1) return ValidatingJsonMap.wrap(map);
@@ -284,6 +308,24 @@ public class ValidatingJsonMap implements Map<String, Object> {
     };
   }
 
+  public static ValidatingJsonMap parse(String resourceName, String includeLocation) {
+    InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(resourceName);
+    if (is == null)
+      throw new RuntimeException("invalid API spec: " + resourceName);
+    ValidatingJsonMap map = null;
+    try {
+      map = fromJSON(is, includeLocation);
+    } catch (Exception e) {
+      log.error("Error in JSON : " + resourceName, e);
+      if (e instanceof RuntimeException) {
+        throw e;
+      }
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
+    }
+    if (map == null) throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Empty value for " + resourceName);
+
+    return getDeepCopy(map, 5, false);
+  }
 
   @Override
   public boolean equals(Object that) {