You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ranger.apache.org by bo...@apache.org on 2015/03/18 00:33:31 UTC
[09/17] incubator-ranger git commit: Support for Solr as Audit
Destination.
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/util/ClientUtils.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/util/ClientUtils.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/util/ClientUtils.java
new file mode 100644
index 0000000..f2e4036
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/util/ClientUtils.java
@@ -0,0 +1,251 @@
+/*
+ * 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.client.solrj.util;
+
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.SolrInputField;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.Base64;
+import org.apache.solr.common.util.ContentStream;
+import org.apache.solr.common.util.ContentStreamBase;
+import org.apache.solr.common.util.DateUtil;
+import org.apache.solr.common.util.XML;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.net.URLEncoder;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+
+/**
+ *
+ * @since solr 1.3
+ */
+public class ClientUtils
+{
+ // Standard Content types
+ public static final String TEXT_XML = "application/xml; charset=UTF-8";
+
+ /**
+ * Take a string and make it an iterable ContentStream
+ */
+ public static Collection<ContentStream> toContentStreams( final String str, final String contentType )
+ {
+ if( str == null )
+ return null;
+
+ ArrayList<ContentStream> streams = new ArrayList<>( 1 );
+ ContentStreamBase ccc = new ContentStreamBase.StringStream( str );
+ ccc.setContentType( contentType );
+ streams.add( ccc );
+ return streams;
+ }
+
+ /**
+ * @param d SolrDocument to convert
+ * @return a SolrInputDocument with the same fields and values as the
+ * SolrDocument. All boosts are 1.0f
+ */
+ public static SolrInputDocument toSolrInputDocument( SolrDocument d )
+ {
+ SolrInputDocument doc = new SolrInputDocument();
+ for( String name : d.getFieldNames() ) {
+ doc.addField( name, d.getFieldValue(name), 1.0f );
+ }
+ return doc;
+ }
+
+ /**
+ * @param d SolrInputDocument to convert
+ * @return a SolrDocument with the same fields and values as the SolrInputDocument
+ */
+ public static SolrDocument toSolrDocument(SolrInputDocument d) {
+ SolrDocument doc = new SolrDocument();
+ for (SolrInputField field : d) {
+ doc.setField(field.getName(), field.getValue());
+ }
+ if (d.getChildDocuments() != null) {
+ for (SolrInputDocument in : d.getChildDocuments()) {
+ doc.addChildDocument(toSolrDocument(in));
+ }
+
+ }
+ return doc;
+ }
+
+ //------------------------------------------------------------------------
+ //------------------------------------------------------------------------
+
+ public static void writeXML( SolrInputDocument doc, Writer writer ) throws IOException
+ {
+ writer.write("<doc boost=\""+doc.getDocumentBoost()+"\">");
+
+ for( SolrInputField field : doc ) {
+ float boost = field.getBoost();
+ String name = field.getName();
+
+ for( Object v : field ) {
+ String update = null;
+
+ if (v instanceof Map) {
+ // currently only supports a single value
+ for (Entry<Object,Object> entry : ((Map<Object,Object>)v).entrySet()) {
+ update = entry.getKey().toString();
+ v = entry.getValue();
+ if (v instanceof Collection) {
+ Collection values = (Collection) v;
+ for (Object value : values) {
+ writeVal(writer, boost, name, value, update);
+ boost = 1.0f;
+ }
+ } else {
+ writeVal(writer, boost, name, v, update);
+ boost = 1.0f;
+ }
+ }
+ } else {
+ writeVal(writer, boost, name, v, update);
+ // only write the boost for the first multi-valued field
+ // otherwise, the used boost is the product of all the boost values
+ boost = 1.0f;
+ }
+ }
+ }
+
+ if (doc.hasChildDocuments()) {
+ for (SolrInputDocument childDocument : doc.getChildDocuments()) {
+ writeXML(childDocument, writer);
+ }
+ }
+
+ writer.write("</doc>");
+ }
+
+ private static void writeVal(Writer writer, float boost, String name, Object v, String update) throws IOException {
+ if (v instanceof Date) {
+ v = DateUtil.getThreadLocalDateFormat().format( (Date)v );
+ } else if (v instanceof byte[]) {
+ byte[] bytes = (byte[]) v;
+ v = Base64.byteArrayToBase64(bytes, 0, bytes.length);
+ } else if (v instanceof ByteBuffer) {
+ ByteBuffer bytes = (ByteBuffer) v;
+ v = Base64.byteArrayToBase64(bytes.array(), bytes.position(),bytes.limit() - bytes.position());
+ }
+
+ if (update == null) {
+ if( boost != 1.0f ) {
+ XML.writeXML(writer, "field", v.toString(), "name", name, "boost", boost);
+ } else if (v != null) {
+ XML.writeXML(writer, "field", v.toString(), "name", name );
+ }
+ } else {
+ if( boost != 1.0f ) {
+ XML.writeXML(writer, "field", v.toString(), "name", name, "boost", boost, "update", update);
+ } else {
+ if (v == null) {
+ XML.writeXML(writer, "field", null, "name", name, "update", update, "null", true);
+ } else {
+ XML.writeXML(writer, "field", v.toString(), "name", name, "update", update);
+ }
+ }
+ }
+ }
+
+
+ public static String toXML( SolrInputDocument doc )
+ {
+ StringWriter str = new StringWriter();
+ try {
+ writeXML( doc, str );
+ }
+ catch( Exception ex ){}
+ return str.toString();
+ }
+
+ //---------------------------------------------------------------------------------------
+
+ /**
+ * See: <a href="https://www.google.com/?gws_rd=ssl#q=lucene+query+parser+syntax">Lucene query parser syntax</a>
+ * for more information on Escaping Special Characters
+ */
+ // NOTE: its broken to link to any lucene-queryparser.jar docs, not in classpath!!!!!
+ public static String escapeQueryChars(String s) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ // These characters are part of the query syntax and must be escaped
+ if (c == '\\' || c == '+' || c == '-' || c == '!' || c == '(' || c == ')' || c == ':'
+ || c == '^' || c == '[' || c == ']' || c == '\"' || c == '{' || c == '}' || c == '~'
+ || c == '*' || c == '?' || c == '|' || c == '&' || c == ';' || c == '/'
+ || Character.isWhitespace(c)) {
+ sb.append('\\');
+ }
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ public static String toQueryString( SolrParams params, boolean xml ) {
+ StringBuilder sb = new StringBuilder(128);
+ try {
+ String amp = xml ? "&" : "&";
+ boolean first=true;
+ Iterator<String> names = params.getParameterNamesIterator();
+ while( names.hasNext() ) {
+ String key = names.next();
+ String[] valarr = params.getParams( key );
+ if( valarr == null ) {
+ sb.append( first?"?":amp );
+ sb.append(key);
+ first=false;
+ }
+ else {
+ for (String val : valarr) {
+ sb.append( first? "?":amp );
+ sb.append(key);
+ if( val != null ) {
+ sb.append('=');
+ sb.append( URLEncoder.encode( val, "UTF-8" ) );
+ }
+ first=false;
+ }
+ }
+ }
+ }
+ catch (IOException e) {throw new RuntimeException(e);} // can't happen
+ return sb.toString();
+ }
+
+ /** Constructs a slices map from a collection of slices and handles disambiguation if multiple collections are being queried simultaneously */
+ public static void addSlices(Map<String,Slice> target, String collectionName, Collection<Slice> slices, boolean multiCollection) {
+ for (Slice slice : slices) {
+ String key = slice.getName();
+ if (multiCollection) key = collectionName + "_" + key;
+ target.put(key, slice);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/util/package-info.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/util/package-info.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/util/package-info.java
new file mode 100644
index 0000000..9464970
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/util/package-info.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Utilities for Solr client applications.
+ */
+package org.apache.solr.client.solrj.util;
+
+
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/EnumFieldValue.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/EnumFieldValue.java b/ranger_solrj/src/main/java/org/apache/solr/common/EnumFieldValue.java
new file mode 100644
index 0000000..50d1fb0
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/EnumFieldValue.java
@@ -0,0 +1,116 @@
+package org.apache.solr.common;
+
+/*
+ * 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.Serializable;
+
+/**
+ * Represents a Enum field value, which includes integer value (indicating the sort order) and string (displayed) value.
+ * Note: this class has a natural ordering that is inconsistent with equals
+ */
+
+public final class EnumFieldValue implements Serializable, Comparable<EnumFieldValue> {
+ private final Integer intValue;
+ private final String stringValue;
+
+ @Override
+ public int hashCode() {
+ int result = intValue != null ? intValue.hashCode() : 0;
+ result = 31 * result + (stringValue != null ? stringValue.hashCode() : 0);
+ return result;
+ }
+
+ public EnumFieldValue(Integer intValue, String stringValue) {
+ this.intValue = intValue;
+ this.stringValue = stringValue;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null)
+ return false;
+ if (!(obj instanceof EnumFieldValue))
+ return false;
+
+ EnumFieldValue otherEnumFieldValue = (EnumFieldValue) obj;
+ return equalsIntegers(intValue, otherEnumFieldValue.intValue) && equalStrings(stringValue, otherEnumFieldValue.stringValue);
+ }
+
+ /**
+ * @return string (displayed) value
+ */
+ @Override
+ public String toString() {
+ return stringValue;
+ }
+
+ /**
+ * @return integer value (indicating the sort order)
+ */
+ public Integer toInt() {
+ return intValue;
+ }
+
+ @Override
+ public int compareTo(EnumFieldValue o) {
+ if (o == null)
+ return 1;
+ return compareIntegers(intValue, o.intValue);
+ }
+
+ private boolean equalStrings(String str1, String str2) {
+ if ((str1 == null) && (str2 == null))
+ return true;
+
+ if (str1 == null)
+ return false;
+
+ if (str2 == null)
+ return false;
+
+ return str1.equals(str2);
+ }
+
+ private boolean equalsIntegers(Integer int1, Integer int2) {
+ if ((int1 == null) && (int2 == null))
+ return true;
+
+ if (int1 == null)
+ return false;
+
+ if (int2 == null)
+ return false;
+
+ return int1.equals(int2);
+ }
+
+ private int compareIntegers(Integer int1, Integer int2) {
+ if ((int1 == null) && (int2 == null))
+ return 0;
+
+ if (int1 == null)
+ return -1;
+
+ if (int2 == null)
+ return 1;
+
+ return int1.compareTo(int2);
+ }
+}
+
+
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/SolrDocument.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/SolrDocument.java b/ranger_solrj/src/main/java/org/apache/solr/common/SolrDocument.java
new file mode 100644
index 0000000..b7e4465
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/SolrDocument.java
@@ -0,0 +1,396 @@
+/*
+ * 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.common;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.common.util.NamedList;
+
+
+/**
+ * A concrete representation of a document within a Solr index. Unlike a lucene
+ * Document, a SolrDocument may have an Object value matching the type defined in
+ * schema.xml
+ *
+ * For indexing documents, use the SolrInputDocument that contains extra information
+ * for document and field boosting.
+ *
+ *
+ * @since solr 1.3
+ */
+public class SolrDocument implements Map<String,Object>, Iterable<Map.Entry<String, Object>>, Serializable
+{
+ private final Map<String,Object> _fields;
+
+ private List<SolrDocument> _childDocuments;
+
+ public SolrDocument()
+ {
+ _fields = new LinkedHashMap<>();
+ }
+
+ /**
+ * @return a list of field names defined in this document - this Collection is directly backed by this SolrDocument.
+ * @see #keySet
+ */
+ public Collection<String> getFieldNames() {
+ return this.keySet();
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // Add / Set / Remove Fields
+ ///////////////////////////////////////////////////////////////////
+
+ /**
+ * Remove all fields from the document
+ */
+ @Override
+ public void clear()
+ {
+ _fields.clear();
+
+ if(_childDocuments != null) {
+ _childDocuments.clear();
+ }
+ }
+
+ /**
+ * Remove all fields with the name
+ */
+ public boolean removeFields(String name)
+ {
+ return this.remove( name ) != null;
+ }
+
+ /**
+ * Set a field with the given object. If the object is an Array, it will
+ * set multiple fields with the included contents. This will replace any existing
+ * field with the given name
+ */
+ @SuppressWarnings("unchecked")
+ public void setField(String name, Object value)
+ {
+ if( value instanceof Object[] ) {
+ value = new ArrayList(Arrays.asList( (Object[])value ));
+ }
+ else if( value instanceof Collection ) {
+ // nothing
+ }
+ else if( value instanceof NamedList ) {
+ // nothing
+ }
+ else if( value instanceof Iterable ) {
+ ArrayList<Object> lst = new ArrayList<>();
+ for( Object o : (Iterable)value ) {
+ lst.add( o );
+ }
+ value = lst;
+ }
+ _fields.put(name, value);
+ }
+
+ /**
+ * This will add a field to the document. If fields already exist with this
+ * name it will append value to the collection. If the value is Collection,
+ * each value will be added independently.
+ *
+ * The class type of value and the name parameter should match schema.xml.
+ * schema.xml can be found in conf directory under the solr home by default.
+ *
+ * @param name Name of the field, should match one of the field names defined under "fields" tag in schema.xml.
+ * @param value Value of the field, should be of same class type as defined by "type" attribute of the corresponding field in schema.xml.
+ */
+ @SuppressWarnings("unchecked")
+ public void addField(String name, Object value)
+ {
+ Object existing = _fields.get(name);
+ if (existing == null) {
+ if( value instanceof Collection ) {
+ Collection<Object> c = new ArrayList<>( 3 );
+ for ( Object o : (Collection<Object>)value ) {
+ c.add(o);
+ }
+ this.setField( name, c );
+ } else {
+ this.setField( name, value );
+ }
+ return;
+ }
+
+ Collection<Object> vals = null;
+ if( existing instanceof Collection ) {
+ vals = (Collection<Object>)existing;
+ }
+ else {
+ vals = new ArrayList<>( 3 );
+ vals.add( existing );
+ }
+
+ // Add the values to the collection
+ if( value instanceof Iterable ) {
+ for( Object o : (Iterable<Object>)value ) {
+ vals.add( o );
+ }
+ }
+ else if( value instanceof Object[] ) {
+ for( Object o : (Object[])value ) {
+ vals.add( o );
+ }
+ }
+ else {
+ vals.add( value );
+ }
+ _fields.put( name, vals );
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // Get the field values
+ ///////////////////////////////////////////////////////////////////
+
+ /**
+ * returns the first value for a field
+ */
+ public Object getFirstValue(String name) {
+ Object v = _fields.get( name );
+ if (v == null || !(v instanceof Collection)) return v;
+ Collection c = (Collection)v;
+ if (c.size() > 0 ) {
+ return c.iterator().next();
+ }
+ return null;
+ }
+
+ /**
+ * Get the value or collection of values for a given field.
+ */
+ public Object getFieldValue(String name) {
+ return _fields.get( name );
+ }
+
+ /**
+ * Get a collection of values for a given field name
+ */
+ @SuppressWarnings("unchecked")
+ public Collection<Object> getFieldValues(String name) {
+ Object v = _fields.get( name );
+ if( v instanceof Collection ) {
+ return (Collection<Object>)v;
+ }
+ if( v != null ) {
+ ArrayList<Object> arr = new ArrayList<>(1);
+ arr.add( v );
+ return arr;
+ }
+ return null;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "SolrDocument"+_fields;
+ }
+
+ /**
+ * Iterate of String->Object keys
+ */
+ @Override
+ public Iterator<Entry<String, Object>> iterator() {
+ return _fields.entrySet().iterator();
+ }
+
+ //-----------------------------------------------------------------------------------------
+ // JSTL Helpers
+ //-----------------------------------------------------------------------------------------
+
+ /**
+ * Expose a Map interface to the solr field value collection.
+ */
+ public Map<String,Collection<Object>> getFieldValuesMap()
+ {
+ return new Map<String,Collection<Object>>() {
+ /** Get the field Value */
+ @Override
+ public Collection<Object> get(Object key) {
+ return getFieldValues( (String)key );
+ }
+
+ // Easily Supported methods
+ @Override
+ public boolean containsKey(Object key) { return _fields.containsKey( key ); }
+ @Override
+ public Set<String> keySet() { return _fields.keySet(); }
+ @Override
+ public int size() { return _fields.size(); }
+ @Override
+ public boolean isEmpty() { return _fields.isEmpty(); }
+
+ // Unsupported operations. These are not necessary for JSTL
+ @Override
+ public void clear() { throw new UnsupportedOperationException(); }
+ @Override
+ public boolean containsValue(Object value) {throw new UnsupportedOperationException();}
+ @Override
+ public Set<java.util.Map.Entry<String, Collection<Object>>> entrySet() {throw new UnsupportedOperationException();}
+ @Override
+ public void putAll(Map<? extends String, ? extends Collection<Object>> t) {throw new UnsupportedOperationException();}
+ @Override
+ public Collection<Collection<Object>> values() {throw new UnsupportedOperationException();}
+ @Override
+ public Collection<Object> put(String key, Collection<Object> value) {throw new UnsupportedOperationException();}
+ @Override
+ public Collection<Object> remove(Object key) {throw new UnsupportedOperationException();}
+ @Override
+ public String toString() {return _fields.toString();}
+ };
+ }
+
+ /**
+ * Expose a Map interface to the solr fields. This function is useful for JSTL
+ */
+ public Map<String,Object> getFieldValueMap() {
+ return new Map<String,Object>() {
+ /** Get the field Value */
+ @Override
+ public Object get(Object key) {
+ return getFirstValue( (String)key );
+ }
+
+ // Easily Supported methods
+ @Override
+ public boolean containsKey(Object key) { return _fields.containsKey( key ); }
+ @Override
+ public Set<String> keySet() { return _fields.keySet(); }
+ @Override
+ public int size() { return _fields.size(); }
+ @Override
+ public boolean isEmpty() { return _fields.isEmpty(); }
+
+ // Unsupported operations. These are not necessary for JSTL
+ @Override
+ public void clear() { throw new UnsupportedOperationException(); }
+ @Override
+ public boolean containsValue(Object value) {throw new UnsupportedOperationException();}
+ @Override
+ public Set<java.util.Map.Entry<String, Object>> entrySet() {throw new UnsupportedOperationException();}
+ @Override
+ public void putAll(Map<? extends String, ? extends Object> t) {throw new UnsupportedOperationException();}
+ @Override
+ public Collection<Object> values() {throw new UnsupportedOperationException();}
+ @Override
+ public Collection<Object> put(String key, Object value) {throw new UnsupportedOperationException();}
+ @Override
+ public Collection<Object> remove(Object key) {throw new UnsupportedOperationException();}
+ @Override
+ public String toString() {return _fields.toString();}
+ };
+ }
+
+ //---------------------------------------------------
+ // MAP interface
+ //---------------------------------------------------
+
+ @Override
+ public boolean containsKey(Object key) {
+ return _fields.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return _fields.containsValue(value);
+ }
+
+ @Override
+ public Set<Entry<String, Object>> entrySet() {
+ return _fields.entrySet();
+ }
+ //TODO: Shouldn't the input parameter here be a String? The _fields map requires a String.
+ @Override
+ public Object get(Object key) {
+ return _fields.get(key);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return _fields.isEmpty();
+ }
+
+ @Override
+ public Set<String> keySet() {
+ return _fields.keySet();
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ return _fields.put(key, value);
+ }
+
+ @Override
+ public void putAll(Map<? extends String, ? extends Object> t) {
+ _fields.putAll( t );
+ }
+
+ @Override
+ public Object remove(Object key) {
+ return _fields.remove(key);
+ }
+
+ @Override
+ public int size() {
+ return _fields.size();
+ }
+
+ @Override
+ public Collection<Object> values() {
+ return _fields.values();
+ }
+
+ public void addChildDocument(SolrDocument child) {
+ if (_childDocuments == null) {
+ _childDocuments = new ArrayList<>();
+ }
+ _childDocuments.add(child);
+ }
+
+ public void addChildDocuments(Collection<SolrDocument> childs) {
+ for (SolrDocument child : childs) {
+ addChildDocument(child);
+ }
+ }
+
+ /** Returns the list of child documents, or null if none. */
+ public List<SolrDocument> getChildDocuments() {
+ return _childDocuments;
+ }
+
+ public boolean hasChildDocuments() {
+ boolean isEmpty = (_childDocuments == null || _childDocuments.isEmpty());
+ return !isEmpty;
+ }
+
+ public int getChildDocumentCount() {
+ return _childDocuments.size();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/SolrDocumentList.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/SolrDocumentList.java b/ranger_solrj/src/main/java/org/apache/solr/common/SolrDocumentList.java
new file mode 100644
index 0000000..d803e7d
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/SolrDocumentList.java
@@ -0,0 +1,68 @@
+/*
+ * 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.common;
+
+import java.util.ArrayList;
+
+
+/**
+ * Represent a list of SolrDocuments returned from a search. This includes
+ * position and offset information.
+ *
+ *
+ * @since solr 1.3
+ */
+public class SolrDocumentList extends ArrayList<SolrDocument>
+{
+ private long numFound = 0;
+ private long start = 0;
+ private Float maxScore = null;
+
+ public Float getMaxScore() {
+ return maxScore;
+ }
+
+ public void setMaxScore(Float maxScore) {
+ this.maxScore = maxScore;
+ }
+
+ public long getNumFound() {
+ return numFound;
+ }
+
+ public void setNumFound(long numFound) {
+ this.numFound = numFound;
+ }
+
+ public long getStart() {
+ return start;
+ }
+
+ public void setStart(long start) {
+ this.start = start;
+ }
+
+ @Override
+ public String toString() {
+ return "{numFound="+numFound
+ +",start="+start
+ + (maxScore!=null ? ",maxScore="+maxScore : "")
+ +",docs="+super.toString()
+ +"}";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/SolrException.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/SolrException.java b/ranger_solrj/src/main/java/org/apache/solr/common/SolrException.java
new file mode 100644
index 0000000..02bbc04
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/SolrException.java
@@ -0,0 +1,208 @@
+/*
+ * 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.common;
+
+import java.io.CharArrayWriter;
+import java.io.PrintWriter;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.solr.common.util.NamedList;
+import org.slf4j.Logger;
+
+/**
+ *
+ */
+public class SolrException extends RuntimeException {
+
+ /**
+ * This list of valid HTTP Status error codes that Solr may return in
+ * the case of a "Server Side" error.
+ *
+ * @since solr 1.2
+ */
+ public enum ErrorCode {
+ BAD_REQUEST( 400 ),
+ UNAUTHORIZED( 401 ),
+ FORBIDDEN( 403 ),
+ NOT_FOUND( 404 ),
+ CONFLICT( 409 ),
+ UNSUPPORTED_MEDIA_TYPE( 415 ),
+ SERVER_ERROR( 500 ),
+ SERVICE_UNAVAILABLE( 503 ),
+ INVALID_STATE( 510 ),
+ UNKNOWN(0);
+ public final int code;
+
+ private ErrorCode( int c )
+ {
+ code = c;
+ }
+ public static ErrorCode getErrorCode(int c){
+ for (ErrorCode err : values()) {
+ if(err.code == c) return err;
+ }
+ return UNKNOWN;
+ }
+ };
+
+ public SolrException(ErrorCode code, String msg) {
+ super(msg);
+ this.code = code.code;
+ }
+ public SolrException(ErrorCode code, String msg, Throwable th) {
+ super(msg, th);
+ this.code = code.code;
+ }
+
+ public SolrException(ErrorCode code, Throwable th) {
+ super(th);
+ this.code = code.code;
+ }
+
+ /**
+ * Constructor that can set arbitrary http status code. Not for
+ * use in Solr, but may be used by clients in subclasses to capture
+ * errors returned by the servlet container or other HTTP proxies.
+ */
+ protected SolrException(int code, String msg, Throwable th) {
+ super(msg, th);
+ this.code = code;
+ }
+
+ int code=0;
+ protected NamedList<String> metadata;
+
+ /**
+ * The HTTP Status code associated with this Exception. For SolrExceptions
+ * thrown by Solr "Server Side", this should valid {@link ErrorCode},
+ * however client side exceptions may contain an arbitrary error code based
+ * on the behavior of the Servlet Container hosting Solr, or any HTTP
+ * Proxies that may exist between the client and the server.
+ *
+ * @return The HTTP Status code associated with this Exception
+ */
+ public int code() { return code; }
+
+ public void setMetadata(NamedList<String> metadata) {
+ this.metadata = metadata;
+ }
+
+ public NamedList<String> getMetadata() {
+ return metadata;
+ }
+
+ public String getMetadata(String key) {
+ return (metadata != null && key != null) ? metadata.get(key) : null;
+ }
+
+ public void setMetadata(String key, String value) {
+ if (key == null || value == null)
+ throw new IllegalArgumentException("Exception metadata cannot be null!");
+
+ if (metadata == null)
+ metadata = new NamedList<String>();
+ metadata.add(key, value);
+ }
+
+ public void log(Logger log) { log(log,this); }
+ public static void log(Logger log, Throwable e) {
+ String stackTrace = toStr(e);
+ String ignore = doIgnore(e, stackTrace);
+ if (ignore != null) {
+ log.info(ignore);
+ return;
+ }
+ log.error(stackTrace);
+
+ }
+
+ public static void log(Logger log, String msg, Throwable e) {
+ String stackTrace = msg + ':' + toStr(e);
+ String ignore = doIgnore(e, stackTrace);
+ if (ignore != null) {
+ log.info(ignore);
+ return;
+ }
+ log.error(stackTrace);
+ }
+
+ public static void log(Logger log, String msg) {
+ String stackTrace = msg;
+ String ignore = doIgnore(null, stackTrace);
+ if (ignore != null) {
+ log.info(ignore);
+ return;
+ }
+ log.error(stackTrace);
+ }
+
+ // public String toString() { return toStr(this); } // oops, inf loop
+ @Override
+ public String toString() { return super.toString(); }
+
+ public static String toStr(Throwable e) {
+ CharArrayWriter cw = new CharArrayWriter();
+ PrintWriter pw = new PrintWriter(cw);
+ e.printStackTrace(pw);
+ pw.flush();
+ return cw.toString();
+
+/** This doesn't work for some reason!!!!!
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ e.printStackTrace(pw);
+ pw.flush();
+ System.out.println("The STRING:" + sw.toString());
+ return sw.toString();
+**/
+ }
+
+
+ /** For test code - do not log exceptions that match any of the regular expressions in ignorePatterns */
+ public static Set<String> ignorePatterns;
+
+ /** Returns null if this exception does not match any ignore patterns, or a message string to use if it does. */
+ public static String doIgnore(Throwable t, String m) {
+ if (ignorePatterns == null || m == null) return null;
+ if (t != null && t instanceof AssertionError) return null;
+
+ for (String regex : ignorePatterns) {
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(m);
+
+ if (matcher.find()) return "Ignoring exception matching " + regex;
+ }
+
+ return null;
+ }
+
+ public static Throwable getRootCause(Throwable t) {
+ while (true) {
+ Throwable cause = t.getCause();
+ if (cause!=null) {
+ t = cause;
+ } else {
+ break;
+ }
+ }
+ return t;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/SolrInputDocument.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/SolrInputDocument.java b/ranger_solrj/src/main/java/org/apache/solr/common/SolrInputDocument.java
new file mode 100644
index 0000000..a51efbf
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/SolrInputDocument.java
@@ -0,0 +1,301 @@
+/*
+ * 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.common;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Represent the field and boost information needed to construct and index
+ * a Lucene Document. Like the SolrDocument, the field values should
+ * match those specified in schema.xml
+ *
+ *
+ * @since solr 1.3
+ */
+public class SolrInputDocument implements Map<String,SolrInputField>, Iterable<SolrInputField>, Serializable
+{
+ private final Map<String,SolrInputField> _fields;
+ private float _documentBoost = 1.0f;
+ private List<SolrInputDocument> _childDocuments;
+
+ public SolrInputDocument() {
+ _fields = new LinkedHashMap<>();
+ }
+
+ public SolrInputDocument(Map<String,SolrInputField> fields) {
+ _fields = fields;
+ }
+
+ /**
+ * Remove all fields and boosts from the document
+ */
+ @Override
+ public void clear()
+ {
+ if( _fields != null ) {
+ _fields.clear();
+ }
+ _childDocuments = null;
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // Add / Set fields
+ ///////////////////////////////////////////////////////////////////
+
+ /**
+ * Add a field with implied null value for boost.
+ *
+ * The class type of value and the name parameter should match schema.xml.
+ * schema.xml can be found in conf directory under the solr home by default.
+ *
+ * @param name Name of the field, should match one of the field names defined under "fields" tag in schema.xml.
+ * @param value Value of the field, should be of same class type as defined by "type" attribute of the corresponding field in schema.xml.
+ * @see #addField(String, Object, float)
+ */
+ public void addField(String name, Object value)
+ {
+ addField(name, value, 1.0f );
+ }
+
+ /** Get the first value for a field.
+ *
+ * @param name name of the field to fetch
+ * @return first value of the field or null if not present
+ */
+ public Object getFieldValue(String name)
+ {
+ SolrInputField field = getField(name);
+ Object o = null;
+ if (field!=null) o = field.getFirstValue();
+ return o;
+ }
+
+ /** Get all the values for a field.
+ *
+ * @param name name of the field to fetch
+ * @return value of the field or null if not set
+ */
+ public Collection<Object> getFieldValues(String name)
+ {
+ SolrInputField field = getField(name);
+ if (field!=null) {
+ return field.getValues();
+ }
+ return null;
+ }
+
+ /** Get all field names.
+ *
+ * @return Set of all field names.
+ */
+ public Collection<String> getFieldNames()
+ {
+ return _fields.keySet();
+ }
+
+ /** Set a field with implied null value for boost.
+ *
+ * @see #setField(String, Object, float)
+ * @param name name of the field to set
+ * @param value value of the field
+ */
+ public void setField(String name, Object value)
+ {
+ setField(name, value, 1.0f );
+ }
+
+ public void setField(String name, Object value, float boost )
+ {
+ SolrInputField field = new SolrInputField( name );
+ _fields.put( name, field );
+ field.setValue( value, boost );
+ }
+
+ /**
+ * Adds a field with the given name, value and boost. If a field with the
+ * name already exists, then the given value is appended to the value of that
+ * field, with the new boost. If the value is a collection, then each of its
+ * values will be added to the field.
+ *
+ * The class type of value and the name parameter should match schema.xml.
+ * schema.xml can be found in conf directory under the solr home by default.
+ *
+ * @param name Name of the field, should match one of the field names defined under "fields" tag in schema.xml.
+ * @param value Value of the field, should be of same class type as defined by "type" attribute of the corresponding field in schema.xml.
+ * @param boost Boost value for the field
+ */
+ public void addField(String name, Object value, float boost )
+ {
+ SolrInputField field = _fields.get( name );
+ if( field == null || field.value == null ) {
+ setField(name, value, boost);
+ }
+ else {
+ field.addValue( value, boost );
+ }
+ }
+
+ /**
+ * Remove a field from the document
+ *
+ * @param name The field name whose field is to be removed from the document
+ * @return the previous field with <tt>name</tt>, or
+ * <tt>null</tt> if there was no field for <tt>key</tt>.
+ */
+ public SolrInputField removeField(String name) {
+ return _fields.remove( name );
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // Get the field values
+ ///////////////////////////////////////////////////////////////////
+
+ public SolrInputField getField( String field )
+ {
+ return _fields.get( field );
+ }
+
+ @Override
+ public Iterator<SolrInputField> iterator() {
+ return _fields.values().iterator();
+ }
+
+ public float getDocumentBoost() {
+ return _documentBoost;
+ }
+
+ public void setDocumentBoost(float documentBoost) {
+ _documentBoost = documentBoost;
+ }
+
+ @Override
+ public String toString()
+ {
+ return "SolrInputDocument(fields: " + _fields.values()
+ + ( _childDocuments == null ? "" : (", children: " + _childDocuments) )
+ + ")";
+ }
+
+ public SolrInputDocument deepCopy() {
+ SolrInputDocument clone = new SolrInputDocument();
+ Set<Entry<String,SolrInputField>> entries = _fields.entrySet();
+ for (Map.Entry<String,SolrInputField> fieldEntry : entries) {
+ clone._fields.put(fieldEntry.getKey(), fieldEntry.getValue().deepCopy());
+ }
+ clone._documentBoost = _documentBoost;
+
+ if (_childDocuments != null) {
+ clone._childDocuments = new ArrayList<>(_childDocuments.size());
+ for (SolrInputDocument child : _childDocuments) {
+ clone._childDocuments.add(child.deepCopy());
+ }
+ }
+
+ return clone;
+ }
+
+ //---------------------------------------------------
+ // MAP interface
+ //---------------------------------------------------
+
+ @Override
+ public boolean containsKey(Object key) {
+ return _fields.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ return _fields.containsValue(value);
+ }
+
+ @Override
+ public Set<Entry<String, SolrInputField>> entrySet() {
+ return _fields.entrySet();
+ }
+
+ @Override
+ public SolrInputField get(Object key) {
+ return _fields.get(key);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return _fields.isEmpty();
+ }
+
+ @Override
+ public Set<String> keySet() {
+ return _fields.keySet();
+ }
+
+ @Override
+ public SolrInputField put(String key, SolrInputField value) {
+ return _fields.put(key, value);
+ }
+
+ @Override
+ public void putAll(Map<? extends String, ? extends SolrInputField> t) {
+ _fields.putAll( t );
+ }
+
+ @Override
+ public SolrInputField remove(Object key) {
+ return _fields.remove(key);
+ }
+
+ @Override
+ public int size() {
+ return _fields.size();
+ }
+
+ @Override
+ public Collection<SolrInputField> values() {
+ return _fields.values();
+ }
+
+ public void addChildDocument(SolrInputDocument child) {
+ if (_childDocuments == null) {
+ _childDocuments = new ArrayList<>();
+ }
+ _childDocuments.add(child);
+ }
+
+ public void addChildDocuments(Collection<SolrInputDocument> childs) {
+ for (SolrInputDocument child : childs) {
+ addChildDocument(child);
+ }
+ }
+
+ /** Returns the list of child documents, or null if none. */
+ public List<SolrInputDocument> getChildDocuments() {
+ return _childDocuments;
+ }
+
+ public boolean hasChildDocuments() {
+ boolean isEmpty = (_childDocuments == null || _childDocuments.isEmpty());
+ return !isEmpty;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/SolrInputField.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/SolrInputField.java b/ranger_solrj/src/main/java/org/apache/solr/common/SolrInputField.java
new file mode 100644
index 0000000..02b6856
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/SolrInputField.java
@@ -0,0 +1,232 @@
+/*
+ * 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.common;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ *
+ * @since solr 1.3
+ */
+public class SolrInputField implements Iterable<Object>, Serializable
+{
+ String name;
+ Object value = null;
+ float boost = 1.0f;
+
+ public SolrInputField( String n )
+ {
+ this.name = n;
+ }
+
+ //---------------------------------------------------------------
+ //---------------------------------------------------------------
+
+ /**
+ * Set the value for a field. Arrays will be converted to a collection. If
+ * a collection is given, then that collection will be used as the backing
+ * collection for the values.
+ */
+ public void setValue(Object v, float b) {
+ boost = b;
+
+ if( v instanceof Object[] ) {
+ Object[] arr = (Object[])v;
+ Collection<Object> c = new ArrayList<>( arr.length );
+ for( Object o : arr ) {
+ c.add( o );
+ }
+ value = c;
+ }
+ else {
+ value = v;
+ }
+ }
+
+ /**
+ * Add values to a field. If the added value is a collection, each value
+ * will be added individually.
+ */
+ @SuppressWarnings("unchecked")
+ public void addValue(Object v, float b) {
+ if( value == null ) {
+ if ( v instanceof Collection ) {
+ Collection<Object> c = new ArrayList<>( 3 );
+ for ( Object o : (Collection<Object>)v ) {
+ c.add( o );
+ }
+ setValue(c, b);
+ } else {
+ setValue(v, b);
+ }
+
+ return;
+ }
+
+ // The lucene API and solr XML field specification make it possible to set boosts
+ // on multi-value fields even though lucene indexing does not support this.
+ // To keep behavior consistent with what happens in the lucene index, we accumulate
+ // the product of all boosts specified for this field.
+ boost *= b;
+
+ Collection<Object> vals = null;
+ if( value instanceof Collection ) {
+ vals = (Collection<Object>)value;
+ }
+ else {
+ vals = new ArrayList<>( 3 );
+ vals.add( value );
+ value = vals;
+ }
+
+ // Add the new values to a collection
+ if( v instanceof Iterable ) {
+ for( Object o : (Iterable<Object>)v ) {
+ vals.add( o );
+ }
+ }
+ else if( v instanceof Object[] ) {
+ for( Object o : (Object[])v ) {
+ vals.add( o );
+ }
+ }
+ else {
+ vals.add( v );
+ }
+ }
+
+ //---------------------------------------------------------------
+ //---------------------------------------------------------------
+
+ @SuppressWarnings("unchecked")
+ public Object getFirstValue() {
+ if( value instanceof Collection ) {
+ Collection c = (Collection<Object>)value;
+ if( c.size() > 0 ) {
+ return c.iterator().next();
+ }
+ return null;
+ }
+ return value;
+ }
+
+ /**
+ * @return the value for this field. If the field has multiple values, this
+ * will be a collection.
+ */
+ public Object getValue() {
+ return value;
+ }
+
+ /**
+ * @return the values for this field. This will return a collection even
+ * if the field is not multi-valued
+ */
+ @SuppressWarnings("unchecked")
+ public Collection<Object> getValues() {
+ if( value instanceof Collection ) {
+ return (Collection<Object>)value;
+ }
+ if( value != null ) {
+ Collection<Object> vals = new ArrayList<>(1);
+ vals.add( value );
+ return vals;
+ }
+ return null;
+ }
+
+ /**
+ * @return the number of values for this field
+ */
+ public int getValueCount() {
+ if( value instanceof Collection ) {
+ return ((Collection)value).size();
+ }
+ return (value == null) ? 0 : 1;
+ }
+
+ //---------------------------------------------------------------
+ //---------------------------------------------------------------
+
+ public float getBoost() {
+ return boost;
+ }
+
+ public void setBoost(float boost) {
+ this.boost = boost;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Iterator<Object> iterator() {
+ if( value instanceof Collection ) {
+ return ((Collection)value).iterator();
+ }
+ return new Iterator<Object>() {
+ boolean nxt = (value!=null);
+
+ @Override
+ public boolean hasNext() {
+ return nxt;
+ }
+
+ @Override
+ public Object next() {
+ nxt = false;
+ return value;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public String toString()
+ {
+ return name + ((boost == 1.0) ? "=" : ("("+boost+")=")) + value;
+ }
+
+ public SolrInputField deepCopy() {
+ SolrInputField clone = new SolrInputField(name);
+ clone.boost = boost;
+ // We can't clone here, so we rely on simple primitives
+ if (value instanceof Collection) {
+ Collection<Object> values = (Collection<Object>) value;
+ Collection<Object> cloneValues = new ArrayList<>(values.size());
+ cloneValues.addAll(values);
+ clone.value = cloneValues;
+ } else {
+ clone.value = value;
+ }
+ return clone;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/StringUtils.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/StringUtils.java b/ranger_solrj/src/main/java/org/apache/solr/common/StringUtils.java
new file mode 100644
index 0000000..00fef63
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/StringUtils.java
@@ -0,0 +1,26 @@
+package org.apache.solr.common;
+
+/*
+ * 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.
+ */
+
+public class StringUtils {
+
+ public static boolean isEmpty(String s) {
+ return (s == null) || s.isEmpty();
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/cloud/Aliases.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/cloud/Aliases.java b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/Aliases.java
new file mode 100644
index 0000000..1d18323
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/Aliases.java
@@ -0,0 +1,63 @@
+package org.apache.solr.common.cloud;
+
+/*
+ * 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.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Aliases {
+
+ private Map<String,Map<String,String>> aliasMap;
+
+ public Aliases(Map<String,Map<String,String>> aliasMap) {
+ this.aliasMap = aliasMap;
+ }
+
+ public Aliases() {
+ this.aliasMap = new HashMap<>();
+ }
+
+ public Map<String,String> getCollectionAliasMap() {
+ Map<String,String> cam = aliasMap.get("collection");
+ if (cam == null) return null;
+ return Collections.unmodifiableMap(cam);
+ }
+
+ public Map<String,Map<String,String>> getAliasMap() {
+ return Collections.unmodifiableMap(aliasMap);
+ }
+
+ public int collectionAliasSize() {
+ Map<String,String> cam = aliasMap.get("collection");
+ if (cam == null) return 0;
+ return cam.size();
+ }
+
+ @Override
+ public String toString() {
+ return "Aliases [aliasMap=" + aliasMap + "]";
+ }
+
+ public String getCollectionAlias(String collectionName) {
+ Map<String,String> cam = aliasMap.get("collection");
+ if (cam == null) return null;
+ return cam.get(collectionName);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/cloud/BeforeReconnect.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/cloud/BeforeReconnect.java b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/BeforeReconnect.java
new file mode 100644
index 0000000..44379a4
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/BeforeReconnect.java
@@ -0,0 +1,22 @@
+package org.apache.solr.common.cloud;
+
+/*
+ * 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.
+ */
+
+public interface BeforeReconnect {
+ public void command();
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClosableThread.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClosableThread.java b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClosableThread.java
new file mode 100644
index 0000000..1a19cbd
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClosableThread.java
@@ -0,0 +1,27 @@
+package org.apache.solr.common.cloud;
+
+/*
+ * 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.
+ */
+
+/**
+ * @deprecated because this class is no longer used internally and will be removed
+ */
+@Deprecated
+public interface ClosableThread {
+ public void close();
+ public boolean isClosed();
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClusterState.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClusterState.java b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClusterState.java
new file mode 100644
index 0000000..1b14360
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClusterState.java
@@ -0,0 +1,397 @@
+package org.apache.solr.common.cloud;
+
+/*
+ * 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.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.noggit.JSONWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * Immutable state of the cloud. Normally you can get the state by using
+ * {@link ZkStateReader#getClusterState()}.
+ * @lucene.experimental
+ */
+public class ClusterState implements JSONWriter.Writable {
+ private static Logger log = LoggerFactory.getLogger(ClusterState.class);
+
+ private final Integer znodeVersion;
+
+ private final Map<String, CollectionRef> collectionStates;
+ private Set<String> liveNodes;
+
+ /**
+ * Use this constr when ClusterState is meant for consumption.
+ */
+ public ClusterState(Integer znodeVersion, Set<String> liveNodes,
+ Map<String, DocCollection> collectionStates) {
+ this(liveNodes, getRefMap(collectionStates),znodeVersion);
+ }
+
+ private static Map<String, CollectionRef> getRefMap(Map<String, DocCollection> collectionStates) {
+ Map<String, CollectionRef> collRefs = new LinkedHashMap<>(collectionStates.size());
+ for (Entry<String, DocCollection> entry : collectionStates.entrySet()) {
+ final DocCollection c = entry.getValue();
+ collRefs.put(entry.getKey(), new CollectionRef(c));
+ }
+ return collRefs;
+ }
+
+ /**Use this if all the collection states are not readily available and some needs to be lazily loaded
+ */
+ public ClusterState(Set<String> liveNodes, Map<String, CollectionRef> collectionStates, Integer znodeVersion){
+ this.znodeVersion = znodeVersion;
+ this.liveNodes = new HashSet<>(liveNodes.size());
+ this.liveNodes.addAll(liveNodes);
+ this.collectionStates = new LinkedHashMap<>(collectionStates);
+ }
+
+
+ /**
+ * Returns a new cluster state object modified with the given collection.
+ *
+ * @param collectionName the name of the modified (or deleted) collection
+ * @param collection the collection object. A null value deletes the collection from the state
+ * @return the updated cluster state which preserves the current live nodes and zk node version
+ */
+ public ClusterState copyWith(String collectionName, DocCollection collection) {
+ ClusterState result = new ClusterState(liveNodes, new LinkedHashMap<>(collectionStates), znodeVersion);
+ if (collection == null) {
+ result.collectionStates.remove(collectionName);
+ } else {
+ result.collectionStates.put(collectionName, new CollectionRef(collection));
+ }
+ return result;
+ }
+
+
+ /**
+ * Get the lead replica for specific collection, or null if one currently doesn't exist.
+ */
+ public Replica getLeader(String collection, String sliceName) {
+ DocCollection coll = getCollectionOrNull(collection);
+ if (coll == null) return null;
+ Slice slice = coll.getSlice(sliceName);
+ if (slice == null) return null;
+ return slice.getLeader();
+ }
+ private Replica getReplica(DocCollection coll, String replicaName) {
+ if (coll == null) return null;
+ for (Slice slice : coll.getSlices()) {
+ Replica replica = slice.getReplica(replicaName);
+ if (replica != null) return replica;
+ }
+ return null;
+ }
+
+ public boolean hasCollection(String coll) {
+ return collectionStates.containsKey(coll) ;
+ }
+
+ /**
+ * Gets the replica by the core name (assuming the slice is unknown) or null if replica is not found.
+ * If the slice is known, do not use this method.
+ * coreNodeName is the same as replicaName
+ */
+ public Replica getReplica(final String collection, final String coreNodeName) {
+ return getReplica(getCollectionOrNull(collection), coreNodeName);
+ }
+
+ /**
+ * Get the named Slice for collection, or null if not found.
+ */
+ public Slice getSlice(String collection, String sliceName) {
+ DocCollection coll = getCollectionOrNull(collection);
+ if (coll == null) return null;
+ return coll.getSlice(sliceName);
+ }
+
+ public Map<String, Slice> getSlicesMap(String collection) {
+ DocCollection coll = getCollectionOrNull(collection);
+ if (coll == null) return null;
+ return coll.getSlicesMap();
+ }
+
+ public Map<String, Slice> getActiveSlicesMap(String collection) {
+ DocCollection coll = getCollectionOrNull(collection);
+ if (coll == null) return null;
+ return coll.getActiveSlicesMap();
+ }
+
+ public Collection<Slice> getSlices(String collection) {
+ DocCollection coll = getCollectionOrNull(collection);
+ if (coll == null) return null;
+ return coll.getSlices();
+ }
+
+ public Collection<Slice> getActiveSlices(String collection) {
+ DocCollection coll = getCollectionOrNull(collection);
+ if (coll == null) return null;
+ return coll.getActiveSlices();
+ }
+
+
+ /**
+ * Get the named DocCollection object, or throw an exception if it doesn't exist.
+ */
+ public DocCollection getCollection(String collection) {
+ DocCollection coll = getCollectionOrNull(collection);
+ if (coll == null) throw new SolrException(ErrorCode.BAD_REQUEST, "Could not find collection : " + collection);
+ return coll;
+ }
+
+ public CollectionRef getCollectionRef(String coll) {
+ return collectionStates.get(coll);
+ }
+
+ public DocCollection getCollectionOrNull(String coll) {
+ CollectionRef ref = collectionStates.get(coll);
+ return ref == null? null:ref.get();
+ }
+
+ /**
+ * Get collection names.
+ */
+ public Set<String> getCollections() {
+ return collectionStates.keySet();
+ }
+
+
+ /**
+ * Get names of the currently live nodes.
+ */
+ public Set<String> getLiveNodes() {
+ return Collections.unmodifiableSet(liveNodes);
+ }
+
+ public String getShardId(String nodeName, String coreName) {
+ return getShardId(null, nodeName, coreName);
+ }
+
+ public String getShardId(String collectionName, String nodeName, String coreName) {
+ Collection<CollectionRef> states = collectionStates.values();
+ if (collectionName != null) {
+ CollectionRef c = collectionStates.get(collectionName);
+ if (c != null) states = Collections.singletonList( c );
+ }
+
+ for (CollectionRef ref : states) {
+ DocCollection coll = ref.get();
+ if(coll == null) continue;// this collection go tremoved in between, skip
+ for (Slice slice : coll.getSlices()) {
+ for (Replica replica : slice.getReplicas()) {
+ // TODO: for really large clusters, we could 'index' on this
+ String rnodeName = replica.getStr(ZkStateReader.NODE_NAME_PROP);
+ String rcore = replica.getStr(ZkStateReader.CORE_NAME_PROP);
+ if (nodeName.equals(rnodeName) && coreName.equals(rcore)) {
+ return slice.getName();
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check if node is alive.
+ */
+ public boolean liveNodesContain(String name) {
+ return liveNodes.contains(name);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("live nodes:" + liveNodes);
+ sb.append(" collections:" + collectionStates);
+ return sb.toString();
+ }
+
+ public static ClusterState load(Integer version, byte[] bytes, Set<String> liveNodes) {
+ return load(version, bytes, liveNodes, ZkStateReader.CLUSTER_STATE);
+ }
+ /**
+ * Create ClusterState from json string that is typically stored in zookeeper.
+ *
+ * @param version zk version of the clusterstate.json file (bytes)
+ * @param bytes clusterstate.json as a byte array
+ * @param liveNodes list of live nodes
+ * @return the ClusterState
+ */
+ public static ClusterState load(Integer version, byte[] bytes, Set<String> liveNodes, String znode) {
+ // System.out.println("######## ClusterState.load:" + (bytes==null ? null : new String(bytes)));
+ if (bytes == null || bytes.length == 0) {
+ return new ClusterState(version, liveNodes, Collections.<String, DocCollection>emptyMap());
+ }
+ Map<String, Object> stateMap = (Map<String, Object>) ZkStateReader.fromJSON(bytes);
+ Map<String,CollectionRef> collections = new LinkedHashMap<>(stateMap.size());
+ for (Entry<String, Object> entry : stateMap.entrySet()) {
+ String collectionName = entry.getKey();
+ DocCollection coll = collectionFromObjects(collectionName, (Map<String,Object>)entry.getValue(), version, znode);
+ collections.put(collectionName, new CollectionRef(coll));
+ }
+
+ return new ClusterState( liveNodes, collections,version);
+ }
+
+
+ public static Aliases load(byte[] bytes) {
+ if (bytes == null || bytes.length == 0) {
+ return new Aliases();
+ }
+ Map<String,Map<String,String>> aliasMap = (Map<String,Map<String,String>>) ZkStateReader.fromJSON(bytes);
+
+ return new Aliases(aliasMap);
+ }
+
+ private static DocCollection collectionFromObjects(String name, Map<String, Object> objs, Integer version, String znode) {
+ Map<String,Object> props;
+ Map<String,Slice> slices;
+
+ Map<String,Object> sliceObjs = (Map<String,Object>)objs.get(DocCollection.SHARDS);
+ if (sliceObjs == null) {
+ // legacy format from 4.0... there was no separate "shards" level to contain the collection shards.
+ slices = makeSlices(objs);
+ props = Collections.emptyMap();
+ } else {
+ slices = makeSlices(sliceObjs);
+ props = new HashMap<>(objs);
+ objs.remove(DocCollection.SHARDS);
+ }
+
+ Object routerObj = props.get(DocCollection.DOC_ROUTER);
+ DocRouter router;
+ if (routerObj == null) {
+ router = DocRouter.DEFAULT;
+ } else if (routerObj instanceof String) {
+ // back compat with Solr4.4
+ router = DocRouter.getDocRouter((String)routerObj);
+ } else {
+ Map routerProps = (Map)routerObj;
+ router = DocRouter.getDocRouter((String) routerProps.get("name"));
+ }
+
+ return new DocCollection(name, slices, props, router, version, znode);
+ }
+
+ private static Map<String,Slice> makeSlices(Map<String,Object> genericSlices) {
+ if (genericSlices == null) return Collections.emptyMap();
+ Map<String,Slice> result = new LinkedHashMap<>(genericSlices.size());
+ for (Map.Entry<String,Object> entry : genericSlices.entrySet()) {
+ String name = entry.getKey();
+ Object val = entry.getValue();
+ if (val instanceof Slice) {
+ result.put(name, (Slice)val);
+ } else if (val instanceof Map) {
+ result.put(name, new Slice(name, null, (Map<String,Object>)val));
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public void write(JSONWriter jsonWriter) {
+ LinkedHashMap<String , DocCollection> map = new LinkedHashMap<>();
+ for (Entry<String, CollectionRef> e : collectionStates.entrySet()) {
+ // using this class check to avoid fetching from ZK in case of lazily loaded collection
+ if (e.getValue().getClass() == CollectionRef.class) {
+ // check if it is a lazily loaded collection outside of clusterstate.json
+ DocCollection coll = e.getValue().get();
+ if (coll.getStateFormat() == 1) {
+ map.put(coll.getName(),coll);
+ }
+ }
+ }
+ jsonWriter.write(map);
+ }
+
+ /**
+ * The version of clusterstate.json in ZooKeeper.
+ *
+ * @return null if ClusterState was created for publication, not consumption
+ */
+ public Integer getZkClusterStateVersion() {
+ return znodeVersion;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result
+ + ((znodeVersion == null) ? 0 : znodeVersion.hashCode());
+ result = prime * result + ((liveNodes == null) ? 0 : liveNodes.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ ClusterState other = (ClusterState) obj;
+ if (znodeVersion == null) {
+ if (other.znodeVersion != null) return false;
+ } else if (!znodeVersion.equals(other.znodeVersion)) return false;
+ if (liveNodes == null) {
+ if (other.liveNodes != null) return false;
+ } else if (!liveNodes.equals(other.liveNodes)) return false;
+ return true;
+ }
+
+
+
+ /**
+ * Internal API used only by ZkStateReader
+ */
+ void setLiveNodes(Set<String> liveNodes){
+ this.liveNodes = liveNodes;
+ }
+
+ /**For internal use only
+ */
+ Map<String, CollectionRef> getCollectionStates() {
+ return collectionStates;
+ }
+
+ public static class CollectionRef {
+ private final DocCollection coll;
+
+ public CollectionRef(DocCollection coll) {
+ this.coll = coll;
+ }
+
+ public DocCollection get(){
+ return coll;
+ }
+
+ public boolean isLazilyLoaded() { return false; }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClusterStateUtil.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClusterStateUtil.java b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClusterStateUtil.java
new file mode 100644
index 0000000..fe74884
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/common/cloud/ClusterStateUtil.java
@@ -0,0 +1,230 @@
+package org.apache.solr.common.cloud;
+
+/*
+ * 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.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClusterStateUtil {
+ private static Logger log = LoggerFactory.getLogger(ClusterStateUtil.class);
+
+ private static final int TIMEOUT_POLL_MS = 1000;
+
+ /**
+ * Wait to see *all* cores live and active.
+ *
+ * @param zkStateReader
+ * to use for ClusterState
+ * @param timeoutInMs
+ * how long to wait before giving up
+ * @return false if timed out
+ */
+ public static boolean waitForAllActiveAndLive(ZkStateReader zkStateReader, int timeoutInMs) {
+ return waitForAllActiveAndLive(zkStateReader, null, timeoutInMs);
+ }
+
+ /**
+ * Wait to see *all* cores live and active.
+ *
+ * @param zkStateReader
+ * to use for ClusterState
+ * @param collection to look at
+ * @param timeoutInMs
+ * how long to wait before giving up
+ * @return false if timed out
+ */
+ public static boolean waitForAllActiveAndLive(ZkStateReader zkStateReader, String collection,
+ int timeoutInMs) {
+ long timeout = System.nanoTime()
+ + TimeUnit.NANOSECONDS.convert(timeoutInMs, TimeUnit.MILLISECONDS);
+ boolean success = false;
+ while (System.nanoTime() < timeout) {
+ success = true;
+ ClusterState clusterState = zkStateReader.getClusterState();
+ if (clusterState != null) {
+ Set<String> collections;
+ if (collection != null) {
+ collections = Collections.singleton(collection);
+ } else {
+ collections = clusterState.getCollections();
+ }
+ for (String coll : collections) {
+ DocCollection docCollection = clusterState.getCollection(coll);
+ Collection<Slice> slices = docCollection.getSlices();
+ for (Slice slice : slices) {
+ // only look at active shards
+ if (slice.getState().equals(Slice.ACTIVE)) {
+ Collection<Replica> replicas = slice.getReplicas();
+ for (Replica replica : replicas) {
+ // on a live node?
+ boolean live = clusterState.liveNodesContain(replica
+ .getNodeName());
+ String state = replica.getStr(ZkStateReader.STATE_PROP);
+ if (!live || !state.equals(ZkStateReader.ACTIVE)) {
+ // fail
+ success = false;
+ }
+ }
+ }
+ }
+ }
+ if (!success) {
+ try {
+ Thread.sleep(TIMEOUT_POLL_MS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new SolrException(ErrorCode.SERVER_ERROR, "Interrupted");
+ }
+ }
+ }
+ }
+
+ return success;
+ }
+
+ /**
+ * Wait to see an entry in the ClusterState with a specific coreNodeName and
+ * baseUrl.
+ *
+ * @param zkStateReader
+ * to use for ClusterState
+ * @param collection
+ * to look in
+ * @param coreNodeName
+ * to wait for
+ * @param baseUrl
+ * to wait for
+ * @param timeoutInMs
+ * how long to wait before giving up
+ * @return false if timed out
+ */
+ public static boolean waitToSeeLive(ZkStateReader zkStateReader,
+ String collection, String coreNodeName, String baseUrl,
+ int timeoutInMs) {
+ long timeout = System.nanoTime()
+ + TimeUnit.NANOSECONDS.convert(timeoutInMs, TimeUnit.MILLISECONDS);
+
+ while (System.nanoTime() < timeout) {
+ log.debug("waiting to see replica just created live collection={} replica={} baseUrl={}",
+ collection, coreNodeName, baseUrl);
+ ClusterState clusterState = zkStateReader.getClusterState();
+ if (clusterState != null) {
+ DocCollection docCollection = clusterState.getCollection(collection);
+ Collection<Slice> slices = docCollection.getSlices();
+ for (Slice slice : slices) {
+ // only look at active shards
+ if (slice.getState().equals(Slice.ACTIVE)) {
+ Collection<Replica> replicas = slice.getReplicas();
+ for (Replica replica : replicas) {
+ // on a live node?
+ boolean live = clusterState.liveNodesContain(replica.getNodeName());
+ String rcoreNodeName = replica.getName();
+ String rbaseUrl = replica.getStr(ZkStateReader.BASE_URL_PROP);
+ if (live && coreNodeName.equals(rcoreNodeName)
+ && baseUrl.equals(rbaseUrl)) {
+ // found it
+ return true;
+ }
+ }
+ }
+ }
+ try {
+ Thread.sleep(TIMEOUT_POLL_MS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new SolrException(ErrorCode.SERVER_ERROR, "Interrupted");
+ }
+ }
+ }
+
+ log.error("Timed out waiting to see replica just created in cluster state. Continuing...");
+ return false;
+ }
+
+ public static boolean waitForAllNotLive(ZkStateReader zkStateReader, int timeoutInMs) {
+ return waitForAllNotLive(zkStateReader, null, timeoutInMs);
+ }
+
+
+ public static boolean waitForAllNotLive(ZkStateReader zkStateReader,
+ String collection, int timeoutInMs) {
+ long timeout = System.nanoTime()
+ + TimeUnit.NANOSECONDS.convert(timeoutInMs, TimeUnit.MILLISECONDS);
+ boolean success = false;
+ while (System.nanoTime() < timeout) {
+ success = true;
+ ClusterState clusterState = zkStateReader.getClusterState();
+ if (clusterState != null) {
+ Set<String> collections;
+ if (collection == null) {
+ collections = clusterState.getCollections();
+ } else {
+ collections = Collections.singleton(collection);
+ }
+ for (String coll : collections) {
+ DocCollection docCollection = clusterState.getCollection(coll);
+ Collection<Slice> slices = docCollection.getSlices();
+ for (Slice slice : slices) {
+ // only look at active shards
+ if (slice.getState().equals(Slice.ACTIVE)) {
+ Collection<Replica> replicas = slice.getReplicas();
+ for (Replica replica : replicas) {
+ // on a live node?
+ boolean live = clusterState.liveNodesContain(replica
+ .getNodeName());
+ if (live) {
+ // fail
+ success = false;
+ }
+ }
+ }
+ }
+ }
+ if (!success) {
+ try {
+ Thread.sleep(TIMEOUT_POLL_MS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new SolrException(ErrorCode.SERVER_ERROR, "Interrupted");
+ }
+ }
+ }
+ }
+
+ return success;
+ }
+
+ public static boolean isAutoAddReplicas(ZkStateReader reader, String collection) {
+ ClusterState clusterState = reader.getClusterState();
+ if (clusterState != null) {
+ DocCollection docCollection = clusterState.getCollectionOrNull(collection);
+ if (docCollection != null) {
+ return docCollection.getAutoAddReplicas();
+ }
+ }
+ return false;
+ }
+
+}