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:37 UTC
[15/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/SolrQuery.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrQuery.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrQuery.java
new file mode 100644
index 0000000..bda6f34
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrQuery.java
@@ -0,0 +1,1109 @@
+/*
+ * 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;
+
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.FacetParams;
+import org.apache.solr.common.params.HighlightParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.StatsParams;
+import org.apache.solr.common.params.TermsParams;
+import org.apache.solr.common.util.DateUtil;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.regex.Pattern;
+
+
+/**
+ * This is an augmented SolrParams with get/set/add fields for common fields used
+ * in the Standard and Dismax request handlers
+ *
+ *
+ * @since solr 1.3
+ */
+public class SolrQuery extends ModifiableSolrParams
+{
+ public static final String DOCID = "_docid_"; // duplicate of org.apache.solr.search.QueryParsing.DOCID which is not accessible from here
+
+ public enum ORDER { desc, asc;
+ public ORDER reverse() {
+ return (this == asc) ? desc : asc;
+ }
+ }
+
+ /** Maintains a map of current sorts */
+ private List<SortClause> sortClauses;
+
+ public SolrQuery() {
+ super();
+ }
+
+ /** Create a new SolrQuery
+ *
+ * @param q query string
+ */
+ public SolrQuery(String q) {
+ this();
+ this.set(CommonParams.Q, q);
+ }
+
+ /** enable/disable terms.
+ *
+ * @param b flag to indicate terms should be enabled. <br> if b==false, removes all other terms parameters
+ * @return Current reference (<i>this</i>)
+ */
+ public SolrQuery setTerms(boolean b) {
+ if (b) {
+ this.set(TermsParams.TERMS, true);
+ } else {
+ this.remove(TermsParams.TERMS);
+ this.remove(TermsParams.TERMS_FIELD);
+ this.remove(TermsParams.TERMS_LOWER);
+ this.remove(TermsParams.TERMS_UPPER);
+ this.remove(TermsParams.TERMS_UPPER_INCLUSIVE);
+ this.remove(TermsParams.TERMS_LOWER_INCLUSIVE);
+ this.remove(TermsParams.TERMS_LIMIT);
+ this.remove(TermsParams.TERMS_PREFIX_STR);
+ this.remove(TermsParams.TERMS_MINCOUNT);
+ this.remove(TermsParams.TERMS_MAXCOUNT);
+ this.remove(TermsParams.TERMS_RAW);
+ this.remove(TermsParams.TERMS_SORT);
+ this.remove(TermsParams.TERMS_REGEXP_STR);
+ this.remove(TermsParams.TERMS_REGEXP_FLAG);
+ }
+ return this;
+ }
+
+ public boolean getTerms() {
+ return this.getBool(TermsParams.TERMS, false);
+ }
+
+ public SolrQuery addTermsField(String field) {
+ this.add(TermsParams.TERMS_FIELD, field);
+ return this;
+ }
+
+ public String[] getTermsFields() {
+ return this.getParams(TermsParams.TERMS_FIELD);
+ }
+
+ public SolrQuery setTermsLower(String lower) {
+ this.set(TermsParams.TERMS_LOWER, lower);
+ return this;
+ }
+
+ public String getTermsLower() {
+ return this.get(TermsParams.TERMS_LOWER, "");
+ }
+
+ public SolrQuery setTermsUpper(String upper) {
+ this.set(TermsParams.TERMS_UPPER, upper);
+ return this;
+ }
+
+ public String getTermsUpper() {
+ return this.get(TermsParams.TERMS_UPPER, "");
+ }
+
+ public SolrQuery setTermsUpperInclusive(boolean b) {
+ this.set(TermsParams.TERMS_UPPER_INCLUSIVE, b);
+ return this;
+ }
+
+ public boolean getTermsUpperInclusive() {
+ return this.getBool(TermsParams.TERMS_UPPER_INCLUSIVE, false);
+ }
+
+ public SolrQuery setTermsLowerInclusive(boolean b) {
+ this.set(TermsParams.TERMS_LOWER_INCLUSIVE, b);
+ return this;
+ }
+
+ public boolean getTermsLowerInclusive() {
+ return this.getBool(TermsParams.TERMS_LOWER_INCLUSIVE, true);
+ }
+
+ public SolrQuery setTermsLimit(int limit) {
+ this.set(TermsParams.TERMS_LIMIT, limit);
+ return this;
+ }
+
+ public int getTermsLimit() {
+ return this.getInt(TermsParams.TERMS_LIMIT, 10);
+ }
+
+ public SolrQuery setTermsMinCount(int cnt) {
+ this.set(TermsParams.TERMS_MINCOUNT, cnt);
+ return this;
+ }
+
+ public int getTermsMinCount() {
+ return this.getInt(TermsParams.TERMS_MINCOUNT, 1);
+ }
+
+ public SolrQuery setTermsMaxCount(int cnt) {
+ this.set(TermsParams.TERMS_MAXCOUNT, cnt);
+ return this;
+ }
+
+ public int getTermsMaxCount() {
+ return this.getInt(TermsParams.TERMS_MAXCOUNT, -1);
+ }
+
+ public SolrQuery setTermsPrefix(String prefix) {
+ this.set(TermsParams.TERMS_PREFIX_STR, prefix);
+ return this;
+ }
+
+ public String getTermsPrefix() {
+ return this.get(TermsParams.TERMS_PREFIX_STR, "");
+ }
+
+ public SolrQuery setTermsRaw(boolean b) {
+ this.set(TermsParams.TERMS_RAW, b);
+ return this;
+ }
+
+ public boolean getTermsRaw() {
+ return this.getBool(TermsParams.TERMS_RAW, false);
+ }
+
+ public SolrQuery setTermsSortString(String type) {
+ this.set(TermsParams.TERMS_SORT, type);
+ return this;
+ }
+
+ public String getTermsSortString() {
+ return this.get(TermsParams.TERMS_SORT, TermsParams.TERMS_SORT_COUNT);
+ }
+
+ public SolrQuery setTermsRegex(String regex) {
+ this.set(TermsParams.TERMS_REGEXP_STR, regex);
+ return this;
+ }
+
+ public String getTermsRegex() {
+ return this.get(TermsParams.TERMS_REGEXP_STR);
+ }
+
+ public SolrQuery setTermsRegexFlag(String flag) {
+ this.add(TermsParams.TERMS_REGEXP_FLAG, flag);
+ return this;
+ }
+
+ public String[] getTermsRegexFlags() {
+ return this.getParams(TermsParams.TERMS_REGEXP_FLAG);
+ }
+
+ /** Add field(s) for facet computation.
+ *
+ * @param fields Array of field names from the IndexSchema
+ * @return this
+ */
+ public SolrQuery addFacetField(String ... fields) {
+ add(FacetParams.FACET_FIELD, fields);
+ this.set(FacetParams.FACET, true);
+ return this;
+ }
+
+ /** Add field(s) for pivot computation.
+ *
+ * pivot fields are comma separated
+ *
+ * @param fields Array of field names from the IndexSchema
+ * @return this
+ */
+ public SolrQuery addFacetPivotField(String ... fields) {
+ add(FacetParams.FACET_PIVOT, fields);
+ this.set(FacetParams.FACET, true);
+ return this;
+ }
+
+ /**
+ * Add a numeric range facet.
+ *
+ * @param field The field
+ * @param start The start of range
+ * @param end The end of the range
+ * @param gap The gap between each count
+ * @return this
+ */
+ public SolrQuery addNumericRangeFacet(String field, Number start, Number end, Number gap) {
+ add(FacetParams.FACET_RANGE, field);
+ add(String.format(Locale.ROOT, "f.%s.%s", field, FacetParams.FACET_RANGE_START), start.toString());
+ add(String.format(Locale.ROOT, "f.%s.%s", field, FacetParams.FACET_RANGE_END), end.toString());
+ add(String.format(Locale.ROOT, "f.%s.%s", field, FacetParams.FACET_RANGE_GAP), gap.toString());
+ this.set(FacetParams.FACET, true);
+ return this;
+ }
+
+ /**
+ * Add a numeric range facet.
+ *
+ * @param field The field
+ * @param start The start of range
+ * @param end The end of the range
+ * @param gap The gap between each count
+ * @return this
+ */
+ public SolrQuery addDateRangeFacet(String field, Date start, Date end, String gap) {
+ add(FacetParams.FACET_RANGE, field);
+ add(String.format(Locale.ROOT, "f.%s.%s", field, FacetParams.FACET_RANGE_START), DateUtil.getThreadLocalDateFormat().format(start));
+ add(String.format(Locale.ROOT, "f.%s.%s", field, FacetParams.FACET_RANGE_END), DateUtil.getThreadLocalDateFormat().format(end));
+ add(String.format(Locale.ROOT, "f.%s.%s", field, FacetParams.FACET_RANGE_GAP), gap);
+ this.set(FacetParams.FACET, true);
+ return this;
+ }
+
+ /**
+ * Add Interval Faceting on a field. All intervals for the same field should be included
+ * in the same call to this method.
+ * For syntax documentation see <a href="https://wiki.apache.org/solr/SimpleFacetParameters#Interval_Faceting">Solr wiki</a>.
+ * <br>
+ * Key substitution, filter exclusions or other local params on the field are not supported when using this method,
+ * if this is needed, use the lower level {@link #add} method.<br>
+ * Key substitution IS supported on intervals when using this method.
+ *
+ *
+ * @param field the field to add facet intervals. Must be an existing field and can't be null
+ * @param intervals Intervals to be used for faceting. It can be an empty array, but it can't
+ * be <code>null</code>
+ * @return this
+ */
+ public SolrQuery addIntervalFacets(String field, String[] intervals) {
+ if (intervals == null) {
+ throw new IllegalArgumentException("Can't add null intervals");
+ }
+ if (field == null) {
+ throw new IllegalArgumentException("Field can't be null");
+ }
+ set(FacetParams.FACET, true);
+ add(FacetParams.FACET_INTERVAL, field);
+ for (String interval:intervals) {
+ add(String.format(Locale.ROOT, "f.%s.facet.interval.set", field), interval);
+ }
+ return this;
+ }
+
+ /**
+ * Remove all Interval Facets on a field
+ *
+ * @param field the field to remove from facet intervals
+ * @return Array of current intervals for <code>field</code>
+ */
+ public String[] removeIntervalFacets(String field) {
+ while(remove(FacetParams.FACET_INTERVAL, field)){};
+ return remove(String.format(Locale.ROOT, "f.%s.facet.interval.set", field));
+ }
+
+ /** get the facet fields
+ *
+ * @return string array of facet fields or null if not set/empty
+ */
+ public String[] getFacetFields() {
+ return this.getParams(FacetParams.FACET_FIELD);
+ }
+
+ /** remove a facet field
+ *
+ * @param name Name of the facet field to be removed.
+ *
+ * @return true, if the item was removed. <br>
+ * false, if the facet field was null or did not exist.
+ */
+ public boolean removeFacetField(String name) {
+ boolean b = this.remove(FacetParams.FACET_FIELD, name);
+ if (this.get(FacetParams.FACET_FIELD) == null && this.get(FacetParams.FACET_QUERY) == null) {
+ this.setFacet(false);
+ }
+ return b;
+ }
+
+ /** enable/disable faceting.
+ *
+ * @param b flag to indicate faceting should be enabled. <br> if b==false, removes all other faceting parameters
+ * @return Current reference (<i>this</i>)
+ */
+ public SolrQuery setFacet(boolean b) {
+ if (b) {
+ this.set(FacetParams.FACET, true);
+ } else {
+ this.remove(FacetParams.FACET);
+ this.remove(FacetParams.FACET_MINCOUNT);
+ this.remove(FacetParams.FACET_FIELD);
+ this.remove(FacetParams.FACET_LIMIT);
+ this.remove(FacetParams.FACET_MISSING);
+ this.remove(FacetParams.FACET_OFFSET);
+ this.remove(FacetParams.FACET_PREFIX);
+ this.remove(FacetParams.FACET_QUERY);
+ this.remove(FacetParams.FACET_SORT);
+ this.remove(FacetParams.FACET_ZEROS);
+ this.remove(FacetParams.FACET_PREFIX); // does not include the individual fields...
+ this.remove(FacetParams.FACET_INTERVAL); // does not remove interval parameters
+ }
+ return this;
+ }
+
+ public SolrQuery setFacetPrefix( String prefix )
+ {
+ this.set( FacetParams.FACET_PREFIX, prefix );
+ return this;
+ }
+
+ public SolrQuery setFacetPrefix( String field, String prefix )
+ {
+ this.set( "f."+field+"."+FacetParams.FACET_PREFIX, prefix );
+ return this;
+ }
+
+ /** add a faceting query
+ *
+ * @param f facet query
+ */
+ public SolrQuery addFacetQuery(String f) {
+ this.add(FacetParams.FACET_QUERY, f);
+ this.set(FacetParams.FACET, true);
+ return this;
+ }
+
+ /** get facet queries
+ *
+ * @return all facet queries or null if not set/empty
+ */
+ public String[] getFacetQuery() {
+ return this.getParams(FacetParams.FACET_QUERY);
+ }
+
+ /** remove a facet query
+ *
+ * @param q the facet query to remove
+ * @return true if the facet query was removed false otherwise
+ */
+ public boolean removeFacetQuery(String q) {
+ boolean b = this.remove(FacetParams.FACET_QUERY, q);
+ if (this.get(FacetParams.FACET_FIELD) == null && this.get(FacetParams.FACET_QUERY) == null) {
+ this.setFacet(false);
+ }
+ return b;
+ }
+
+ /** set the facet limit
+ *
+ * @param lim number facet items to return
+ */
+ public SolrQuery setFacetLimit(int lim) {
+ this.set(FacetParams.FACET_LIMIT, lim);
+ return this;
+ }
+
+ /** get current facet limit
+ *
+ * @return facet limit or default of 25
+ */
+ public int getFacetLimit() {
+ return this.getInt(FacetParams.FACET_LIMIT, 25);
+ }
+
+ /** set facet minimum count
+ *
+ * @param cnt facets having less that cnt hits will be excluded from teh facet list
+ */
+ public SolrQuery setFacetMinCount(int cnt) {
+ this.set(FacetParams.FACET_MINCOUNT, cnt);
+ return this;
+ }
+
+ /** get facet minimum count
+ *
+ * @return facet minimum count or default of 1
+ */
+ public int getFacetMinCount() {
+ return this.getInt(FacetParams.FACET_MINCOUNT, 1);
+ }
+
+ /**
+ * Sets facet missing boolean flag
+ *
+ * @param v flag to indicate the field of {@link FacetParams#FACET_MISSING} .
+ * @return this
+ */
+ public SolrQuery setFacetMissing(Boolean v) {
+ this.set(FacetParams.FACET_MISSING, v);
+ return this;
+ }
+
+ /** get facet sort
+ *
+ * @return facet sort or default of {@link FacetParams#FACET_SORT_COUNT}
+ */
+ public String getFacetSortString() {
+ return this.get(FacetParams.FACET_SORT, FacetParams.FACET_SORT_COUNT);
+ }
+
+
+ /** set facet sort
+ *
+ * @param sort sort facets
+ * @return this
+ */
+ public SolrQuery setFacetSort(String sort) {
+ this.set(FacetParams.FACET_SORT, sort);
+ return this;
+ }
+
+ /** add highlight field
+ *
+ * @param f field to enable for highlighting
+ */
+ public SolrQuery addHighlightField(String f) {
+ this.add(HighlightParams.FIELDS, f);
+ this.set(HighlightParams.HIGHLIGHT, true);
+ return this;
+ }
+
+ /** remove a field for highlighting
+ *
+ * @param f field name to not highlight
+ * @return <i>true</i>, if removed, <br> <i>false</i>, otherwise
+ */
+ public boolean removeHighlightField(String f) {
+ boolean b = this.remove(HighlightParams.FIELDS, f);
+ if (this.get(HighlightParams.FIELDS) == null) {
+ this.setHighlight(false);
+ }
+ return b;
+ }
+
+ /** get list of highlighted fields
+ *
+ * @return Array of highlight fields or null if not set/empty
+ */
+ public String[] getHighlightFields() {
+ return this.getParams(HighlightParams.FIELDS);
+ }
+
+ public SolrQuery setHighlightSnippets(int num) {
+ this.set(HighlightParams.SNIPPETS, num);
+ return this;
+ }
+
+ public int getHighlightSnippets() {
+ return this.getInt(HighlightParams.SNIPPETS, 1);
+ }
+
+ public SolrQuery setHighlightFragsize(int num) {
+ this.set(HighlightParams.FRAGSIZE, num);
+ return this;
+ }
+
+ public int getHighlightFragsize() {
+ return this.getInt(HighlightParams.FRAGSIZE, 100);
+ }
+
+ public SolrQuery setHighlightRequireFieldMatch(boolean flag) {
+ this.set(HighlightParams.FIELD_MATCH, flag);
+ return this;
+ }
+
+ public boolean getHighlightRequireFieldMatch() {
+ return this.getBool(HighlightParams.FIELD_MATCH, false);
+ }
+
+ public SolrQuery setHighlightSimplePre(String f) {
+ this.set(HighlightParams.SIMPLE_PRE, f);
+ return this;
+ }
+
+ public String getHighlightSimplePre() {
+ return this.get(HighlightParams.SIMPLE_PRE, "");
+ }
+
+ public SolrQuery setHighlightSimplePost(String f) {
+ this.set(HighlightParams.SIMPLE_POST, f);
+ return this;
+ }
+
+ public String getHighlightSimplePost() {
+ return this.get(HighlightParams.SIMPLE_POST, "");
+ }
+
+ /**
+ * Gets the raw sort field, as it will be sent to Solr.
+ * <p>
+ * The returned sort field will always contain a serialized version
+ * of the sort string built using {@link #setSort(SortClause)},
+ * {@link #addSort(SortClause)}, {@link #addOrUpdateSort(SortClause)},
+ * {@link #removeSort(SortClause)}, {@link #clearSorts()} and
+ * {@link #setSorts(List)}.
+ */
+ public String getSortField() {
+ return this.get(CommonParams.SORT);
+ }
+
+ /**
+ * Clears current sort information.
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery clearSorts() {
+ sortClauses = null;
+ serializeSorts();
+ return this;
+ }
+
+ /**
+ * Replaces the current sort information.
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery setSorts(List<SortClause> value) {
+ sortClauses = new ArrayList<>(value);
+ serializeSorts();
+ return this;
+ }
+
+ /**
+ * Gets an a list of current sort clauses.
+ *
+ * @return an immutable list of current sort clauses
+ * @since 4.2
+ */
+ public List<SortClause> getSorts() {
+ if (sortClauses == null) return Collections.emptyList();
+ else return Collections.unmodifiableList(sortClauses);
+ }
+
+ /**
+ * Replaces the current sort information with a single sort clause
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery setSort(String field, ORDER order) {
+ return setSort(new SortClause(field, order));
+ }
+
+ /**
+ * Replaces the current sort information with a single sort clause
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery setSort(SortClause sortClause) {
+ clearSorts();
+ return addSort(sortClause);
+ }
+
+ /**
+ * Adds a single sort clause to the end of the current sort information.
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery addSort(String field, ORDER order) {
+ return addSort(new SortClause(field, order));
+ }
+
+ /**
+ * Adds a single sort clause to the end of the query.
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery addSort(SortClause sortClause) {
+ if (sortClauses == null) sortClauses = new ArrayList<>();
+ sortClauses.add(sortClause);
+ serializeSorts();
+ return this;
+ }
+
+ /**
+ * Updates or adds a single sort clause to the query.
+ * If the field is already used for sorting, the order
+ * of the existing field is modified; otherwise, it is
+ * added to the end.
+ * <p>
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery addOrUpdateSort(String field, ORDER order) {
+ return addOrUpdateSort(new SortClause(field, order));
+ }
+
+ /**
+ * Updates or adds a single sort field specification to the current sort
+ * information. If the sort field already exist in the sort information map,
+ * its position is unchanged and the sort order is set; if it does not exist,
+ * it is appended at the end with the specified order..
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery addOrUpdateSort(SortClause sortClause) {
+ if (sortClauses != null) {
+ for (int index=0 ; index<sortClauses.size() ; index++) {
+ SortClause existing = sortClauses.get(index);
+ if (existing.getItem().equals(sortClause.getItem())) {
+ sortClauses.set(index, sortClause);
+ serializeSorts();
+ return this;
+ }
+ }
+ }
+ return addSort(sortClause);
+ }
+
+ /**
+ * Removes a single sort field from the current sort information.
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery removeSort(SortClause sortClause) {
+ return removeSort(sortClause.getItem());
+ }
+
+ /**
+ * Removes a single sort field from the current sort information.
+ *
+ * @return the modified SolrQuery object, for easy chaining
+ * @since 4.2
+ */
+ public SolrQuery removeSort(String itemName) {
+ if (sortClauses != null) {
+ for (SortClause existing : sortClauses) {
+ if (existing.getItem().equals(itemName)) {
+ sortClauses.remove(existing);
+ if (sortClauses.isEmpty()) sortClauses = null;
+ serializeSorts();
+ break;
+ }
+ }
+ }
+ return this;
+ }
+
+ private void serializeSorts() {
+ if (sortClauses == null || sortClauses.isEmpty()) {
+ remove(CommonParams.SORT);
+ } else {
+ StringBuilder sb = new StringBuilder();
+ for (SortClause sortClause : sortClauses) {
+ if (sb.length() > 0) sb.append(",");
+ sb.append(sortClause.getItem());
+ sb.append(" ");
+ sb.append(sortClause.getOrder());
+ }
+ set(CommonParams.SORT, sb.toString());
+ }
+ }
+
+ public void setGetFieldStatistics( boolean v )
+ {
+ this.set( StatsParams.STATS, v );
+ }
+
+ public void setGetFieldStatistics( String field )
+ {
+ this.set( StatsParams.STATS, true );
+ this.add( StatsParams.STATS_FIELD, field );
+ }
+
+
+ public void addGetFieldStatistics( String ... field )
+ {
+ this.set( StatsParams.STATS, true );
+ this.add( StatsParams.STATS_FIELD, field );
+ }
+
+ public void addStatsFieldFacets( String field, String ... facets )
+ {
+ if( field == null ) {
+ this.add( StatsParams.STATS_FACET, facets );
+ }
+ else {
+ for( String f : facets ) {
+ this.add( "f."+field+"."+StatsParams.STATS_FACET, f );
+ }
+ }
+ }
+
+ public void addStatsFieldCalcDistinct(String field, boolean calcDistinct) {
+ if (field == null) {
+ this.add(StatsParams.STATS_CALC_DISTINCT, Boolean.toString(calcDistinct));
+ } else {
+ this.add("f." + field + "." + StatsParams.STATS_CALC_DISTINCT, Boolean.toString(calcDistinct));
+ }
+ }
+
+ public SolrQuery setFilterQueries(String ... fq) {
+ this.set(CommonParams.FQ, fq);
+ return this;
+ }
+
+ public SolrQuery addFilterQuery(String ... fq) {
+ this.add(CommonParams.FQ, fq);
+ return this;
+ }
+
+ public boolean removeFilterQuery(String fq) {
+ return this.remove(CommonParams.FQ, fq);
+ }
+
+ public String[] getFilterQueries() {
+ return this.getParams(CommonParams.FQ);
+ }
+
+ public boolean getHighlight() {
+ return this.getBool(HighlightParams.HIGHLIGHT, false);
+ }
+
+ public SolrQuery setHighlight(boolean b) {
+ if (b) {
+ this.set(HighlightParams.HIGHLIGHT, true);
+ } else {
+ this.remove(HighlightParams.HIGHLIGHT);
+ this.remove(HighlightParams.FIELD_MATCH);
+ this.remove(HighlightParams.FIELDS);
+ this.remove(HighlightParams.FORMATTER);
+ this.remove(HighlightParams.FRAGSIZE);
+ this.remove(HighlightParams.SIMPLE_POST);
+ this.remove(HighlightParams.SIMPLE_PRE);
+ this.remove(HighlightParams.SNIPPETS);
+ }
+ return this;
+ }
+
+ public SolrQuery setFields(String ... fields) {
+ if( fields == null || fields.length == 0 ) {
+ this.remove( CommonParams.FL );
+ return this;
+ }
+ StringBuilder sb = new StringBuilder();
+ sb.append( fields[0] );
+ for( int i=1; i<fields.length; i++ ) {
+ sb.append( ',' );
+ sb.append( fields[i] );
+ }
+ this.set(CommonParams.FL, sb.toString() );
+ return this;
+ }
+
+ public SolrQuery addField(String field) {
+ return addValueToParam(CommonParams.FL, field);
+ }
+
+ public String getFields() {
+ String fields = this.get(CommonParams.FL);
+ if (fields!=null && fields.equals("score")) {
+ fields = "*, score";
+ }
+ return fields;
+ }
+
+ private static Pattern scorePattern = Pattern.compile("(^|[, ])score");
+
+ public SolrQuery setIncludeScore(boolean includeScore) {
+ String fields = get(CommonParams.FL,"*");
+ if (includeScore) {
+ if (!scorePattern.matcher(fields).find()) {
+ this.set(CommonParams.FL, fields+",score");
+ }
+ } else {
+ this.set(CommonParams.FL, scorePattern.matcher(fields).replaceAll(""));
+ }
+ return this;
+ }
+
+ public SolrQuery setQuery(String query) {
+ this.set(CommonParams.Q, query);
+ return this;
+ }
+
+ public String getQuery() {
+ return this.get(CommonParams.Q);
+ }
+
+ public SolrQuery setRows(Integer rows) {
+ if( rows == null ) {
+ this.remove( CommonParams.ROWS );
+ }
+ else {
+ this.set(CommonParams.ROWS, rows);
+ }
+ return this;
+ }
+
+ public Integer getRows()
+ {
+ return this.getInt(CommonParams.ROWS);
+ }
+
+ public void setShowDebugInfo(boolean showDebugInfo) {
+ this.set(CommonParams.DEBUG_QUERY, String.valueOf(showDebugInfo));
+ }
+
+ public void setDistrib(boolean val) {
+ this.set(CommonParams.DISTRIB, String.valueOf(val));
+ }
+
+
+ public SolrQuery setStart(Integer start) {
+ if( start == null ) {
+ this.remove( CommonParams.START );
+ }
+ else {
+ this.set(CommonParams.START, start);
+ }
+ return this;
+ }
+
+ public Integer getStart()
+ {
+ return this.getInt(CommonParams.START);
+ }
+
+ /**
+ * The Request Handler to use (see the solrconfig.xml), which is stored in the "qt" parameter.
+ * Normally it starts with a '/' and if so it will be used by
+ * {@link org.apache.solr.client.solrj.request.QueryRequest#getPath()} in the URL instead of the "qt" parameter.
+ * If this is left blank, then the default of "/select" is assumed.
+ *
+ * @param qt The Request Handler name corresponding to one in solrconfig.xml on the server.
+ * @return this
+ */
+ public SolrQuery setRequestHandler(String qt) {
+ this.set(CommonParams.QT, qt);
+ return this;
+ }
+
+ public String getRequestHandler() {
+ return this.get(CommonParams.QT);
+ }
+
+ /**
+ * @return this
+ * @see ModifiableSolrParams#set(String,String[])
+ */
+ public SolrQuery setParam(String name, String ... values) {
+ this.set(name, values);
+ return this;
+ }
+
+ /**
+ * @return this
+ * @see org.apache.solr.common.params.ModifiableSolrParams#set(String, boolean)
+ */
+ public SolrQuery setParam(String name, boolean value) {
+ this.set(name, value);
+ return this;
+ }
+
+ /** get a deep copy of this object **/
+ public SolrQuery getCopy() {
+ SolrQuery q = new SolrQuery();
+ for (String name : this.getParameterNames()) {
+ q.setParam(name, this.getParams(name));
+ }
+ return q;
+ }
+
+ /**
+ * Set the maximum time allowed for this query. If the query takes more time
+ * than the specified milliseconds, a timeout occurs and partial (or no)
+ * results may be returned.
+ *
+ * If given Integer is null, then this parameter is removed from the request
+ *
+ *@param milliseconds the time in milliseconds allowed for this query
+ */
+ public SolrQuery setTimeAllowed(Integer milliseconds) {
+ if (milliseconds == null) {
+ this.remove(CommonParams.TIME_ALLOWED);
+ } else {
+ this.set(CommonParams.TIME_ALLOWED, milliseconds);
+ }
+ return this;
+ }
+
+ /**
+ * Get the maximum time allowed for this query.
+ */
+ public Integer getTimeAllowed() {
+ return this.getInt(CommonParams.TIME_ALLOWED);
+ }
+
+ ///////////////////////
+ // Utility functions
+ ///////////////////////
+
+ private String toSortString(String field, ORDER order) {
+ return field.trim() + ' ' + String.valueOf(order).trim();
+ }
+
+ private String join(String a, String b, String sep) {
+ StringBuilder sb = new StringBuilder();
+ if (a!=null && a.length()>0) {
+ sb.append(a);
+ sb.append(sep);
+ }
+ if (b!=null && b.length()>0) {
+ sb.append(b);
+ }
+ return sb.toString().trim();
+ }
+
+ private SolrQuery addValueToParam(String name, String value) {
+ String tmp = this.get(name);
+ tmp = join(tmp, value, ",");
+ this.set(name, tmp);
+ return this;
+ }
+
+ private String join(String[] vals, String sep, String removeVal) {
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i<vals.length; i++) {
+ if (!vals[i].equals(removeVal)) {
+ if (sb.length() > 0) {
+ sb.append(sep);
+ }
+ sb.append(vals[i]);
+ }
+ }
+ return sb.toString().trim();
+ }
+
+ /**
+ * A single sort clause, encapsulating what to sort and the sort order.
+ * <p>
+ * The item specified can be "anything sortable" by solr; some examples
+ * include a simple field name, the constant string {@code score}, and functions
+ * such as {@code sum(x_f, y_f)}.
+ * <p>
+ * A SortClause can be created through different mechanisms:
+ * <PRE><code>
+ * new SortClause("product", SolrQuery.ORDER.asc);
+ * new SortClause("product", "asc");
+ * SortClause.asc("product");
+ * SortClause.desc("product");
+ * </code></PRE>
+ */
+ public static class SortClause implements java.io.Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String item;
+ private final ORDER order;
+
+ /**
+ * Creates a SortClause based on item and order
+ * @param item item to sort on
+ * @param order direction to sort
+ */
+ public SortClause(String item, ORDER order) {
+ this.item = item;
+ this.order = order;
+ }
+
+ /**
+ * Creates a SortClause based on item and order
+ * @param item item to sort on
+ * @param order string value for direction to sort
+ */
+ public SortClause(String item, String order) {
+ this(item, ORDER.valueOf(order));
+ }
+
+ /**
+ * Creates an ascending SortClause for an item
+ * @param item item to sort on
+ */
+ public static SortClause create (String item, ORDER order) {
+ return new SortClause(item, order);
+ }
+
+ /**
+ * Creates a SortClause based on item and order
+ * @param item item to sort on
+ * @param order string value for direction to sort
+ */
+ public static SortClause create(String item, String order) {
+ return new SortClause(item, ORDER.valueOf(order));
+ }
+
+ /**
+ * Creates an ascending SortClause for an item
+ * @param item item to sort on
+ */
+ public static SortClause asc (String item) {
+ return new SortClause(item, ORDER.asc);
+ }
+
+ /**
+ * Creates a decending SortClause for an item
+ * @param item item to sort on
+ */
+ public static SortClause desc (String item) {
+ return new SortClause(item, ORDER.desc);
+ }
+
+ /**
+ * Gets the item to sort, typically a function or a fieldname
+ * @return item to sort
+ */
+ public String getItem() {
+ return item;
+ }
+
+ /**
+ * Gets the order to sort
+ * @return order to sort
+ */
+ public ORDER getOrder() {
+ return order;
+ }
+
+ public boolean equals(Object other){
+ if (this == other) return true;
+ if (!(other instanceof SortClause)) return false;
+ final SortClause that = (SortClause) other;
+ return this.getItem().equals(that.getItem()) && this.getOrder().equals(that.getOrder());
+ }
+
+ public int hashCode(){
+ return this.getItem().hashCode();
+ }
+
+ /**
+ * Gets a human readable description of the sort clause.
+ * <p>
+ * The returned string is not suitable for passing to Solr,
+ * but may be useful in debug output and the like.
+ * @return a description of the current sort clause
+ */
+ public String toString() {
+ return "[" + getClass().getSimpleName() + ": item=" + getItem() + "; order=" + getOrder() + "]";
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrRequest.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrRequest.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrRequest.java
new file mode 100644
index 0000000..6d4efb6
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrRequest.java
@@ -0,0 +1,137 @@
+/*
+ * 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;
+
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.ContentStream;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ *
+ *
+ * @since solr 1.3
+ */
+public abstract class SolrRequest<T extends SolrResponse> implements Serializable {
+
+ public enum METHOD {
+ GET,
+ POST,
+ PUT
+ };
+
+ private METHOD method = METHOD.GET;
+ private String path = null;
+
+ private ResponseParser responseParser;
+ private StreamingResponseCallback callback;
+ private Set<String> queryParams;
+
+ //---------------------------------------------------------
+ //---------------------------------------------------------
+
+ public SolrRequest( METHOD m, String path )
+ {
+ this.method = m;
+ this.path = path;
+ }
+
+ //---------------------------------------------------------
+ //---------------------------------------------------------
+
+ public METHOD getMethod() {
+ return method;
+ }
+ public void setMethod(METHOD method) {
+ this.method = method;
+ }
+
+ public String getPath() {
+ return path;
+ }
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ /**
+ *
+ * @return The {@link org.apache.solr.client.solrj.ResponseParser}
+ */
+ public ResponseParser getResponseParser() {
+ return responseParser;
+ }
+
+ /**
+ * Optionally specify how the Response should be parsed. Not all server implementations require a ResponseParser
+ * to be specified.
+ * @param responseParser The {@link org.apache.solr.client.solrj.ResponseParser}
+ */
+ public void setResponseParser(ResponseParser responseParser) {
+ this.responseParser = responseParser;
+ }
+
+ public StreamingResponseCallback getStreamingResponseCallback() {
+ return callback;
+ }
+
+ public void setStreamingResponseCallback(StreamingResponseCallback callback) {
+ this.callback = callback;
+ }
+
+ /**
+ * Parameter keys that are sent via the query string
+ */
+ public Set<String> getQueryParams() {
+ return this.queryParams;
+ }
+
+ public void setQueryParams(Set<String> queryParams) {
+ this.queryParams = queryParams;
+ }
+
+ public abstract SolrParams getParams();
+
+ public abstract Collection<ContentStream> getContentStreams() throws IOException;
+
+ /**
+ * Create a new SolrResponse to hold the response from the server
+ * @param client the {@link SolrClient} the request will be sent to
+ */
+ protected abstract T createResponse(SolrClient client);
+
+ /**
+ * Send this request to a {@link SolrClient} and return the response
+ * @param client the SolrClient to communicate with
+ * @return the response
+ * @throws SolrServerException if there is an error on the Solr server
+ * @throws IOException if there is a communication error
+ */
+ public final T process(SolrClient client) throws SolrServerException, IOException {
+ long startTime = TimeUnit.MILLISECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS);
+ T res = createResponse(client);
+ res.setResponse(client.request(this));
+ long endTime = TimeUnit.MILLISECONDS.convert(System.nanoTime(), TimeUnit.NANOSECONDS);
+ res.setElapsedTime(endTime - startTime);
+ return res;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrResponse.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrResponse.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrResponse.java
new file mode 100644
index 0000000..244a757
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrResponse.java
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.util.NamedList;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+
+
+/**
+ *
+ *
+ * @since solr 1.3
+ */
+public abstract class SolrResponse implements Serializable {
+ public abstract long getElapsedTime();
+
+ public abstract void setResponse(NamedList<Object> rsp);
+
+ public abstract void setElapsedTime(long elapsedTime);
+
+ public abstract NamedList<Object> getResponse();
+
+ public static byte[] serializable(SolrResponse response) {
+ try {
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ ObjectOutputStream outputStream = new ObjectOutputStream(byteStream);
+ outputStream.writeObject(response);
+ return byteStream.toByteArray();
+ } catch (Exception e) {
+ throw new SolrException(ErrorCode.SERVER_ERROR, e);
+ }
+ }
+
+ public static SolrResponse deserialize(byte[] bytes) {
+ try {
+ ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
+ ObjectInputStream inputStream = new ObjectInputStream(byteStream);
+ return (SolrResponse) inputStream.readObject();
+ } catch (Exception e) {
+ throw new SolrException(ErrorCode.SERVER_ERROR, e);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrServer.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrServer.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrServer.java
new file mode 100644
index 0000000..0238214
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrServer.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.client.solrj;
+
+/**
+ * @deprecated Use {@link org.apache.solr.client.solrj.SolrClient}
+ */
+@Deprecated
+public abstract class SolrServer extends SolrClient {
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrServerException.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrServerException.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrServerException.java
new file mode 100644
index 0000000..ed16a43
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/SolrServerException.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+/** Exception to catch all types of communication / parsing issues associated with talking to SOLR
+ *
+ *
+ * @since solr 1.3
+ */
+public class SolrServerException extends Exception {
+
+ private static final long serialVersionUID = -3371703521752000294L;
+
+ public SolrServerException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public SolrServerException(String message) {
+ super(message);
+ }
+
+ public SolrServerException(Throwable cause) {
+ super(cause);
+ }
+
+ public Throwable getRootCause() {
+ Throwable t = this;
+ 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/client/solrj/StreamingResponseCallback.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/StreamingResponseCallback.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/StreamingResponseCallback.java
new file mode 100644
index 0000000..2ba79c8
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/StreamingResponseCallback.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+import org.apache.solr.common.SolrDocument;
+
+/**
+ * A callback interface for streaming response
+ *
+ * @since solr 4.0
+ */
+public abstract class StreamingResponseCallback {
+ /*
+ * Called for each SolrDocument in the response
+ */
+ public abstract void streamSolrDocument( SolrDocument doc );
+
+ /*
+ * Called at the beginning of each DocList (and SolrDocumentList)
+ */
+ public abstract void streamDocListInfo( long numFound, long start, Float maxScore );
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/BindingException.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/BindingException.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/BindingException.java
new file mode 100644
index 0000000..cd10138
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/BindingException.java
@@ -0,0 +1,29 @@
+package org.apache.solr.client.solrj.beans;
+
+/*
+ * 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 BindingException extends RuntimeException {
+
+ public BindingException(String message) {
+ super(message);
+ }
+
+ public BindingException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/DocumentObjectBinder.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/DocumentObjectBinder.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/DocumentObjectBinder.java
new file mode 100644
index 0000000..bff6c6a
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/DocumentObjectBinder.java
@@ -0,0 +1,470 @@
+/*
+ * 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.beans;
+
+import org.apache.solr.common.SolrDocumentList;
+import org.apache.solr.common.SolrDocument;
+import org.apache.solr.common.SolrInputDocument;
+
+import java.lang.reflect.*;
+import java.util.*;
+import java.util.regex.Pattern;
+import java.util.concurrent.ConcurrentHashMap;
+import java.nio.ByteBuffer;
+
+/**
+ * A class to map objects to and from solr documents.
+ *
+ *
+ * @since solr 1.3
+ */
+public class DocumentObjectBinder {
+
+ private final Map<Class, List<DocField>> infocache = new ConcurrentHashMap<>();
+
+ public DocumentObjectBinder() {
+ }
+
+ public <T> List<T> getBeans(Class<T> clazz, SolrDocumentList solrDocList) {
+ List<DocField> fields = getDocFields(clazz);
+ List<T> result = new ArrayList<>(solrDocList.size());
+
+ for (SolrDocument sdoc : solrDocList) {
+ result.add(getBean(clazz, fields, sdoc));
+ }
+ return result;
+ }
+
+ public <T> T getBean(Class<T> clazz, SolrDocument solrDoc) {
+ return getBean(clazz, null, solrDoc);
+ }
+
+ private <T> T getBean(Class<T> clazz, List<DocField> fields, SolrDocument solrDoc) {
+ if (fields == null) {
+ fields = getDocFields(clazz);
+ }
+
+ try {
+ T obj = clazz.newInstance();
+ for (DocField docField : fields) {
+ docField.inject(obj, solrDoc);
+ }
+ return obj;
+ } catch (Exception e) {
+ throw new BindingException("Could not instantiate object of " + clazz, e);
+ }
+ }
+
+ public SolrInputDocument toSolrInputDocument(Object obj) {
+ List<DocField> fields = getDocFields(obj.getClass());
+ if (fields.isEmpty()) {
+ throw new BindingException("class: " + obj.getClass() + " does not define any fields.");
+ }
+
+ SolrInputDocument doc = new SolrInputDocument();
+ for (DocField field : fields) {
+ if (field.dynamicFieldNamePatternMatcher != null &&
+ field.get(obj) != null &&
+ field.isContainedInMap) {
+ Map<String, Object> mapValue = (Map<String, Object>) field.get(obj);
+
+ for (Map.Entry<String, Object> e : mapValue.entrySet()) {
+ doc.setField(e.getKey(), e.getValue(), 1.0f);
+ }
+ } else {
+ if (field.child != null) {
+ addChild(obj, field, doc);
+ } else {
+ doc.setField(field.name, field.get(obj), 1.0f);
+ }
+ }
+ }
+ return doc;
+ }
+
+ private void addChild(Object obj, DocField field, SolrInputDocument doc) {
+ Object val = field.get(obj);
+ if (val == null) return;
+ if (val instanceof Collection) {
+ Collection collection = (Collection) val;
+ for (Object o : collection) {
+ SolrInputDocument child = toSolrInputDocument(o);
+ doc.addChildDocument(child);
+ }
+ } else if (val.getClass().isArray()) {
+ Object[] objs = (Object[]) val;
+ for (Object o : objs) doc.addChildDocument(toSolrInputDocument(o));
+ } else {
+ doc.addChildDocument(toSolrInputDocument(val));
+ }
+ }
+
+ private List<DocField> getDocFields(Class clazz) {
+ List<DocField> fields = infocache.get(clazz);
+ if (fields == null) {
+ synchronized(infocache) {
+ infocache.put(clazz, fields = collectInfo(clazz));
+ }
+ }
+ return fields;
+ }
+
+ private List<DocField> collectInfo(Class clazz) {
+ List<DocField> fields = new ArrayList<>();
+ Class superClazz = clazz;
+ List<AccessibleObject> members = new ArrayList<>();
+
+ while (superClazz != null && superClazz != Object.class) {
+ members.addAll(Arrays.asList(superClazz.getDeclaredFields()));
+ members.addAll(Arrays.asList(superClazz.getDeclaredMethods()));
+ superClazz = superClazz.getSuperclass();
+ }
+ boolean childFieldFound = false;
+ for (AccessibleObject member : members) {
+ if (member.isAnnotationPresent(Field.class)) {
+ member.setAccessible(true);
+ DocField df = new DocField(member);
+ if (df.child != null) {
+ if (childFieldFound)
+ throw new BindingException(clazz.getName() + " cannot have more than one Field with child=true");
+ childFieldFound = true;
+ }
+ fields.add(df);
+ }
+ }
+ return fields;
+ }
+
+ private class DocField {
+ private Field annotation;
+ private String name;
+ private java.lang.reflect.Field field;
+ private Method setter;
+ private Method getter;
+ private Class type;
+ private boolean isArray;
+ private boolean isList;
+ private List<DocField> child;
+
+ /*
+ * dynamic fields may use a Map based data structure to bind a given field.
+ * if a mapping is done using, "Map<String, List<String>> foo", <code>isContainedInMap</code>
+ * is set to <code>TRUE</code> as well as <code>isList</code> is set to <code>TRUE</code>
+ */
+ private boolean isContainedInMap;
+ private Pattern dynamicFieldNamePatternMatcher;
+
+ public DocField(AccessibleObject member) {
+ if (member instanceof java.lang.reflect.Field) {
+ field = (java.lang.reflect.Field) member;
+ } else {
+ setter = (Method) member;
+ }
+ annotation = member.getAnnotation(Field.class);
+ storeName(annotation);
+ storeType();
+
+ // Look for a matching getter
+ if (setter != null) {
+ String gname = setter.getName();
+ if (gname.startsWith("set")) {
+ gname = "get" + gname.substring(3);
+ try {
+ getter = setter.getDeclaringClass().getMethod(gname, (Class[]) null);
+ } catch (Exception ex) {
+ // no getter -- don't worry about it...
+ if (type == Boolean.class) {
+ gname = "is" + setter.getName().substring(3);
+ try {
+ getter = setter.getDeclaringClass().getMethod(gname, (Class[]) null);
+ } catch(Exception ex2) {
+ // no getter -- don't worry about it...
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void storeName(Field annotation) {
+ if (annotation.value().equals(DEFAULT)) {
+ if (field != null) {
+ name = field.getName();
+ } else {
+ String setterName = setter.getName();
+ if (setterName.startsWith("set") && setterName.length() > 3) {
+ name = setterName.substring(3, 4).toLowerCase(Locale.ROOT) + setterName.substring(4);
+ } else {
+ name = setter.getName();
+ }
+ }
+ } else if (annotation.value().indexOf('*') >= 0) { //dynamic fields are annotated as @Field("categories_*")
+ //if the field was annotated as a dynamic field, convert the name into a pattern
+ //the wildcard (*) is supposed to be either a prefix or a suffix, hence the use of replaceFirst
+ name = annotation.value().replaceFirst("\\*", "\\.*");
+ dynamicFieldNamePatternMatcher = Pattern.compile("^"+name+"$");
+ } else {
+ name = annotation.value();
+ }
+ }
+
+ private void storeType() {
+ if (field != null) {
+ type = field.getType();
+ } else {
+ Class[] params = setter.getParameterTypes();
+ if (params.length != 1) {
+ throw new BindingException("Invalid setter method. Must have one and only one parameter");
+ }
+ type = params[0];
+ }
+
+ if (type == Collection.class || type == List.class || type == ArrayList.class) {
+ isList = true;
+ if (annotation.child()) {
+ populateChild(field.getGenericType());
+ } else {
+ type = Object.class;
+ }
+ } else if (type == byte[].class) {
+ //no op
+ } else if (type.isArray()) {
+ isArray = true;
+ if (annotation.child()) {
+ populateChild(type.getComponentType());
+ } else {
+ type = type.getComponentType();
+ }
+ } else if (type == Map.class || type == HashMap.class) { //corresponding to the support for dynamicFields
+ if (annotation.child()) throw new BindingException("Map should is not a valid type for a child document");
+ isContainedInMap = true;
+ //assigned a default type
+ type = Object.class;
+ if (field != null) {
+ if (field.getGenericType() instanceof ParameterizedType) {
+ //check what are the generic values
+ ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();
+ Type[] types = parameterizedType.getActualTypeArguments();
+ if (types != null && types.length == 2 && types[0] == String.class) {
+ //the key should always be String
+ //Raw and primitive types
+ if (types[1] instanceof Class) {
+ //the value could be multivalued then it is a List, Collection, ArrayList
+ if (types[1] == Collection.class || types[1] == List.class || types[1] == ArrayList.class) {
+ type = Object.class;
+ isList = true;
+ } else {
+ //else assume it is a primitive and put in the source type itself
+ type = (Class) types[1];
+ }
+ } else if (types[1] instanceof ParameterizedType) { //Of all the Parameterized types, only List is supported
+ Type rawType = ((ParameterizedType) types[1]).getRawType();
+ if (rawType == Collection.class || rawType == List.class || rawType == ArrayList.class) {
+ type = Object.class;
+ isList = true;
+ }
+ } else if (types[1] instanceof GenericArrayType) { //Array types
+ type = (Class) ((GenericArrayType) types[1]).getGenericComponentType();
+ isArray = true;
+ } else { //Throw an Exception if types are not known
+ throw new BindingException("Allowed type for values of mapping a dynamicField are : " +
+ "Object, Object[] and List");
+ }
+ }
+ }
+ }
+ } else {
+ if (annotation.child()) {
+ populateChild(type);
+ }
+ }
+ }
+
+ private void populateChild(Type typ) {
+ if (typ == null) {
+ throw new RuntimeException("no type information available for" + (field == null ? setter : field));
+ }
+ if (typ.getClass() == Class.class) {//of type class
+ type = (Class) typ;
+ } else if (typ instanceof ParameterizedType) {
+ type = (Class) ((ParameterizedType) typ).getActualTypeArguments()[0];
+ } else {
+ throw new BindingException("Invalid type information available for" + (field == null ? setter : field));
+
+ }
+ child = getDocFields(type);
+ }
+
+ /**
+ * Called by the {@link #inject} method to read the value(s) for a field
+ * This method supports reading of all "matching" fieldName's in the <code>SolrDocument</code>
+ *
+ * Returns <code>SolrDocument.getFieldValue</code> for regular fields,
+ * and <code>Map<String, List<Object>></code> for a dynamic field. The key is all matching fieldName's.
+ */
+ @SuppressWarnings("unchecked")
+ private Object getFieldValue(SolrDocument solrDocument) {
+ if (child != null) {
+ List<SolrDocument> children = solrDocument.getChildDocuments();
+ if (children == null || children.isEmpty()) return null;
+ if (isList) {
+ ArrayList list = new ArrayList(children.size());
+ for (SolrDocument c : children) {
+ list.add(getBean(type, child, c));
+ }
+ return list;
+ } else if (isArray) {
+ Object[] arr = (Object[]) Array.newInstance(type, children.size());
+ for (int i = 0; i < children.size(); i++) {
+ arr[i] = getBean(type, child, children.get(i));
+ }
+ return arr;
+
+ } else {
+ return getBean(type, child, children.get(0));
+ }
+ }
+ Object fieldValue = solrDocument.getFieldValue(name);
+ if (fieldValue != null) {
+ //this is not a dynamic field. so return the value
+ return fieldValue;
+ }
+
+ if (dynamicFieldNamePatternMatcher == null) {
+ return null;
+ }
+
+ //reading dynamic field values
+ Map<String, Object> allValuesMap = null;
+ List allValuesList = null;
+ if (isContainedInMap) {
+ allValuesMap = new HashMap<>();
+ } else {
+ allValuesList = new ArrayList();
+ }
+
+ for (String field : solrDocument.getFieldNames()) {
+ if (dynamicFieldNamePatternMatcher.matcher(field).find()) {
+ Object val = solrDocument.getFieldValue(field);
+ if (val == null) {
+ continue;
+ }
+
+ if (isContainedInMap) {
+ if (isList) {
+ if (!(val instanceof List)) {
+ List al = new ArrayList();
+ al.add(val);
+ val = al;
+ }
+ } else if (isArray) {
+ if (!(val instanceof List)) {
+ Object[] arr = (Object[]) Array.newInstance(type, 1);
+ arr[0] = val;
+ val = arr;
+ } else {
+ val = Array.newInstance(type, ((List) val).size());
+ }
+ }
+ allValuesMap.put(field, val);
+ } else {
+ if (val instanceof Collection) {
+ allValuesList.addAll((Collection) val);
+ } else {
+ allValuesList.add(val);
+ }
+ }
+ }
+ }
+ if (isContainedInMap) {
+ return allValuesMap.isEmpty() ? null : allValuesMap;
+ } else {
+ return allValuesList.isEmpty() ? null : allValuesList;
+ }
+ }
+
+ <T> void inject(T obj, SolrDocument sdoc) {
+ Object val = getFieldValue(sdoc);
+ if(val == null) {
+ return;
+ }
+
+ if (isArray && !isContainedInMap) {
+ List list;
+ if (val.getClass().isArray()) {
+ set(obj, val);
+ return;
+ } else if (val instanceof List) {
+ list = (List) val;
+ } else {
+ list = new ArrayList();
+ list.add(val);
+ }
+ set(obj, list.toArray((Object[]) Array.newInstance(type, list.size())));
+ } else if (isList && !isContainedInMap) {
+ if (!(val instanceof List)) {
+ List list = new ArrayList();
+ list.add(val);
+ val = list;
+ }
+ set(obj, val);
+ } else if (isContainedInMap) {
+ if (val instanceof Map) {
+ set(obj, val);
+ }
+ } else {
+ set(obj, val);
+ }
+
+ }
+
+ private void set(Object obj, Object v) {
+ if (v != null && type == ByteBuffer.class && v.getClass() == byte[].class) {
+ v = ByteBuffer.wrap((byte[]) v);
+ }
+ try {
+ if (field != null) {
+ field.set(obj, v);
+ } else if (setter != null) {
+ setter.invoke(obj, v);
+ }
+ }
+ catch (Exception e) {
+ throw new BindingException("Exception while setting value : " + v + " on " + (field != null ? field : setter), e);
+ }
+ }
+
+ public Object get(final Object obj) {
+ if (field != null) {
+ try {
+ return field.get(obj);
+ } catch (Exception e) {
+ throw new BindingException("Exception while getting value: " + field, e);
+ }
+ } else if (getter == null) {
+ throw new BindingException("Missing getter for field: " + name + " -- You can only call the 'get' for fields that have a field of 'get' method");
+ }
+
+ try {
+ return getter.invoke(obj, (Object[]) null);
+ } catch (Exception e) {
+ throw new BindingException("Exception while getting value: " + getter, e);
+ }
+ }
+ }
+ public static final String DEFAULT = "#default";
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/Field.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/Field.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/Field.java
new file mode 100644
index 0000000..39f6752
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/Field.java
@@ -0,0 +1,38 @@
+/*
+ * 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.beans;
+
+import static java.lang.annotation.ElementType.*;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import static org.apache.solr.client.solrj.beans.DocumentObjectBinder.DEFAULT;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+
+
+/**
+ * This class can be used to annotate a field or a setter an any class
+ * and SlrJ would help you convert to SolrInputDocument and from SolrDocument
+ *
+ * @since solr 1.3
+ */
+@Target({FIELD, METHOD})
+@Retention(RUNTIME)
+public @interface Field {
+ boolean child() default false;
+ String value() default DEFAULT;
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/package-info.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/package-info.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/package-info.java
new file mode 100644
index 0000000..890005f
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/beans/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.
+ */
+
+/**
+ * Annotation based mapping of client objects to Solr documents.
+ */
+package org.apache.solr.client.solrj.beans;
+
+
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java
new file mode 100644
index 0000000..67274c2
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/impl/BinaryRequestWriter.java
@@ -0,0 +1,120 @@
+/*
+ * 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.impl;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.request.JavaBinUpdateRequestCodec;
+import org.apache.solr.client.solrj.request.RequestWriter;
+import org.apache.solr.client.solrj.request.UpdateRequest;
+import org.apache.solr.common.util.ContentStream;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A RequestWriter which writes requests in the javabin format
+ *
+ *
+ * @see org.apache.solr.client.solrj.request.RequestWriter
+ * @since solr 1.4
+ */
+public class BinaryRequestWriter extends RequestWriter {
+
+ @Override
+ public Collection<ContentStream> getContentStreams(SolrRequest req) throws IOException {
+ if (req instanceof UpdateRequest) {
+ UpdateRequest updateRequest = (UpdateRequest) req;
+ if (isNull(updateRequest.getDocuments()) &&
+ isNull(updateRequest.getDeleteByIdMap()) &&
+ isNull(updateRequest.getDeleteQuery())
+ && (updateRequest.getDocIterator() == null) ) {
+ return null;
+ }
+ List<ContentStream> l = new ArrayList<>();
+ l.add(new LazyContentStream(updateRequest));
+ return l;
+ } else {
+ return super.getContentStreams(req);
+ }
+
+ }
+
+
+ @Override
+ public String getUpdateContentType() {
+ return "application/javabin";
+ }
+
+ @Override
+ public ContentStream getContentStream(final UpdateRequest request) throws IOException {
+ final BAOS baos = new BAOS();
+ new JavaBinUpdateRequestCodec().marshal(request, baos);
+
+ return new ContentStream() {
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public String getSourceInfo() {
+ return "javabin";
+ }
+
+ @Override
+ public String getContentType() {
+ return "application/javabin";
+ }
+
+ @Override
+ public Long getSize() // size if we know it, otherwise null
+ {
+ return new Long(baos.size());
+ }
+
+ @Override
+ public InputStream getStream() {
+ return new ByteArrayInputStream(baos.getbuf(), 0, baos.size());
+ }
+
+ @Override
+ public Reader getReader() {
+ throw new RuntimeException("No reader available . this is a binarystream");
+ }
+ };
+ }
+
+
+ @Override
+ public void write(SolrRequest request, OutputStream os) throws IOException {
+ if (request instanceof UpdateRequest) {
+ UpdateRequest updateRequest = (UpdateRequest) request;
+ new JavaBinUpdateRequestCodec().marshal(updateRequest, os);
+ }
+ }
+
+ /*
+ * A hack to get access to the protected internal buffer and avoid an additional copy
+ */
+ class BAOS extends ByteArrayOutputStream {
+ byte[] getbuf() {
+ return super.buf;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/impl/BinaryResponseParser.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/impl/BinaryResponseParser.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/impl/BinaryResponseParser.java
new file mode 100644
index 0000000..4f3caf1
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/impl/BinaryResponseParser.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl;
+
+import org.apache.solr.client.solrj.ResponseParser;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.JavaBinCodec;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ *
+ * @since solr 1.3
+ */
+public class BinaryResponseParser extends ResponseParser {
+ public static final String BINARY_CONTENT_TYPE = "application/octet-stream";
+
+ @Override
+ public String getWriterType() {
+ return "javabin";
+ }
+
+ @Override
+ public NamedList<Object> processResponse(InputStream body, String encoding) {
+ try {
+ return (NamedList<Object>) new JavaBinCodec().unmarshal(body);
+ } catch (IOException e) {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "parsing error", e);
+
+ }
+ }
+
+ @Override
+ public String getContentType() {
+ return BINARY_CONTENT_TYPE;
+ }
+
+ @Override
+ public String getVersion() {
+ return "2";
+ }
+
+ @Override
+ public NamedList<Object> processResponse(Reader reader) {
+ throw new RuntimeException("Cannot handle character stream");
+ }
+}