You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2019/10/11 13:38:25 UTC

[lucene-solr] branch branch_8x updated (946df69 -> 71e9564)

This is an automated email from the ASF dual-hosted git repository.

noble pushed a change to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git.


    from 946df69  SOLR-13829: Update CHANGES.txt
     new dcb7abf  SOLR-13787: Added support for PayLoad<T> as 3rd param
     new 71e9564  SOLR-13787: Support for Payload<T> as 3rd param

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../src/java/org/apache/solr/api/AnnotatedApi.java | 57 ++++++++++++++++-----
 .../core/src/java/org/apache/solr/api/Command.java |  2 -
 .../api/{package-info.java => PayloadObj.java}     | 20 ++++++--
 .../org/apache/solr/util/ReflectMapWriter.java     | 58 ++++++++++++++++++++++
 .../solr/handler/admin/TestApiFramework.java       |  4 +-
 5 files changed, 120 insertions(+), 21 deletions(-)
 copy solr/core/src/java/org/apache/solr/api/{package-info.java => PayloadObj.java} (73%)
 create mode 100644 solr/core/src/java/org/apache/solr/util/ReflectMapWriter.java


[lucene-solr] 01/02: SOLR-13787: Added support for PayLoad as 3rd param

Posted by no...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

noble pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit dcb7abfc0ee3e9ac8827bf7b0128f1249fb7fc7e
Author: noble <no...@apache.org>
AuthorDate: Sat Oct 12 00:23:40 2019 +1100

    SOLR-13787: Added support for PayLoad<T> as 3rd param
---
 solr/core/src/java/org/apache/solr/api/AnnotatedApi.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
