You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2014/03/16 19:11:10 UTC
svn commit: r1578133 [8/11] - in /lucene/dev/branches/lucene5376_2/lucene:
./ analysis/common/src/java/org/apache/lucene/analysis/charfilter/
analysis/common/src/java/org/apache/lucene/analysis/pattern/
analysis/common/src/java/org/apache/lucene/analys...
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/Request.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/Request.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/Request.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/Request.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,679 @@
+package org.apache.lucene.server.params;
+
+/*
+ * 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.
+ */
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.lucene.server.params.PolyType.PolyEntry;
+import net.minidev.json.JSONArray;
+import net.minidev.json.JSONObject;
+
+// nocommit instead of removing as we getXXX, we could do a
+// Set<String> seen?
+// - would close the loophole of foobar={} not being detected
+// - would allow us to lookup same param more than once
+
+/** Pairs up the actual parameters with its type. For
+ * complex requests, e.g. {@code search}, this is used
+ * recursively. For example, the top-most Request is
+ * created, but then when a sub-struct parameter is
+ * retrieved with {@link #getStruct}, that returns another
+ * {@code Request} wrapping that value. */
+
+public class Request {
+
+ /** Type describing the expected object. */
+ private final StructType type;
+
+ /** The actual request parameters. */
+ private final JSONObject params;
+
+ /** Parent, if this is a sub Request, else null for the
+ * top-level request. This is used for back-trace for
+ * error reporting. */
+ private final Request parent;
+
+ /** Our parameter name from our parent, or null if we are
+ * a top request. This is used for back-trace for error
+ * reporting. */
+ private final String name;
+
+ /** Creates this. */
+ public Request(Request parent, String name, JSONObject params, StructType type) {
+ this.params = params;
+ this.type = type;
+ this.parent = parent;
+ this.name = name;
+ }
+
+ /** Creates Request from another Request, changing the
+ * struct type. */
+ public Request(Request other, StructType type) {
+ this.params = other.params;
+ this.type = type;
+ this.parent = other.parent;
+ this.name = other.name;
+ }
+
+ /** Clears all parameters. */
+ public void clearParams() {
+ params.clear();
+ }
+
+ /** Clear a specific parameter. */
+ public void clearParam(String param) {
+ params.remove(param);
+ }
+
+ /** Get the type for this request. */
+ public StructType getType() {
+ return type;
+ }
+
+ /** True if this param was specified. */
+ public boolean hasParam(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ return params.containsKey(name);
+ }
+
+ /** Returns an iterator over all parameters and their
+ * values. */
+ public Iterator<Map.Entry<String,Object>> getParams() {
+ return params.entrySet().iterator();
+ }
+
+ /** Returns the parameters. */
+ public JSONObject getRawParams() {
+ return params;
+ }
+
+ @Override
+ public String toString() {
+ return params.toString();
+ }
+
+ /** Returns the raw (un type cast) value for this
+ * parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter.*/
+ public Object getAny(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ assert p.type instanceof AnyType;
+
+ Object v = params.get(name);
+ if (v == null) {
+ // Request didn't provide it:
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return p.defaultValue;
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return false;
+ }
+ } else {
+ params.remove(name);
+ p.type.validate(v);
+ return v;
+ }
+ }
+
+ /** Retrieve a boolean parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter. */
+ public boolean getBoolean(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ assert p.type instanceof BooleanType: "name \"" + name + "\" is not BooleanType: got " + p.type;
+
+ Object v = params.get(name);
+ if (v == null) {
+ // Request didn't provide it:
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return ((Boolean) p.defaultValue).booleanValue();
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return false;
+ }
+ } else {
+ try {
+ p.type.validate(v);
+ } catch (IllegalArgumentException iae) {
+ fail(name, iae.getMessage(), iae);
+ }
+ params.remove(name);
+ return ((Boolean) v).booleanValue();
+ }
+ }
+
+ /** Retrieve a float parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter. */
+ public float getFloat(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ assert p.type instanceof FloatType: "name \"" + name + "\" is not FloatType: got " + p.type;
+
+ Object v = params.get(name);
+ if (v == null) {
+ // Request didn't provide it:
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return ((Float) p.defaultValue).floatValue();
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return 0;
+ }
+ } else {
+ try {
+ p.type.validate(v);
+ } catch (IllegalArgumentException iae) {
+ fail(name, iae.getMessage(), iae);
+ }
+ params.remove(name);
+ return ((Number) v).floatValue();
+ }
+ }
+
+ /** Retrieve a double parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter. */
+ public double getDouble(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ // assert p.type instanceof FloatType: "name \"" + name + "\" is not FloatType: got " + p.type;
+
+ Object v = params.get(name);
+ if (v == null) {
+ // Request didn't provide it:
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return ((Number) p.defaultValue).doubleValue();
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return 0;
+ }
+ } else {
+ try {
+ p.type.validate(v);
+ } catch (IllegalArgumentException iae) {
+ fail(name, iae.getMessage(), iae);
+ }
+ params.remove(name);
+ return ((Number) v).doubleValue();
+ }
+ }
+
+ /** Retrieve an int parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter. */
+ public int getInt(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ assert p.type instanceof IntType: "name \"" + name + "\" is not IntType: got " + p.type;
+
+ Object v = params.get(name);
+ if (v == null) {
+ // Request didn't provide it:
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return ((Integer) p.defaultValue).intValue();
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return 0;
+ }
+ } else if (!(v instanceof Integer)) {
+ fail(name, "expected Integer but got: " + v.getClass());
+ // Dead code but compiler disagrees:
+ return 0;
+ } else {
+ params.remove(name);
+ return ((Integer) v).intValue();
+ }
+ }
+
+ /** Retrieve a long parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter. */
+ public long getLong(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ //assert p.type instanceof LongType: "name \"" + name + "\" is not LongType: got " + p.type;
+
+ Object v = params.get(name);
+ if (v == null) {
+ // Request didn't provide it:
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return ((Long) p.defaultValue).longValue();
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return 0L;
+ }
+ } else if (!(v instanceof Long) && !(v instanceof Integer)) {
+ fail(name, "expected Long but got: " + v.getClass());
+ // Dead code but compiler disagrees:
+ return 0L;
+ } else {
+ params.remove(name);
+ return ((Number) v).longValue();
+ }
+ }
+
+ /** True if the parameter is a string value. */
+ public boolean isString(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ Object v = params.get(name);
+ return v instanceof String;
+ }
+
+ /** Retrieve a string parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter. */
+ public String getString(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ // Use getEnum instead:
+ assert !(p.type instanceof EnumType);
+
+ Object v = params.get(name);
+ if (v == null) {
+ // Request didn't provide it:
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return (String) p.defaultValue;
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return null;
+ }
+ } else {
+ if ((v instanceof String) == false) {
+ fail(name, "expected String but got " + toSimpleString(v.getClass()));
+ }
+ try {
+ p.type.validate(v);
+ } catch (IllegalArgumentException iae) {
+ fail(name, iae.getMessage(), iae);
+ }
+ params.remove(name);
+ return (String) v;
+ }
+ }
+
+ private static String toSimpleString(Class<?> cl) {
+ return cl.getSimpleName();
+ }
+
+ /** Retrieve an enum parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter. */
+ public String getEnum(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ assert p.type instanceof EnumType: "name \"" + name + "\" is not EnumType: got " + p.type;
+
+ Object v = params.get(name);
+ if (v == null) {
+ // Request didn't provide it:
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return (String) p.defaultValue;
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return null;
+ }
+ } else {
+ // Make sure the value is valid for this enum:
+ try {
+ p.type.validate(v);
+ } catch (IllegalArgumentException iae) {
+ fail(name, iae.getMessage(), iae);
+ }
+ params.remove(name);
+ return (String) v;
+ }
+ }
+
+ /** A result returned from {@link #getPoly}. */
+ public static class PolyResult {
+ /** The name of the poly parameter. */
+ public final String name;
+
+ /** The new request, cast to the poly sub type */
+ public final Request r;
+
+ /** Sole constructor. */
+ PolyResult(String name, Request r) {
+ this.name = name;
+ this.r = r;
+ }
+ }
+
+ /** Retrieve a poly typed parameter. Once this is called
+ * for a given parameter it cannot be called again on
+ * that parameter. */
+ public PolyResult getPoly(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ assert p.type instanceof PolyType: "name \"" + name + "\" is not PolyType: got " + p.type;
+ Object v = params.get(name);
+ if (v == null) {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return null;
+ } else if (!(v instanceof String)) {
+ fail(name, "expected String but got " + v);
+ // dead code but compiler disagrees:
+ return null;
+ } else {
+ PolyType pt = (PolyType) p.type;
+ String value = (String) v;
+ PolyEntry sub = pt.types.get(value);
+ if (sub == null) {
+ fail(name, "unrecognized value \"" + value + "\"; must be one of: " + pt.types.keySet());
+ }
+ params.remove(name);
+ return new PolyResult((String) v, new Request(parent, name, params, sub.type));
+ }
+ }
+
+ /** Retrieve the raw object for a parameter, or null if
+ * the parameter was not specified. This can be called
+ * multiple types for a given parameter. */
+ public Object getRaw(String name) {
+ return params.get(name);
+ }
+
+ /** Returns the raw object, and removes the binding. */
+ public Object getAndRemoveRaw(String name) {
+ Object o = params.get(name);
+ params.remove(name);
+ return o;
+ }
+
+ /** Retrieve a struct parameter. This can be called
+ * multiple times for a given parameter name. */
+ public Request getStruct(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter; valid params=" + type.params.keySet() + "; path=" + getPath();
+ Type pType = p.type;
+ if (pType instanceof WrapType) {
+ pType = ((WrapType) pType).getWrappedType();
+ }
+ if (pType instanceof StructType == false) {
+ pType = findStructType(pType);
+ }
+ assert pType instanceof StructType: "name \"" + name + "\" is not StructType: got " + type;
+
+ Object v = params.get(name);
+ if (v == null) {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return null;
+ } else {
+ // If the value is a String, and the type is Struct
+ // that has a "class" param, pretend this was a Struct
+ // with just the "class" param. This is so user can
+ // just do String (for the class name) instead of
+ // struct with only "class" param:
+ if (v instanceof String) {
+ StructType st = (StructType) pType;
+ if (st.params.containsKey("class") && st.params.get("class").type instanceof PolyType) {
+ JSONObject o = new JSONObject();
+ o.put("class", v);
+ v = o;
+ params.remove(name);
+ }
+ }
+
+ if (!(v instanceof JSONObject)) {
+ fail(name, "expected Object but got " + v.getClass());
+ }
+
+ // nocommit does this mean we fail to detect when a
+ // whole extra struct was specified
+
+ // Don't remove, so that we can recurse and make sure
+ // all structs had all their params visited too
+ //params.remove(name);
+ return new Request(this, name, (JSONObject) v, (StructType) pType);
+ }
+ }
+
+ // nocommit hacky
+ private StructType findStructType(Type t) {
+ if (t instanceof StructType) {
+ return (StructType) t;
+ } else if (t instanceof ListType) {
+ ListType lt = (ListType) t;
+ if (lt.subType instanceof StructType) {
+ return (StructType) lt.subType;
+ } else if (lt.subType instanceof OrType) {
+ for(Type t2 : ((OrType) lt.subType).types) {
+ if (t2 instanceof StructType) {
+ return (StructType) t2;
+ }
+ }
+ }
+ } else if (t instanceof OrType) {
+ OrType ot = (OrType) t;
+ for(Type t2 : ot.types) {
+ if (t2 instanceof StructType) {
+ return (StructType) t2;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /** Retrieve a list parameter. Once this is called for a
+ * given parameter it cannot be called again on that
+ * parameter. */
+ @SuppressWarnings("unchecked")
+ public List<Object> getList(String name) {
+ Param p = type.params.get(name);
+ assert p != null: "name \"" + name + "\" is not a known parameter";
+ // nocommit make this stronger ... check the subTypes of OrType:
+ //assert p.type instanceof ListType: "name \"" + name + "\" is not ListType: got " + p.type;
+ assert p.type instanceof ListType || p.type instanceof OrType: "name \"" + name + "\" is not ListType: got " + p.type;
+ Object v = params.get(name);
+ if (v == null) {
+ if (p.defaultValue != null) {
+ // Fallback to default
+ return (List<Object>) p.defaultValue;
+ } else {
+ fail(name, "required parameter \"" + name + "\" is missing");
+ // dead code but compiler disagrees:
+ return null;
+ }
+ } else {
+ if (!(v instanceof JSONArray)) {
+ fail(name, "expected array but got " + v.getClass());
+ }
+ List<Object> subs = new ArrayList<Object>();
+ Iterator<Object> it = ((JSONArray) v).iterator();
+ int idx = 0;
+ while(it.hasNext()) {
+ Object o = it.next();
+
+ // If the value is a String, and the type is Struct
+ // that has a "class" param, pretend this was a Struct
+ // with just the "class" param. This is so user can
+ // just do String (for the class name) instead of
+ // struct with only "class" param:
+ if (o instanceof String && p.type instanceof ListType && ((ListType) p.type).subType instanceof StructType) {
+ StructType st = (StructType) ((ListType) p.type).subType;
+ if (st.params.containsKey("class") && st.params.get("class").type instanceof PolyType) {
+ JSONObject o2 = new JSONObject();
+ o2.put("class", o);
+ o = o2;
+ it.remove();
+ }
+ }
+
+ if (o instanceof JSONObject) {
+ StructType st = findStructType(p.type);
+ if (st != null) {
+ subs.add(new Request(this, name + "[" + idx + "]", (JSONObject) o, st));
+ } else {
+ subs.add(o);
+ }
+ } else {
+ // nocommit make this work w/ OrType
+ if (p.type instanceof ListType) {
+ try {
+ ((ListType) p.type).subType.validate(o);
+ } catch (IllegalArgumentException iae) {
+ fail(name + "[" + idx + "]", iae.getMessage(), iae);
+ }
+ }
+ subs.add(o);
+ }
+ if (!(o instanceof JSONObject)) {
+ // nocommit this is O(N^2)!!
+ it.remove();
+ }
+ idx++;
+ }
+ return subs;
+ }
+ }
+
+ /** True if this request has any bindings, excluding
+ * empty containers. */
+ public static boolean anythingLeft(JSONObject obj) {
+ Iterator<Map.Entry<String,Object>> it = obj.entrySet().iterator();
+ boolean anything = false;
+ while(it.hasNext()) {
+ Map.Entry<String,Object> ent = it.next();
+ if (ent.getValue() instanceof JSONObject) {
+ if (!anythingLeft((JSONObject) ent.getValue())) {
+ it.remove();
+ } else {
+ anything = true;
+ }
+ } else if (ent.getValue() instanceof JSONArray) {
+ Iterator<Object> it2 = ((JSONArray) ent.getValue()).iterator();
+ while(it2.hasNext()) {
+ Object obj2 = it2.next();
+ if (obj2 instanceof JSONObject) {
+ if (!anythingLeft((JSONObject) obj2)) {
+ it2.remove();
+ } else {
+ anything = true;
+ }
+ }
+ }
+ if (((JSONArray) ent.getValue()).isEmpty()) {
+ it.remove();
+ } else {
+ anything = true;
+ }
+ } else {
+ anything = true;
+ }
+ }
+
+ return anything;
+ }
+
+ private void buildPath(StringBuilder sb) {
+ if (parent != null) {
+ parent.buildPath(sb);
+ }
+ if (sb.length() > 0) {
+ sb.append(" > ");
+ }
+ if (name != null) {
+ sb.append(name);
+ }
+ }
+
+ private String getPath() {
+ StringBuilder sb = new StringBuilder();
+ buildPath(sb);
+ return sb.toString();
+ }
+
+ /** Throws a {@link RequestFailedException} with the
+ * provided message. */
+ public void fail(String message) {
+ fail(null, message, null);
+ }
+
+ /** Throws a {@link RequestFailedException} with the
+ * provided parameter and message. */
+ public void fail(String param, String message) {
+ fail(param, message, null);
+ }
+
+ /** Throws a {@link RequestFailedException} with the
+ * provided parameter and message. */
+ public void fail(String message, Throwable cause) {
+ fail(null, message, cause);
+ }
+
+ /** Throws {@link RequestFailedException} when the wrong
+ * class was encountered. */
+ public void failWrongClass(String param, String reason, Object thingy) {
+ fail(param, reason + "; got: " + thingy.getClass());
+ }
+
+ /** Throws a {@link RequestFailedException} with the
+ * provided parameter and message and original cause. */
+ public void fail(String param, String reason, Throwable cause) {
+ StringBuilder sb = new StringBuilder();
+ buildPath(sb);
+ if (param != null) {
+ Param p = type.params.get(param);
+
+ // Exempt param[N]:
+ if (p == null && param.indexOf('[') == -1) {
+ // BUG:
+ assert false: "name \"" + param + "\" is not a known parameter";
+ }
+
+ if (sb.length() > 0) {
+ sb.append(" > ");
+ }
+ sb.append(param);
+ }
+
+ RequestFailedException e = new RequestFailedException(this, param, sb.toString(), reason);
+ if (cause != null) {
+ e.initCause(cause);
+ }
+
+ throw e;
+ }
+}
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/RequestFailedException.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/RequestFailedException.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/RequestFailedException.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/RequestFailedException.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,58 @@
+package org.apache.lucene.server.params;
+
+/*
+ * 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.
+ */
+
+// nocommit rename to InvalidRequestExc?
+
+/** Exception thrown on an invalid request. */
+public class RequestFailedException extends IllegalArgumentException {
+
+ /** The request that contains the failure. */
+ public final Request request;
+
+ /** Which parameter led to the failure, if any (can be
+ * null). */
+ public final String param;
+
+ /** The full path leading to the parameter (e.g.,
+ * sort.fields[0].field). */
+ public final String path;
+
+ /** The specific reason for the failure (e.g., "expected
+ * int but got string"). */
+ public final String reason;
+
+ /** Creates this. */
+ public RequestFailedException(Request r, String param, String path, String reason) {
+ super(path + ": " + reason);
+ this.request = r;
+ this.param = param;
+ this.path = path;
+ this.reason = reason;
+ }
+
+ /** Creates this from another {@code
+ * RequestFailedException}, adding further details. */
+ public RequestFailedException(RequestFailedException other, String details) {
+ super(other.reason + ": " + details);
+ this.reason = other.reason + ": " + details;
+ this.request = other.request;
+ this.param = other.param;
+ this.path = other.path;
+ }
+}
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/StringType.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/StringType.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/StringType.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/StringType.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,33 @@
+package org.apache.lucene.server.params;
+
+/*
+ * 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.
+ */
+
+/** Type for a string. */
+public class StringType extends Type {
+
+ /** Sole constructor. */
+ public StringType() {
+ }
+
+ @Override
+ public void validate(Object o) {
+ if (!(o instanceof String)) {
+ throw new IllegalArgumentException("expected String but got " + o.getClass());
+ }
+ }
+}
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/StructType.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/StructType.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/StructType.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/StructType.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,62 @@
+package org.apache.lucene.server.params;
+
+/*
+ * 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.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.minidev.json.JSONObject;
+
+/** Type for a structure containing named typed parameters. */
+public class StructType extends Type {
+
+ /** Parameters contained in this struct. */
+ public final Map<String,Param> params = new HashMap<String,Param>();
+
+ /** Sole constructor. */
+ public StructType(Param... params) {
+ boolean sawPoly = false;
+ for(Param p : params) {
+ if (this.params.containsKey(p.name)) {
+ throw new IllegalArgumentException("param name \"" + p.name + "\" appears more than once");
+ }
+ if (p.type instanceof PolyType) {
+ if (sawPoly) {
+ throw new IllegalArgumentException("only one PolyType per struct");
+ }
+ sawPoly = true;
+ }
+ this.params.put(p.name, p);
+ }
+ }
+
+ /** Add another parameter. */
+ public void addParam(Param param) {
+ if (params.containsKey(param.name)) {
+ throw new IllegalArgumentException("param name \"" + param.name + "\" already exists");
+ }
+ params.put(param.name, param);
+ }
+
+ @Override
+ public void validate(Object _o) {
+ if (!(_o instanceof JSONObject)) {
+ throw new IllegalArgumentException("expected struct but got " + _o.getClass());
+ }
+ }
+}
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/Type.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/Type.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/Type.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/Type.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,31 @@
+package org.apache.lucene.server.params;
+
+/*
+ * 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.
+ */
+
+/** Base class for al types. */
+public abstract class Type {
+
+ /** Sole constructor. */
+ protected Type() {
+ }
+
+ /** Confirms that the object is a valid item matching the
+ * type; if it is not, throw {@code
+ * IllegalArgumentException}. */
+ public abstract void validate(Object o);
+}
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/WrapType.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/WrapType.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/WrapType.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/WrapType.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,46 @@
+package org.apache.lucene.server.params;
+
+/*
+ * 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.
+ */
+
+/** Wraps another type; use this to break type recursion. */
+public class WrapType extends Type {
+ private Type other;
+
+ /** Sole constructor. */
+ public WrapType() {
+ }
+
+ /** Set our wrapped type. */
+ public void set(Type other) {
+ if (this.other != null) {
+ throw new IllegalStateException("already set");
+ }
+
+ this.other = other;
+ }
+
+ @Override
+ public void validate(Object o) {
+ other.validate(o);
+ }
+
+ /** Return the type we wrap. */
+ public Type getWrappedType() {
+ return other;
+ }
+}
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/package.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/package.html?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/package.html (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/params/package.html Sun Mar 16 18:11:07 2014
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<html>
+ <head>
+ <title>Lucene Server: params</title>
+ </head>
+ <body>
+ <h1>Lucene Server: params</h1>
+ Classes to handle matching incoming JSON requests against declared expected types.
+ </body>
+</html>
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/plugins/Plugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/plugins/Plugin.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/plugins/Plugin.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/plugins/Plugin.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,32 @@
+package org.apache.lucene.server.plugins;
+
+/*
+ * 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.
+ */
+
+/** Base class for all plugins. */
+public abstract class Plugin {
+
+ /** Sole constructor. */
+ public Plugin() {
+ }
+
+ /** Name of this plugin. */
+ public abstract String getName();
+
+ /** Documentation for this plugin (English). */
+ public abstract String getTopDoc();
+}
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/plugins/package.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/plugins/package.html?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/plugins/package.html (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/org/apache/lucene/server/plugins/package.html Sun Mar 16 18:11:07 2014
@@ -0,0 +1,25 @@
+<!--
+ 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.
+-->
+<html>
+ <head>
+ <title>Lucene Server: plugins</title>
+ </head>
+ <body>
+ <h1>Lucene Server: plugins</h1>
+ Classes to handle plugins.
+ </body>
+</html>
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/java/overview.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/java/overview.html?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/java/overview.html (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/java/overview.html Sun Mar 16 18:11:07 2014
@@ -0,0 +1,26 @@
+<!--
+ 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.
+-->
+<html>
+ <head>
+ <title>
+ server
+ </title>
+ </head>
+ <body>
+ Demo search server
+ </body>
+</html>
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/resources/META-INF/services/org.apache.lucene.codecs.Codec
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/resources/META-INF/services/org.apache.lucene.codecs.Codec?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/resources/META-INF/services/org.apache.lucene.codecs.Codec (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/resources/META-INF/services/org.apache.lucene.codecs.Codec Sun Mar 16 18:11:07 2014
@@ -0,0 +1,16 @@
+# 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.
+
+org.apache.lucene.server.ServerCodec
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/another-post.py
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/another-post.py?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/another-post.py (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/another-post.py Sun Mar 16 18:11:07 2014
@@ -0,0 +1,57 @@
+import json
+import threading
+import http.client
+import urllib.request, urllib.error, urllib.parse
+import subprocess
+import shutil
+
+shutil.rmtree('index')
+shutil.rmtree('taxonomy')
+
+def send(command, data):
+ u = urllib.request.urlopen('http://localhost:4000/%s' % command, data)
+ print('did open')
+ print(u.read())
+
+def readServerOutput(p, startupEvent, failureEvent):
+ while True:
+ l = p.stdout.readline()
+ if l == '':
+ failureEvent.set()
+ startupEvent.set()
+ raise RuntimeError('Server failed to start')
+ if l.find('listening on port 4000') != -1:
+ startupEvent.set()
+ print('SVR: %s' % l.rstrip())
+
+startupEvent = threading.Event()
+failureEvent = threading.Event()
+
+p = subprocess.Popen('java -cp /home/mike/.ivy2/cache/net.minidev/json-smart/jars/json-smart-1.1.1.jar:/home/mike/.ivy2/cache/org.apache.lucene/lucene-facet/jars/lucene-facet-4.1-SNAPSHOT.jar:/home/mike/.ivy2/cache/org.apache.lucene/lucene-highlighter/jars/lucene-highlighter-4.1-SNAPSHOT.jar:/home/mike/.ivy2/cache/io.netty/netty/bundles/netty-3.5.11.Final.jar:/home/mike/.ivy2/cache/org.apache.lucene/lucene-core/jars/lucene-core-4.1-SNAPSHOT.jar:/home/mike/.ivy2/cache/org.apache.lucene/lucene-analyzers-common/jars/lucene-analyzers-common-4.1-SNAPSHOT.jar:/l/server/build/luceneserver.jar org.apache.lucene.server.Server', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
+t = threading.Thread(target=readServerOutput, args=(p, startupEvent, failureEvent))
+t.setDaemon(True)
+t.start()
+
+startupEvent.wait()
+if failureEvent.isSet():
+ sys.exit(0)
+
+print('Server started...')
+
+fields = {'date': {'type': 'atom',
+ 'index': True,
+ 'store': True}}
+
+send('registerFields', json.dumps(fields))
+
+print('Done register')
+
+h = http.client.HTTPConnection('localhost', 4000)
+h.request('POST', '/addDocument')
+h.endheaders()
+
+for i in range(100):
+ h.send('{"date": "foobar"}')
+r = h.getresponse()
+print(r.read())
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/loadTest2.py
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/loadTest2.py?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/loadTest2.py (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/loadTest2.py Sun Mar 16 18:11:07 2014
@@ -0,0 +1,122 @@
+import time
+import threading
+import sys
+import json
+import asyncore
+import socket
+import random
+
+class RollingStats:
+
+ def __init__(self, count):
+ self.buffer = [0] * count
+ self.sum = 0
+ self.upto = 0
+
+ def add(self, value):
+ if value < 0:
+ raise RuntimeError('values should be positive')
+ idx = self.upto % len(self.buffer)
+ self.sum += value - self.buffer[idx]
+ self.buffer[idx] = value
+ self.upto += 1
+
+ def get(self):
+ if self.upto == 0:
+ return -1.0
+ else:
+ if self.upto < len(self.buffer):
+ v = float(self.sum)/self.upto
+ else:
+ v = float(self.sum)/len(self.buffer)
+ # Don't let roundoff error manifest as -0.0:
+ return max(0.0, v)
+
+class HTTPClient(asyncore.dispatcher):
+
+ def __init__(self, host, port, path, data, doneCallback):
+ self.startTime = time.time()
+ asyncore.dispatcher.__init__(self)
+ self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
+ l = ['POST %s HTTP/1.0' % path]
+ l.append('Content-Length: %d' % len(data))
+ self.buffer = '\r\n'.join(l) + '\r\n\r\n' + data
+ self.result = []
+ self.doneCallback = doneCallback
+ self.connect((host, port))
+
+ def handle_connect(self):
+ pass
+
+ def handle_close(self):
+ self.close()
+ self.doneCallback(time.time() - self.startTime)
+
+ def handle_read(self):
+ self.result.append(self.recv(8192))
+ print('read %s' % self.result[-1])
+
+ def writable(self):
+ return (len(self.buffer) > 0)
+
+ def handle_write(self):
+ sent = self.send(self.buffer)
+ self.buffer = self.buffer[sent:]
+
+class Stats:
+
+ def __init__(self):
+ self.actualQPSStats = RollingStats(5)
+ self.totalTimeStats = RollingStats(100)
+ self.lastIntSec = None
+ self.startTime = time.time()
+
+ def queryDone(self, t):
+ self.totalTimeStats.add(t)
+ intSec = int(time.time()-self.startTime)
+ if intSec != self.lastIntSec:
+ if self.lastIntSec is not None:
+ self.actualQPSStats.add(self.queriesThisSec)
+ self.queriesThisSec = 0
+ self.lastIntSec = intSec
+ self.queriesThisSec += 1
+
+def loop():
+ while True:
+ asyncore.loop()
+
+def main(targetQPS):
+
+ t = threading.Thread(target=loop, args=())
+ t.setDaemon(True)
+ t.start()
+
+ r = random.Random(0)
+
+ queryText = '1'
+ query = {'indexName': 'wiki',
+ 'queryText': queryText,
+ 'facets': [{'path': 'dateFacet', 'topN': 10}]}
+ data = json.dumps(query)
+
+ targetTime = time.time()
+
+ stats = Stats()
+ lastPrintTime = time.time()
+ while True:
+
+ targetTime += r.expovariate(targetQPS)
+ now = time.time()
+ if now - lastPrintTime > 1.0:
+ print('%.1f QPS, %.1f msec' % (stats.actualQPSStats.get(), 1000*stats.totalTimeStats.get()))
+ lastPrintTime = time.time()
+
+ pause = targetTime - time.time()
+ if pause > 0:
+ time.sleep(pause)
+
+ HTTPClient('10.17.4.91', 4001, '/search', data, stats.queryDone)
+
+
+if __name__ == '__main__':
+ main(int(sys.argv[1]))
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/post.py
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/post.py?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/post.py (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/scripts/post.py Sun Mar 16 18:11:07 2014
@@ -0,0 +1,6 @@
+import urllib2
+
+r = urllib2.urlopen('http://localhost:4000/updateDocument', 'here is some data')
+print r.read()
+
+
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin-hello.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin-hello.txt?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin-hello.txt (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin-hello.txt Sun Mar 16 18:11:07 2014
@@ -0,0 +1 @@
+hello world!
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin-lucene-server-plugin.properties
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin-lucene-server-plugin.properties?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin-lucene-server-plugin.properties (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin-lucene-server-plugin.properties Sun Mar 16 18:11:07 2014
@@ -0,0 +1,16 @@
+# 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.
+
+class: org.apache.lucene.server.MockPlugin
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/MockPlugin.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,63 @@
+package org.apache.lucene.server;
+
+/*
+ * 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.
+ */
+
+import org.apache.lucene.server.handlers.Handler;
+import org.apache.lucene.server.params.IntType;
+import org.apache.lucene.server.params.Param;
+import org.apache.lucene.server.params.Request;
+import org.apache.lucene.server.params.StructType;
+import org.apache.lucene.server.plugins.Plugin;
+import net.minidev.json.JSONObject;
+
+public class MockPlugin extends Plugin {
+
+ @Override
+ public String getTopDoc() {
+ return "Adds foobar param to AddDocument";
+ }
+
+ @Override
+ public String getName() {
+ return "Mock";
+ }
+
+ private static class AddDocumentPreHandler implements PreHandle {
+
+ @Override
+ public void invoke(Request r) {
+ Request r2 = r.getStruct("fields");
+ if (r2.hasParam("mockFoobar")) {
+ int x = r2.getInt("mockFoobar");
+ JSONObject params = r2.getRawParams();
+ params.put("intfield", 2*x);
+ }
+ }
+ }
+
+ public MockPlugin(GlobalState state) {
+ Handler addDocHandler = state.getHandler("addDocument");
+
+ // Register our pre-processor in addDocument:
+ addDocHandler.addPreHandle(new AddDocumentPreHandler());
+
+ StructType fieldsType = ((StructType) addDocHandler.getType().params.get("fields").type);
+
+ fieldsType.addParam(new Param("mockFoobar", "Testing adding a new silly param", new IntType()));
+ }
+}
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/ServerBaseTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/ServerBaseTestCase.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/ServerBaseTestCase.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/ServerBaseTestCase.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,572 @@
+package org.apache.lucene.server;
+
+/*
+ * 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.
+ */
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.TestUtil;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectWriter;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import net.minidev.json.JSONArray;
+import net.minidev.json.JSONObject;
+import net.minidev.json.JSONStyle;
+import net.minidev.json.JSONStyleIdent;
+import net.minidev.json.JSONStyleIdent;
+import net.minidev.json.JSONValue;
+import net.minidev.json.parser.JSONParser;
+import net.minidev.json.parser.ParseException;
+
+public abstract class ServerBaseTestCase extends LuceneTestCase {
+
+ private static Thread serverThread;
+ static int port;
+
+ /** Current index name; we auto-insert this to outgoing
+ * commands that need it. */
+
+ protected static String curIndexName = "index";
+ protected static boolean useDefaultIndex = true;
+
+ protected static File STATE_DIR;
+
+ /** Last result from the server; tests can access this to
+ * check results. */
+ protected static JSONObject lastResult;
+
+ /** We record the last indexGen we saw return from the
+ * server, and then insert that for search command if no
+ * searcher is already specified. This avoids a common
+ * test bug of forgetting to specify which indexGen to
+ * search. */
+ private static long lastIndexGen = -1;
+
+ @BeforeClass
+ public static void beforeClassServerBase() throws Exception {
+ File dir = TestUtil.getTempDir("ServerBase");
+ STATE_DIR = new File(dir, "state");
+ }
+
+ @AfterClass
+ public static void afterClassServerBase() throws Exception {
+ // who sets this? netty? what a piece of crap
+ System.clearProperty("sun.nio.ch.bugLevel");
+ STATE_DIR = null;
+ lastResult = null;
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ lastIndexGen = -1;
+ if (useDefaultIndex) {
+ curIndexName = "index";
+
+ // Some tests bounce the server, so we need to restart
+ // the default "index" index for those tests that expect
+ // it to be running:
+ send("startIndex");
+ }
+ }
+
+ protected long addDocument(String json) throws Exception {
+ JSONObject o = send("addDocument", json);
+ return ((Number) o.get("indexGen")).longValue();
+ }
+
+ protected static void installPlugin(File sourceFile) throws IOException {
+ ZipFile zipFile = new ZipFile(sourceFile);
+
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+
+ File pluginsDir = new File(STATE_DIR, "plugins");
+ if (!pluginsDir.exists()) {
+ pluginsDir.mkdirs();
+ }
+
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+
+ InputStream in = zipFile.getInputStream(entry);
+ File targetFile = new File(pluginsDir, entry.getName());
+ if (entry.isDirectory()) {
+ // allow unzipping with directory structure
+ targetFile.mkdirs();
+ } else {
+ if (targetFile.getParentFile()!=null) {
+ targetFile.getParentFile().mkdirs();
+ }
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(targetFile));
+
+ byte[] buffer = new byte[8192];
+ int len;
+ while((len = in.read(buffer)) >= 0) {
+ out.write(buffer, 0, len);
+ }
+
+ in.close();
+ out.close();
+ }
+ }
+
+ zipFile.close();
+ }
+
+ protected static void put(JSONObject o, String key, String value) throws ParseException {
+ o.put(key, JSONValue.parseWithException(value));
+ }
+
+ protected static void startServer() throws Exception {
+ final CountDownLatch ready = new CountDownLatch(1);
+ final Exception[] exc = new Exception[1];
+ final AtomicReference<Server> theServer = new AtomicReference<Server>();
+ serverThread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ Server s = new Server(STATE_DIR);
+ theServer.set(s);
+ s.run(0, 1, ready);
+ } catch (Exception e) {
+ exc[0] = e;
+ ready.countDown();
+ }
+ }
+ };
+ serverThread.start();
+ if (!ready.await(2, TimeUnit.SECONDS)) {
+ throw new IllegalStateException("server took more than 2 seconds to start");
+ }
+ if (exc[0] != null) {
+ throw exc[0];
+ }
+ ServerBaseTestCase.port = theServer.get().actualPort;
+ }
+
+ protected static void createAndStartIndex() throws Exception {
+ TestUtil.rmDir(new File(curIndexName));
+ send("createIndex", "{indexName: " + curIndexName + ", rootDir: " + curIndexName + "}");
+ // Wait at most 1 msec for a searcher to reopen; this
+ // value is too low for a production site but for
+ // testing we want to minimize sleep time:
+ send("liveSettings", "{indexName: " + curIndexName + ", minRefreshSec: 0.001}");
+ send("startIndex", "{indexName: " + curIndexName + "}");
+ }
+
+ protected static void shutdownServer() throws Exception {
+ send("shutdown");
+ if (serverThread != null) {
+ serverThread.join();
+ serverThread = null;
+ }
+ lastIndexGen = -1;
+ }
+
+ protected static void deleteAllDocs() throws Exception {
+ if (VERBOSE) {
+ System.out.println("TEST: deleteAllDocs");
+ }
+ send("deleteAllDocuments", "{indexName: " + curIndexName + "}");
+ }
+
+ protected static void commit() throws Exception {
+ send("commit", "{indexName: " + curIndexName + "}");
+ }
+
+ /** Send a no-args command, or a command taking just
+ * indexName which is automatically added (e.g., commit,
+ * closeIndex, startIndex). */
+ protected static JSONObject send(String command) throws Exception {
+ if (command.equals("startIndex")) {
+ // We do this so tests that index a doc and then need
+ // to search it, don't wait very long for the new
+ // searcher:
+ send("liveSettings", "{minRefreshSec: 0.001}");
+ }
+ return _send(command, "{}");
+ }
+
+ protected static JSONObject send(String command, String args) throws Exception {
+ if (args.equals("{}")) {
+ throw new IllegalArgumentException("don't pass empty args");
+ }
+ JSONObject o;
+ try {
+ o = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE & ~(JSONParser.ACCEPT_TAILLING_DATA)).parse(args);
+ } catch (ParseException pe) {
+ // NOTE: don't send pe as the cause; it adds lots of
+ // unhelpful noise because the message usually states
+ // what's wrong very well:
+ throw new IllegalArgumentException("test bug: failed to parse json args \"" + args + "\": " + pe.getMessage());
+ }
+ return send(command, o);
+ }
+
+ private static JSONObject _send(String command, String args) throws Exception {
+ JSONObject o;
+ try {
+ o = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE & ~(JSONParser.ACCEPT_TAILLING_DATA)).parse(args);
+ } catch (ParseException pe) {
+ // NOTE: don't send pe as the cause; it adds lots of
+ // unhelpful noise because the message usually states
+ // what's wrong very well:
+ throw new IllegalArgumentException("test bug: failed to parse json args \"" + args + "\": " + pe.getMessage());
+ }
+ return send(command, o);
+ }
+
+ private static boolean requiresIndexName(String command) {
+ if (command.equals("shutdown")) {
+ return false;
+ }
+ return true;
+ }
+
+ protected static JSONObject send(String command, JSONObject args) throws Exception {
+ // Auto-insert indexName:
+ if (curIndexName != null && requiresIndexName(command) && args.get("indexName") == null) {
+ if (VERBOSE) {
+ System.out.println("NOTE: ServerBaseTestCase: now add current indexName: " + curIndexName);
+ }
+ args.put("indexName", curIndexName);
+ }
+
+ if (command.equals("search") && args.containsKey("searcher") == false && lastIndexGen != -1) {
+ if (VERBOSE) {
+ System.out.println("\nNOTE: ServerBaseTestCase: inserting 'searcher: {indexGen: " + lastIndexGen + "}' into search request");
+ }
+ JSONObject o = new JSONObject();
+ o.put("indexGen", lastIndexGen);
+ args.put("searcher", o);
+ }
+
+ if (VERBOSE) {
+ System.out.println("\nNOTE: ServerBaseTestCase: sendRaw command=" + command + " args:\n" + args.toJSONString(new JSONStyleIdent()));
+ }
+
+ lastResult = sendRaw(command, args.toJSONString(JSONStyle.NO_COMPRESS));
+
+ if (VERBOSE) {
+ System.out.println("NOTE: ServerBaseTestCase: server response:\n" + lastResult.toJSONString(new JSONStyleIdent()));
+ }
+
+ if (lastResult.containsKey("indexGen")) {
+ lastIndexGen = getLong(lastResult, "indexGen");
+ if (VERBOSE) {
+ System.out.println("NOTE: ServerBaseTestCase: record lastIndexGen=" + lastIndexGen);
+ }
+ }
+
+ return lastResult;
+ }
+
+ protected static JSONObject sendRaw(String command, String body) throws Exception {
+ byte[] bytes = body.getBytes("UTF-8");
+ HttpURLConnection c = (HttpURLConnection) new URL("http://localhost:" + port + "/" + command).openConnection();
+ c.setUseCaches(false);
+ c.setDoOutput(true);
+ c.setRequestMethod("POST");
+ c.setRequestProperty("Content-Length", ""+bytes.length);
+ c.setRequestProperty("Charset", "UTF-8");
+ try {
+ c.getOutputStream().write(bytes);
+ } catch (ConnectException ce) {
+ System.out.println("FAILED port=" + port + ":");
+ ce.printStackTrace(System.out);
+ throw ce;
+ }
+ // c.connect()
+ int code = c.getResponseCode();
+ int size = c.getContentLength();
+ bytes = new byte[size];
+ if (code == 200) {
+ InputStream is = c.getInputStream();
+ is.read(bytes);
+ c.disconnect();
+ return (JSONObject) JSONValue.parseStrict(new String(bytes, "UTF-8"));
+ } else {
+ InputStream is = c.getErrorStream();
+ is.read(bytes);
+ c.disconnect();
+ throw new IOException("Server error:\n" + new String(bytes, "UTF-8"));
+ }
+ }
+
+ protected static void copyFile(File source, File dest) throws IOException {
+ InputStream is = null;
+ OutputStream os = null;
+ try {
+ is = new FileInputStream(source);
+ os = new FileOutputStream(dest);
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = is.read(buffer)) > 0) {
+ os.write(buffer, 0, length);
+ }
+ } finally {
+ is.close();
+ os.close();
+ }
+ }
+
+ protected String prettyPrint(JSONObject o) throws Exception {
+ return o.toJSONString(new JSONStyleIdent());
+ }
+
+ protected static String httpLoad(String path) throws Exception {
+ HttpURLConnection c = (HttpURLConnection) new URL("http://localhost:" + port + "/" + path).openConnection();
+ c.setUseCaches(false);
+ c.setDoOutput(true);
+ c.setRequestMethod("GET");
+ // c.connect()
+ int code = c.getResponseCode();
+ int size = c.getContentLength();
+ byte[] bytes = new byte[size];
+ if (code == 200) {
+ InputStream is = c.getInputStream();
+ is.read(bytes);
+ c.disconnect();
+ return new String(bytes, "UTF-8");
+ } else {
+ InputStream is = c.getErrorStream();
+ is.read(bytes);
+ c.disconnect();
+ throw new IOException("Server error:\n" + new String(bytes, "UTF-8"));
+ }
+ }
+
+ protected static JSONObject sendChunked(String body, String request) throws Exception {
+ HttpURLConnection c = (HttpURLConnection) new URL("http://localhost:" + port + "/" + request).openConnection();
+ c.setUseCaches(false);
+ c.setDoOutput(true);
+ c.setChunkedStreamingMode(256);
+ c.setRequestMethod("POST");
+ c.setRequestProperty("Charset", "UTF-8");
+ byte[] bytes = body.getBytes("UTF-8");
+ c.getOutputStream().write(bytes);
+ // c.connect()
+ int code = c.getResponseCode();
+ int size = c.getContentLength();
+ if (code == 200) {
+ InputStream is = c.getInputStream();
+ bytes = new byte[size];
+ is.read(bytes);
+ c.disconnect();
+ return (JSONObject) JSONValue.parseStrict(new String(bytes, "UTF-8"));
+ } else {
+ InputStream is = c.getErrorStream();
+ is.read(bytes);
+ c.disconnect();
+ throw new IOException("Server error:\n" + new String(bytes, "UTF-8"));
+ }
+ }
+
+ /** Simple xpath-like utility method to jump down and grab
+ * something out of the JSON response. */
+ protected static Object get(Object o, String path) {
+ int upto = 0;
+ int tokStart = 0;
+ boolean inArrayIndex = false;
+ while(upto < path.length()) {
+ char ch = path.charAt(upto++);
+ if (inArrayIndex) {
+ if (ch == ']') {
+ int index = Integer.parseInt(path.substring(tokStart, upto-1));
+ o = ((JSONArray) o).get(index);
+ inArrayIndex = false;
+ tokStart = upto;
+ }
+ } else if (ch == '.' || ch == '[') {
+ String name = path.substring(tokStart, upto-1);
+ if (name.length() != 0) {
+ o = ((JSONObject) o).get(name);
+ if (o == null) {
+ // Likely a test bug: try to help out:
+ throw new IllegalArgumentException("path " + path.substring(0, tokStart-1) + " does not have member ." + name);
+ }
+ }
+ tokStart = upto;
+ if (ch == '[') {
+ inArrayIndex = true;
+ }
+ }
+ }
+
+ String name = path.substring(tokStart, upto);
+ if (name.length() > 0) {
+ if (o instanceof JSONArray && name.equals("length")) {
+ o = new Integer(((JSONArray) o).size());
+ } else {
+ o = ((JSONObject) o).get(name);
+ if (o == null) {
+ // Likely a test bug: try to help out:
+ throw new IllegalArgumentException("path " + path.substring(0, tokStart) + " does not have member ." + name);
+ }
+ }
+ }
+ return o;
+ }
+
+ protected boolean hasParam(Object o, String path) {
+ try {
+ get(o, path);
+ return true;
+ } catch (IllegalArgumentException iae) {
+ return false;
+ }
+ }
+
+ protected boolean hasParam(String path) {
+ return hasParam(lastResult, path);
+ }
+
+ protected static String getString(Object o, String path) {
+ return (String) get(o, path);
+ }
+
+ protected static String getString(String path) {
+ return getString(lastResult, path);
+ }
+
+ protected static int getInt(Object o, String path) {
+ return ((Number) get(o, path)).intValue();
+ }
+
+ protected static int getInt(String path) {
+ return getInt(lastResult, path);
+ }
+
+ protected static boolean getBoolean(Object o, String path) {
+ return ((Boolean) get(o, path)).booleanValue();
+ }
+
+ protected static boolean getBoolean(String path) {
+ return getBoolean(lastResult, path);
+ }
+
+ protected static long getLong(Object o, String path) {
+ return ((Number) get(o, path)).longValue();
+ }
+
+ protected static long getLong(String path) {
+ return getLong(lastResult, path);
+ }
+
+ protected static float getFloat(Object o, String path) {
+ return ((Number) get(o, path)).floatValue();
+ }
+
+ protected static float getFloat(String path) {
+ return getFloat(lastResult, path);
+ }
+
+ protected static JSONObject getObject(Object o, String path) {
+ return (JSONObject) get(o, path);
+ }
+
+ protected static JSONObject getObject(String path) {
+ return getObject(lastResult, path);
+ }
+
+ protected static JSONArray getArray(Object o, String path) {
+ return (JSONArray) get(o, path);
+ }
+
+ protected static JSONArray getArray(String path) {
+ return getArray(lastResult, path);
+ }
+
+ protected static JSONArray getArray(JSONArray o, int index) {
+ return (JSONArray) o.get(index);
+ }
+
+ /** Renders one hilited field (multiple passages) value
+ * with <b>...</b> tags, and ... separating the passages. */
+ protected String renderHighlight(JSONArray hit) {
+ StringBuilder sb = new StringBuilder();
+ for(Object o : hit) {
+ if (sb.length() != 0) {
+ sb.append("...");
+ }
+ sb.append(renderSingleHighlight(getArray(o, "parts")));
+ }
+
+ return sb.toString();
+ }
+
+ /** Renders a single passage with <b>...</b> tags. */
+ protected String renderSingleHighlight(JSONArray passage) {
+ StringBuilder sb = new StringBuilder();
+ for(Object o2 : passage) {
+ if (o2 instanceof String) {
+ sb.append((String) o2);
+ } else {
+ JSONObject obj = (JSONObject) o2;
+ sb.append("<b>");
+ sb.append(obj.get("text"));
+ sb.append("</b>");
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /** Sends the command + args, expecting a failure such
+ * that all fragments occur in the failure message
+ * string. Use this to verify a failure case is hitting
+ * the right error messages back to the user. */
+ protected void assertFailsWith(String command, JSONObject args, String... fragments) throws Exception {
+ assertFailsWith(command, args.toString(), fragments);
+ }
+
+ /** Sends the command + args, expecting a failure such
+ * that all fragments occur in the failure message
+ * string. Use this to verify a failure case is hitting
+ * the right error messages back to the user. */
+ protected void assertFailsWith(String command, String args, String... fragments) throws Exception {
+ try {
+ send(command, args);
+ fail("did not hit expected exception");
+ } catch (IOException ioe) {
+ for(String fragment : fragments) {
+ if (ioe.getMessage().contains(fragment) == false) {
+ fail("expected: " + fragment + "\nactual: \"" + ioe.getMessage());
+ }
+ }
+ }
+ }
+}
+
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/TermFreqPayload.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/TermFreqPayload.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/TermFreqPayload.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/TermFreqPayload.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,36 @@
+package org.apache.lucene.server;
+
+/*
+ * 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.
+ */
+
+import org.apache.lucene.util.BytesRef;
+
+public final class TermFreqPayload {
+ public final BytesRef term;
+ public final long v;
+ public final BytesRef payload;
+
+ public TermFreqPayload(String term, long v, BytesRef payload) {
+ this(new BytesRef(term), v, payload);
+ }
+
+ public TermFreqPayload(BytesRef term, long v, BytesRef payload) {
+ this.term = term;
+ this.v = v;
+ this.payload = payload;
+ }
+}
\ No newline at end of file
Added: lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/TestAddDocuments.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/TestAddDocuments.java?rev=1578133&view=auto
==============================================================================
--- lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/TestAddDocuments.java (added)
+++ lucene/dev/branches/lucene5376_2/lucene/server/src/test/org/apache/lucene/server/TestAddDocuments.java Sun Mar 16 18:11:07 2014
@@ -0,0 +1,123 @@
+package org.apache.lucene.server;
+
+/*
+ * 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.
+ */
+
+import java.util.Locale;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import net.minidev.json.JSONArray;
+import net.minidev.json.JSONObject;
+
+public class TestAddDocuments extends ServerBaseTestCase {
+
+ @BeforeClass
+ public static void initClass() throws Exception {
+ useDefaultIndex = true;
+ curIndexName = "index";
+ startServer();
+ createAndStartIndex();
+ registerFields();
+ //commit();
+ }
+
+ @AfterClass
+ public static void fini() throws Exception {
+ shutdownServer();
+ }
+
+ private static void registerFields() throws Exception {
+ send("registerFields", "{fields: {docType: {type: atom}, name: {type: atom}, country: {type: atom}, skill: {type: atom}}}");
+ }
+
+ private JSONObject getResume(String name, String country) {
+ JSONObject o = new JSONObject();
+ o.put("docType", "resume");
+ o.put("name", name);
+ o.put("country", country);
+ JSONObject o2 = new JSONObject();
+ o2.put("fields", o);
+ return o2;
+ }
+
+ private JSONObject getJob(String skill, int year) {
+ JSONObject o = new JSONObject();
+ o.put("skill", skill);
+ //o.put("year", year);
+ JSONObject o2 = new JSONObject();
+ o2.put("fields", o);
+ return o2;
+ }
+
+ public void testAddDocuments() throws Exception {
+ deleteAllDocs();
+
+ JSONObject o = new JSONObject();
+ o.put("indexName", "index");
+ o.put("parent", getResume("Lisa", "United Kingdom"));
+ JSONArray arr = new JSONArray();
+ o.put("children", arr);
+ arr.add(getJob("java", 2007));
+ arr.add(getJob("python", 2010));
+ JSONObject result = send("addDocuments", o);
+ long indexGen = ((Number) result.get("indexGen")).longValue();
+
+ // search on parent:
+ result = send("search", String.format(Locale.ROOT, "{queryText: 'name:Lisa', searcher: {indexGen: %d}}", indexGen));
+ assertEquals(1, result.get("totalHits"));
+
+ // search on child:
+ result = send("search", String.format(Locale.ROOT, "{queryText: 'skill:python', searcher: {indexGen: %d}}", indexGen));
+ assertEquals(1, result.get("totalHits"));
+ }
+
+ public void testBulkAddDocuments() throws Exception {
+ deleteAllDocs();
+ StringBuilder sb = new StringBuilder();
+ sb.append("{\"indexName\": \"index\", \"documents\": [");
+ for(int i=0;i<100;i++) {
+ JSONObject o = new JSONObject();
+ o.put("parent", getResume("Lisa", "United Kingdom"));
+ JSONArray arr = new JSONArray();
+ o.put("children", arr);
+ arr.add(getJob("java", 2007));
+ arr.add(getJob("python", 2010));
+ if (i > 0) {
+ sb.append(',');
+ }
+ sb.append(o.toString());
+ }
+ sb.append("]}");
+
+ String s = sb.toString();
+
+ JSONObject result = sendChunked(s, "bulkAddDocuments");
+ assertEquals(100, result.get("indexedDocumentBlockCount"));
+ long indexGen = ((Number) result.get("indexGen")).longValue();
+
+ // search on parent:
+ result = send("search", String.format(Locale.ROOT, "{queryText: 'name:Lisa', searcher: {indexGen: %d}}", indexGen));
+ assertEquals(100, result.get("totalHits"));
+
+ // search on child:
+ result = send("search", String.format(Locale.ROOT, "{queryText: 'skill:python', searcher: {indexGen: %d}}", indexGen));
+ assertEquals(100, result.get("totalHits"));
+ }
+
+ // TODO: test block join/grouping once they are impl'd!
+}