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; + } + +}