index cda2d64..b1be461 100644
--- a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
+++ b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
@@ -108,7 +108,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
 
       for (Method method : klas.getMethods()) {
         Command command = method.getAnnotation(Command.class);
-        if (command != null && !command.name().isEmpty()) {
+        if (command != null && !command.name().isBlank()) {
           cmds.put(command.name(), AnnotatedApi.createSchema(method));
         }
       }


[lucene-solr] 02/02: SOLR-13787: Support for Payload as 3rd param

Posted by no...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

noble pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit 71e9564e0d520449b6eeb52a6f67ede91ff091a7
Author: noble <no...@apache.org>
AuthorDate: Sat Oct 12 00:38:06 2019 +1100

    SOLR-13787: Support for Payload<T> as 3rd param
---
 .../src/java/org/apache/solr/api/AnnotatedApi.java | 59 +++++++++++++++++-----
 .../core/src/java/org/apache/solr/api/Command.java |  2 -
 .../solr/api/{Command.java => PayloadObj.java}     | 26 +++++-----
 .../org/apache/solr/util/ReflectMapWriter.java     | 58 +++++++++++++++++++++
 .../solr/handler/admin/TestApiFramework.java       |  4 +-
 5 files changed, 116 insertions(+), 33 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
index b1be461..964af85 100644
--- a/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
+++ b/solr/core/src/java/org/apache/solr/api/AnnotatedApi.java
@@ -45,14 +45,14 @@ import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.security.AuthorizationContext;
 import org.apache.solr.security.PermissionNameProvider;
 
-/**This class implements an Api just from  an annotated java class
+/**
+ * This class implements an Api just from  an annotated java class
  * The class must have an annotation {@link EndPoint}
  * Each method must have an annotation {@link Command}
  * The methods that implement a command should have the first 2 parameters
  * {@link SolrQueryRequest} and {@link SolrQueryResponse} or it may optionally
  * have a third parameter which could be a java class annotated with jackson annotations.
  * The third parameter is only valid if it is using a json command payload
- *
  */
 
 public class AnnotatedApi extends Api implements PermissionNameProvider {
@@ -62,7 +62,6 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
 
   public AnnotatedApi(Object obj) {
     this(obj, null);
-
   }
 
   public AnnotatedApi(Object obj, Api fallback) {
@@ -94,21 +93,21 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
 
   private static SpecProvider readSpec(Class klas) {
     EndPoint endPoint = (EndPoint) klas.getAnnotation(EndPoint.class);
-    if (endPoint == null) throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Invalid class :  "+ klas.getName());
-    EndPoint endPoint1 = (EndPoint) klas.getAnnotation(EndPoint.class);
+    if (endPoint == null)
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Invalid class :  " + klas.getName());
     return () -> {
       Map map = new LinkedHashMap();
       List<String> methods = new ArrayList<>();
-      for (SolrRequest.METHOD method : endPoint1.method()) {
+      for (SolrRequest.METHOD method : endPoint.method()) {
         methods.add(method.name());
       }
       map.put("methods", methods);
-      map.put("url", new ValidatingJsonMap(Collections.singletonMap("paths", Arrays.asList(endPoint1.path()))));
+      map.put("url", new ValidatingJsonMap(Collections.singletonMap("paths", Arrays.asList(endPoint.path()))));
       Map<String, Object> cmds = new HashMap<>();
 
       for (Method method : klas.getMethods()) {
         Command command = method.getAnnotation(Command.class);
-        if (command != null && !command.name().isBlank()) {
+        if (command != null && !command.name().isEmpty()) {
           cmds.put(command.name(), AnnotatedApi.createSchema(method));
         }
       }
@@ -132,7 +131,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
       }
     }
 
-    List<CommandOperation> cmds = req.getCommands(true);
+    List<CommandOperation> cmds = req.getCommands(false);
     boolean allExists = true;
     for (CommandOperation cmd : cmds) {
       if (!commands.containsKey(cmd.name)) {
@@ -168,6 +167,7 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
     ObjectMapper mapper = new ObjectMapper();
     int paramsCount;
     Class c;
+    boolean isWrappedInPayloadObj = false;
 
 
     Cmd(Command command, Object obj, Method method) {
@@ -181,7 +181,23 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
           throw new RuntimeException("Invalid params for method " + method);
         }
         if (parameterTypes.length == 3) {
-          c = parameterTypes[2];
+          Type t = method.getGenericParameterTypes()[2];
+          if (t instanceof ParameterizedType) {
+            ParameterizedType typ = (ParameterizedType) t;
+            if (typ.getRawType() == PayloadObj.class) {
+              isWrappedInPayloadObj = true;
+              Type t1 = typ.getActualTypeArguments()[0];
+              if (t1 instanceof ParameterizedType) {
+                ParameterizedType parameterizedType = (ParameterizedType) t1;
+                c = (Class) parameterizedType.getRawType();
+              } else {
+                c = (Class) typ.getActualTypeArguments()[0];
+              }
+            }
+          } else {
+            c = (Class) t;
+          }
+
         }
         if (parameterTypes.length > 3) {
           throw new RuntimeException("Invalid params count for method " + method);
@@ -195,7 +211,6 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
 
     void invoke(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation cmd) {
       try {
-
         if (paramsCount == 2) {
           method.invoke(obj, req, rsp);
         } else {
@@ -203,14 +218,26 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
           if (o instanceof Map && c != null) {
             o = mapper.readValue(Utils.toJSONString(o), c);
           }
-          method.invoke(obj, req, rsp, o);
+          if (isWrappedInPayloadObj) {
+            PayloadObj<Object> payloadObj = new PayloadObj<>(cmd.name, cmd.getCommandData(), o);
+            cmd = payloadObj;
+            method.invoke(obj, req, rsp, payloadObj);
+          } else {
+            method.invoke(obj, req, rsp, o);
+          }
+          if (cmd.hasError()) {
+            throw new ApiBag.ExceptionWithErrObject(SolrException.ErrorCode.BAD_REQUEST, "Error executing command",
+                CommandOperation.captureErrors(Collections.singletonList(cmd)));
+          }
         }
 
+
       } catch (SolrException se) {
         throw se;
       } catch (InvocationTargetException ite) {
         throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, ite.getCause());
       } catch (Exception e) {
+        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
       }
 
     }
@@ -243,11 +270,15 @@ public class AnnotatedApi extends Api implements PermissionNameProvider {
 
   private static Map<String, Object> createSchemaFromType(Type t) {
     Map<String, Object> map = new LinkedHashMap<>();
+    if (t instanceof ParameterizedType) {
+      ParameterizedType typ = (ParameterizedType) t;
+      if (typ.getRawType() == PayloadObj.class) {
+        t = typ.getActualTypeArguments()[0];
+      }
+    }
 
     if (primitives.containsKey(t)) {
       map.put("type", primitives.get(t));
-    } else if (t == List.class) {
-
     } else if (t instanceof ParameterizedType && ((ParameterizedType) t).getRawType() == List.class) {
       Type typ = ((ParameterizedType) t).getActualTypeArguments()[0];
       map.put("type", "array");
diff --git a/solr/core/src/java/org/apache/solr/api/Command.java b/solr/core/src/java/org/apache/solr/api/Command.java
index d18d064..25de077 100644
--- a/solr/core/src/java/org/apache/solr/api/Command.java
+++ b/solr/core/src/java/org/apache/solr/api/Command.java
@@ -32,6 +32,4 @@ public @interface Command {
    */
   String name() default "";
 
-  String jsonSchema() default "";
-
 }
diff --git a/solr/core/src/java/org/apache/solr/api/Command.java b/solr/core/src/java/org/apache/solr/api/PayloadObj.java
similarity index 64%
copy from solr/core/src/java/org/apache/solr/api/Command.java
copy to solr/core/src/java/org/apache/solr/api/PayloadObj.java
index d18d064..c09c442 100644
--- a/solr/core/src/java/org/apache/solr/api/Command.java
+++ b/solr/core/src/java/org/apache/solr/api/PayloadObj.java
@@ -17,21 +17,19 @@
 
 package org.apache.solr.api;
 
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
+import org.apache.solr.common.util.CommandOperation;
 
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.METHOD)
-public @interface Command {
-  /**if this is not a json command , leave it empty.
-   * Keep in mind that you cannot have duplicates.
-   * Only one method per name
-   *
-   */
-  String name() default "";
+public  class PayloadObj<T> extends CommandOperation {
 
-  String jsonSchema() default "";
+  private T obj;
 
+
+  public PayloadObj(String operationName, Object metaData, T obj) {
+    super(operationName, metaData);
+    this.obj = obj;
+  }
+
+  public T get(){
+    return obj;
+  }
 }
diff --git a/solr/core/src/java/org/apache/solr/util/ReflectMapWriter.java b/solr/core/src/java/org/apache/solr/util/ReflectMapWriter.java
new file mode 100644
index 0000000..9555740
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/ReflectMapWriter.java
@@ -0,0 +1,58 @@
+/*
+ * 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.solr.util;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.apache.solr.common.MapWriter;
+
+public interface ReflectMapWriter extends MapWriter {
+
+  @Override
+  default void writeMap(EntryWriter ew) throws IOException {
+    for (Field field : this.getClass().getDeclaredFields()) {
+      JsonProperty prop = field.getAnnotation(JsonProperty.class);
+      if (prop == null) continue;
+      int modifiers = field.getModifiers();
+      if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) {
+        String fname = prop.value().isEmpty() ? field.getName() : prop.value();
+        try {
+          if (field.getType() == int.class) {
+            ew.put(fname, field.getInt(this));
+          } else if (field.getType() == float.class) {
+            ew.put(fname, field.getFloat(this));
+          } else if (field.getType() == double.class) {
+            ew.put(fname, field.getDouble(this));
+          } else if (field.getType() == boolean.class) {
+            ew.put(fname, field.getBoolean(this));
+          } else if (field.getType() == long.class) {
+            ew.put(fname, field.getLong(this));
+          } else {
+            ew.putIfNotNull(fname, field.get(this));
+          }
+        } catch (IllegalAccessException e) {
+          //it should not happen
+        }
+      }
+    }
+  }
+
+}
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java b/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
index 933b862..fde0335 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/TestApiFramework.java
@@ -168,7 +168,7 @@ public class TestApiFramework extends SolrTestCaseJ4 {
 
   }
 
-  public void testPayload() throws IOException {
+  public void testPayload() {
     String json = "{package:pkg1, version: '0.1', files  :[a.jar, b.jar]}";
     Utils.fromJSONString(json);
 
@@ -213,8 +213,6 @@ public class TestApiFramework extends SolrTestCaseJ4 {
 
     }
 
-
-
   }
 
   public static class AddVersion {