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:33 UTC

[11/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/request/FieldAnalysisRequest.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/FieldAnalysisRequest.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/FieldAnalysisRequest.java
new file mode 100644
index 0000000..66ef535
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/FieldAnalysisRequest.java
@@ -0,0 +1,270 @@
+/*
+ * 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.request;
+
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.response.FieldAnalysisResponse;
+import org.apache.solr.common.params.AnalysisParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.ContentStream;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * A request for the org.apache.solr.handler.FieldAnalysisRequestHandler.
+ *
+ *
+ * @since solr.14
+ */
+public class FieldAnalysisRequest extends SolrRequest<FieldAnalysisResponse> {
+
+  private String fieldValue;
+  private String query;
+  private boolean showMatch;
+  private List<String> fieldNames;
+  private List<String> fieldTypes;
+
+  /**
+   * Constructs a new FieldAnalysisRequest with a default uri of "/fieldanalysis".
+   */
+  public FieldAnalysisRequest() {
+    super(METHOD.GET, "/analysis/field");
+  }
+
+  /**
+   * Constructs a new FieldAnalysisRequest with a given uri.
+   *
+   * @param uri the uri of the request handler.
+   */
+  public FieldAnalysisRequest(String uri) {
+    super(METHOD.GET, uri);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public Collection<ContentStream> getContentStreams() throws IOException {
+    return null;
+  }
+
+  @Override
+  protected FieldAnalysisResponse createResponse(SolrClient client) {
+    if (fieldTypes == null && fieldNames == null) {
+      throw new IllegalStateException("At least one field type or field name need to be specified");
+    }
+    if (fieldValue == null) {
+      throw new IllegalStateException("The field value must be set");
+    }
+    return new FieldAnalysisResponse();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public SolrParams getParams() {
+    ModifiableSolrParams params = new ModifiableSolrParams();
+    params.set(AnalysisParams.FIELD_VALUE, fieldValue);
+    if (query != null) {
+      params.add(AnalysisParams.QUERY, query);
+      params.add(AnalysisParams.SHOW_MATCH, String.valueOf(showMatch));
+    }
+    if (fieldNames != null) {
+      String fieldNameValue = listToCommaDelimitedString(fieldNames);
+      params.add(AnalysisParams.FIELD_NAME, fieldNameValue);
+    }
+    if (fieldTypes != null) {
+      String fieldTypeValue = listToCommaDelimitedString(fieldTypes);
+      params.add(AnalysisParams.FIELD_TYPE, fieldTypeValue);
+    }
+    return params;
+  }
+
+  //================================================ Helper Methods ==================================================
+
+  /**
+   * Convers the given list of string to a comma-separated string.
+   *
+   * @param list The list of string.
+   *
+   * @return The comma-separated string.
+   */
+  static String listToCommaDelimitedString(List<String> list) {
+    StringBuilder result = new StringBuilder();
+    for (String str : list) {
+      if (result.length() > 0) {
+        result.append(",");
+      }
+      result.append(str);
+    }
+    return result.toString();
+  }
+
+
+  //============================================ Setter/Getter Methods ===============================================
+
+  /**
+   * Sets the field value to be analyzed.
+   *
+   * @param fieldValue The field value to be analyzed.
+   *
+   * @return This FieldAnalysisRequest (fluent interface support).
+   */
+  public FieldAnalysisRequest setFieldValue(String fieldValue) {
+    this.fieldValue = fieldValue;
+    return this;
+  }
+
+  /**
+   * Returns the field value that will be analyzed when this request is processed.
+   *
+   * @return The field value that will be analyzed when this request is processed.
+   */
+  public String getFieldValue() {
+    return fieldValue;
+  }
+
+  /**
+   * Sets the query to be analyzed. May be {@code null} indicated that no query analysis should take place.
+   *
+   * @param query The query to be analyzed.
+   *
+   * @return This FieldAnalysisRequest (fluent interface support).
+   */
+  public FieldAnalysisRequest setQuery(String query) {
+    this.query = query;
+    return this;
+  }
+
+  /**
+   * Returns the query that will be analyzed. May return {@code null} indicating that no query analysis will be
+   * performed.
+   *
+   * @return The query that will be analyzed. May return {@code null} indicating that no query analysis will be
+   *         performed.
+   */
+  public String getQuery() {
+    return query;
+  }
+
+  /**
+   * Sets whether index time tokens that match query time tokens should be marked as a "match". By default this is set
+   * to {@code false}. Obviously, this flag is ignored if when the query is set to {@code null}.
+   *
+   * @param showMatch Sets whether index time tokens that match query time tokens should be marked as a "match".
+   *
+   * @return This FieldAnalysisRequest (fluent interface support).
+   */
+  public FieldAnalysisRequest setShowMatch(boolean showMatch) {
+    this.showMatch = showMatch;
+    return this;
+  }
+
+  /**
+   * Returns whether index time tokens that match query time tokens should be marked as a "match".
+   *
+   * @return Whether index time tokens that match query time tokens should be marked as a "match".
+   *
+   * @see #setShowMatch(boolean)
+   */
+  public boolean isShowMatch() {
+    return showMatch;
+  }
+
+  /**
+   * Adds the given field name for analysis.
+   *
+   * @param fieldName A field name on which the analysis should be performed.
+   *
+   * @return this FieldAnalysisRequest (fluent interface support).
+   */
+  public FieldAnalysisRequest addFieldName(String fieldName) {
+    if (fieldNames == null) {
+      fieldNames = new LinkedList<>();
+    }
+    fieldNames.add(fieldName);
+    return this;
+  }
+
+  /**
+     * Sets the field names on which the analysis should be performed.
+     *
+     * @param fieldNames The field names on which the analysis should be performed.
+     *
+     * @return this FieldAnalysisRequest (fluent interface support).
+     */
+  public FieldAnalysisRequest setFieldNames(List<String> fieldNames) {
+    this.fieldNames = fieldNames;
+    return this;
+  }
+
+  /**
+   * Returns a list of field names the analysis should be performed on. May return {@code null} indicating that no
+   * analysis will be performed on field names.
+   *
+   * @return The field names the analysis should be performed on.
+   */
+  public List<String> getFieldNames() {
+    return fieldNames;
+  }
+
+  /**
+   * Adds the given field type for analysis.
+   *
+   * @param fieldTypeName A field type name on which analysis should be performed.
+   *
+   * @return This FieldAnalysisRequest (fluent interface support).
+   */
+  public FieldAnalysisRequest addFieldType(String fieldTypeName) {
+    if (fieldTypes == null) {
+      fieldTypes = new LinkedList<>();
+    }
+    fieldTypes.add(fieldTypeName);
+    return this;
+  }
+
+/**
+   * Sets the field types on which analysis should be performed.
+   *
+   * @param fieldTypes The field type names on which analysis should be performed.
+   *
+   * @return This FieldAnalysisRequest (fluent interface support).
+   */
+  public FieldAnalysisRequest setFieldTypes(List<String> fieldTypes) {
+    this.fieldTypes = fieldTypes;
+    return this;
+  }
+
+
+  /**
+   * Returns a list of field types the analysis should be performed on. May return {@code null} indicating that no
+   * analysis will be peformed on field types.
+   *
+   * @return The field types the analysis should be performed on.
+   */
+  public List<String> getFieldTypes() {
+    return fieldTypes;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/IsUpdateRequest.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/IsUpdateRequest.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/IsUpdateRequest.java
new file mode 100644
index 0000000..ec49e30
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/IsUpdateRequest.java
@@ -0,0 +1,26 @@
+package org.apache.solr.client.solrj.request;
+
+/*
+ * 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.
+ */
+
+
+/**
+ * Marker class so that we can determine which requests are updates.
+ */
+public interface IsUpdateRequest {
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/JavaBinUpdateRequestCodec.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/JavaBinUpdateRequestCodec.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/JavaBinUpdateRequestCodec.java
new file mode 100644
index 0000000..7bb64b4
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/JavaBinUpdateRequestCodec.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.request;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.DataInputInputStream;
+import org.apache.solr.common.util.JavaBinCodec;
+import org.apache.solr.common.util.NamedList;
+
+/**
+ * Provides methods for marshalling an UpdateRequest to a NamedList which can be serialized in the javabin format and
+ * vice versa.
+ *
+ *
+ * @see org.apache.solr.common.util.JavaBinCodec
+ * @since solr 1.4
+ */
+public class JavaBinUpdateRequestCodec {
+
+  /**
+   * Converts an UpdateRequest to a NamedList which can be serialized to the given OutputStream in the javabin format
+   *
+   * @param updateRequest the UpdateRequest to be written out
+   * @param os            the OutputStream to which the request is to be written
+   *
+   * @throws IOException in case of an exception during marshalling or writing to the stream
+   */
+  public void marshal(UpdateRequest updateRequest, OutputStream os) throws IOException {
+    NamedList nl = new NamedList();
+    NamedList params = solrParamsToNamedList(updateRequest.getParams());
+    if (updateRequest.getCommitWithin() != -1) {
+      params.add("commitWithin", updateRequest.getCommitWithin());
+    }
+    Iterator<SolrInputDocument> docIter = null;
+
+    if(updateRequest.getDocIterator() != null){
+      docIter = updateRequest.getDocIterator();
+    }
+    
+    Map<SolrInputDocument,Map<String,Object>> docMap = updateRequest.getDocumentsMap();
+
+    nl.add("params", params);// 0: params
+    if (updateRequest.getDeleteByIdMap() != null) {
+      nl.add("delByIdMap", updateRequest.getDeleteByIdMap());
+    }
+    nl.add("delByQ", updateRequest.getDeleteQuery());
+
+    if (docMap != null) {
+      nl.add("docsMap", docMap.entrySet().iterator());
+    } else {
+      if (updateRequest.getDocuments() != null) {
+        docIter = updateRequest.getDocuments().iterator();
+      }
+      nl.add("docs", docIter);
+    }
+    JavaBinCodec codec = new JavaBinCodec();
+    codec.marshal(nl, os);
+  }
+
+  /**
+   * Reads a NamedList from the given InputStream, converts it into a SolrInputDocument and passes it to the given
+   * StreamingUpdateHandler
+   *
+   * @param is      the InputStream from which to read
+   * @param handler an instance of StreamingUpdateHandler to which SolrInputDocuments are streamed one by one
+   *
+   * @return the UpdateRequest
+   *
+   * @throws IOException in case of an exception while reading from the input stream or unmarshalling
+   */
+  public UpdateRequest unmarshal(InputStream is, final StreamingUpdateHandler handler) throws IOException {
+    final UpdateRequest updateRequest = new UpdateRequest();
+    List<List<NamedList>> doclist;
+    List<Entry<SolrInputDocument,Map<Object,Object>>>  docMap;
+    List<String> delById;
+    Map<String,Map<String,Object>> delByIdMap;
+    List<String> delByQ;
+    final NamedList[] namedList = new NamedList[1];
+    JavaBinCodec codec = new JavaBinCodec() {
+
+      // NOTE: this only works because this is an anonymous inner class 
+      // which will only ever be used on a single stream -- if this class 
+      // is ever refactored, this will not work.
+      private boolean seenOuterMostDocIterator = false;
+        
+      @Override
+      public NamedList readNamedList(DataInputInputStream dis) throws IOException {
+        int sz = readSize(dis);
+        NamedList nl = new NamedList();
+        if (namedList[0] == null) {
+          namedList[0] = nl;
+        }
+        for (int i = 0; i < sz; i++) {
+          String name = (String) readVal(dis);
+          Object val = readVal(dis);
+          nl.add(name, val);
+        }
+        return nl;
+      }
+
+      @Override
+      public List readIterator(DataInputInputStream fis) throws IOException {
+
+        // default behavior for reading any regular Iterator in the stream
+        if (seenOuterMostDocIterator) return super.readIterator(fis);
+
+        // special treatment for first outermost Iterator 
+        // (the list of documents)
+        seenOuterMostDocIterator = true;
+        return readOuterMostDocIterator(fis);
+      }
+
+      private List readOuterMostDocIterator(DataInputInputStream fis) throws IOException {
+        NamedList params = (NamedList) namedList[0].get("params");
+        updateRequest.setParams(new ModifiableSolrParams(SolrParams.toSolrParams(params)));
+        if (handler == null) return super.readIterator(fis);
+        Integer commitWithin = null;
+        Boolean overwrite = null;
+        while (true) {
+          Object o = readVal(fis);
+          if (o == END_OBJ) break;
+          SolrInputDocument sdoc = null;
+          if (o instanceof List) {
+            sdoc = listToSolrInputDocument((List<NamedList>) o);
+          } else if (o instanceof NamedList)  {
+            UpdateRequest req = new UpdateRequest();
+            req.setParams(new ModifiableSolrParams(SolrParams.toSolrParams((NamedList) o)));
+            handler.update(null, req, null, null);
+          } else if (o instanceof Map.Entry){
+            sdoc = (SolrInputDocument) ((Map.Entry) o).getKey();
+            Map p = (Map) ((Map.Entry) o).getValue();
+            if (p != null) {
+              commitWithin = (Integer) p.get(UpdateRequest.COMMIT_WITHIN);
+              overwrite = (Boolean) p.get(UpdateRequest.OVERWRITE);
+            }
+          } else  {
+          
+            sdoc = (SolrInputDocument) o;
+          }
+          handler.update(sdoc, updateRequest, commitWithin, overwrite);
+        }
+        return Collections.EMPTY_LIST;
+      }
+
+    };
+
+    codec.unmarshal(is);
+    
+    // NOTE: if the update request contains only delete commands the params
+    // must be loaded now
+    if(updateRequest.getParams()==null) {
+      NamedList params = (NamedList) namedList[0].get("params");
+      if(params!=null) {
+        updateRequest.setParams(new ModifiableSolrParams(SolrParams.toSolrParams(params)));
+      }
+    }
+    delById = (List<String>) namedList[0].get("delById");
+    delByIdMap = (Map<String,Map<String,Object>>) namedList[0].get("delByIdMap");
+    delByQ = (List<String>) namedList[0].get("delByQ");
+    doclist = (List) namedList[0].get("docs");
+    Object docsMapObj = namedList[0].get("docsMap");
+
+    if (docsMapObj instanceof Map) {//SOLR-5762
+      docMap =  new ArrayList(((Map)docsMapObj).entrySet());
+    } else {
+      docMap = (List<Entry<SolrInputDocument, Map<Object, Object>>>) docsMapObj;
+    }
+    
+
+    // we don't add any docs, because they were already processed
+    // deletes are handled later, and must be passed back on the UpdateRequest
+    
+    if (delById != null) {
+      for (String s : delById) {
+        updateRequest.deleteById(s);
+      }
+    }
+    if (delByIdMap != null) {
+      for (Map.Entry<String,Map<String,Object>> entry : delByIdMap.entrySet()) {
+        Map<String,Object> params = entry.getValue();
+        if (params != null) {
+          Long version = (Long) params.get(UpdateRequest.VER);
+          if (params.containsKey(UpdateRequest.ROUTE))
+            updateRequest.deleteById(entry.getKey(), (String) params.get(UpdateRequest.ROUTE));
+          else
+          updateRequest.deleteById(entry.getKey(), version);
+        } else {
+          updateRequest.deleteById(entry.getKey());
+        }
+  
+      }
+    }
+    if (delByQ != null) {
+      for (String s : delByQ) {
+        updateRequest.deleteByQuery(s);
+      }
+    }
+    
+    return updateRequest;
+  }
+
+  private SolrInputDocument listToSolrInputDocument(List<NamedList> namedList) {
+    SolrInputDocument doc = new SolrInputDocument();
+    for (int i = 0; i < namedList.size(); i++) {
+      NamedList nl = namedList.get(i);
+      if (i == 0) {
+        doc.setDocumentBoost(nl.getVal(0) == null ? 1.0f : (Float) nl.getVal(0));
+      } else {
+        doc.addField((String) nl.getVal(0),
+                nl.getVal(1),
+                nl.getVal(2) == null ? 1.0f : (Float) nl.getVal(2));
+      }
+    }
+    return doc;
+  }
+
+  private NamedList solrParamsToNamedList(SolrParams params) {
+    if (params == null) return new NamedList();
+    return params.toNamedList();
+  }
+
+  public static interface StreamingUpdateHandler {
+    public void update(SolrInputDocument document, UpdateRequest req, Integer commitWithin, Boolean override);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/LukeRequest.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/LukeRequest.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/LukeRequest.java
new file mode 100644
index 0000000..82b5330
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/LukeRequest.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.request;
+
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.response.LukeResponse;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.ContentStream;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 
+ *
+ * @since solr 1.3
+ */
+public class LukeRequest extends SolrRequest<LukeResponse> {
+
+  private List<String> fields;
+  private int numTerms = -1;
+  private boolean showSchema = false;
+  
+  public LukeRequest()
+  {
+    super( METHOD.GET, "/admin/luke" );
+  }
+
+  public LukeRequest( String path )
+  {
+    super( METHOD.GET, path );
+  }
+
+  //---------------------------------------------------------------------------------
+  //---------------------------------------------------------------------------------
+  
+  public void addField( String f )
+  {
+    if( fields == null ) {
+      fields = new ArrayList<>();
+    }
+    fields.add( f );
+  }
+
+  public void setFields( List<String> f )
+  {
+    fields = f;
+  }
+  
+  //---------------------------------------------------------------------------------
+  //---------------------------------------------------------------------------------
+  
+  public boolean isShowSchema() {
+    return showSchema;
+  }
+
+  public void setShowSchema(boolean showSchema) {
+    this.showSchema = showSchema;
+  }
+
+  public int getNumTerms() {
+    return numTerms;
+  }
+
+  /**
+   * the number of terms to return for a given field.  If the number is 0, it will not traverse the terms.  
+   */
+  public void setNumTerms(int count) {
+    this.numTerms = count;
+  }
+
+  //---------------------------------------------------------------------------------
+  //---------------------------------------------------------------------------------
+  
+  @Override
+  public Collection<ContentStream> getContentStreams() {
+    return null;
+  }
+
+  @Override
+  protected LukeResponse createResponse(SolrClient client) {
+    return new LukeResponse();
+  }
+
+  @Override
+  public SolrParams getParams() {
+    ModifiableSolrParams params = new ModifiableSolrParams();
+    if( fields != null && fields.size() > 0 ) {
+      params.add( CommonParams.FL, fields.toArray( new String[fields.size()] ) );
+    }
+    if( numTerms >= 0 ) {
+      params.add( "numTerms", numTerms+"" );
+    }
+    if (showSchema) {
+      params.add("show", "schema");
+    }
+    return params;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/QueryRequest.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/QueryRequest.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/QueryRequest.java
new file mode 100644
index 0000000..9d47f99
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/QueryRequest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.request;
+
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.response.QueryResponse;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.ContentStream;
+
+import java.util.Collection;
+
+/**
+ * 
+ *
+ * @since solr 1.3
+ */
+public class QueryRequest extends SolrRequest<QueryResponse> {
+
+  private SolrParams query;
+  
+  public QueryRequest()
+  {
+    super( METHOD.GET, null );
+  }
+
+  public QueryRequest( SolrParams q )
+  {
+    super( METHOD.GET, null );
+    query = q;
+  }
+  
+  public QueryRequest( SolrParams q, METHOD method )
+  {
+    super( method, null );
+    query = q;
+  }
+
+  /**
+   * Use the params 'QT' parameter if it exists
+   */
+  @Override
+  public String getPath() {
+    String qt = query == null ? null : query.get( CommonParams.QT );
+    if( qt == null ) {
+      qt = super.getPath();
+    }
+    if( qt != null && qt.startsWith( "/" ) ) {
+      return qt;
+    }
+    return "/select";
+  }
+  
+  //---------------------------------------------------------------------------------
+  //---------------------------------------------------------------------------------
+  
+  @Override
+  public Collection<ContentStream> getContentStreams() {
+    return null;
+  }
+
+  @Override
+  protected QueryResponse createResponse(SolrClient client) {
+    return new QueryResponse(client);
+  }
+
+  @Override
+  public SolrParams getParams() {
+    return query;
+  }
+
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/RequestWriter.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/RequestWriter.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/RequestWriter.java
new file mode 100644
index 0000000..15872b2
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/RequestWriter.java
@@ -0,0 +1,146 @@
+/*
+ * 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.request;
+
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.util.ClientUtils;
+import org.apache.solr.common.util.ContentStream;
+import org.apache.solr.common.util.ContentStreamBase;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * A RequestWriter is used to write requests to Solr.
+ * <p>
+ * A subclass can override the methods in this class to supply a custom format in which a request can be sent.
+ *
+ *
+ * @since solr 1.4
+ */
+public class RequestWriter {
+  public static final Charset UTF_8 = StandardCharsets.UTF_8;
+
+  public Collection<ContentStream> getContentStreams(SolrRequest req) throws IOException {
+    if (req instanceof UpdateRequest) {
+      UpdateRequest updateRequest = (UpdateRequest) req;
+      if (isEmpty(updateRequest)) return null;
+      List<ContentStream> l = new ArrayList<>();
+      l.add(new LazyContentStream(updateRequest));
+      return l;
+    }
+    return req.getContentStreams();
+  }
+
+  private boolean isEmpty(UpdateRequest updateRequest) {
+    return isNull(updateRequest.getDocuments()) &&
+            isNull(updateRequest.getDeleteByIdMap()) &&
+            isNull(updateRequest.getDeleteQuery()) &&
+            updateRequest.getDocIterator() == null;
+  }
+
+  public String getPath(SolrRequest req) {
+    return req.getPath();
+  }
+
+  public ContentStream getContentStream(UpdateRequest req) throws IOException {
+    return new ContentStreamBase.StringStream(req.getXML());
+  }
+
+  public void write(SolrRequest request, OutputStream os) throws IOException {
+    if (request instanceof UpdateRequest) {
+      UpdateRequest updateRequest = (UpdateRequest) request;
+      BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, UTF_8));
+      updateRequest.writeXML(writer);
+      writer.flush();
+    }
+  }
+
+  public String getUpdateContentType() {
+    return ClientUtils.TEXT_XML;
+
+  }
+
+  public class LazyContentStream implements ContentStream {
+    ContentStream contentStream = null;
+    UpdateRequest req = null;
+
+    public LazyContentStream(UpdateRequest req) {
+      this.req = req;
+    }
+
+    private ContentStream getDelegate() {
+      if (contentStream == null) {
+        try {
+          contentStream = getContentStream(req);
+        } catch (IOException e) {
+          throw new RuntimeException("Unable to write xml into a stream", e);
+        }
+      }
+      return contentStream;
+    }
+
+    @Override
+    public String getName() {
+      return getDelegate().getName();
+    }
+
+    @Override
+    public String getSourceInfo() {
+      return getDelegate().getSourceInfo();
+    }
+
+    @Override
+    public String getContentType() {
+      return getUpdateContentType();
+    }
+
+    @Override
+    public Long getSize() {
+      return getDelegate().getSize();
+    }
+
+    @Override
+    public InputStream getStream() throws IOException {
+      return getDelegate().getStream();
+    }
+
+    @Override
+    public Reader getReader() throws IOException {
+      return getDelegate().getReader();
+    }
+
+    public void writeTo(OutputStream os) throws IOException {
+      write(req, os);
+
+    }
+  }
+
+  protected boolean isNull(List l) {
+    return l == null || l.isEmpty();
+  }
+  
+  protected boolean isNull(Map l) {
+    return l == null || l.isEmpty();
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/SolrPing.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/SolrPing.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/SolrPing.java
new file mode 100644
index 0000000..00ad41f
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/SolrPing.java
@@ -0,0 +1,111 @@
+/*
+ * 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.request;
+
+import org.apache.solr.client.solrj.SolrClient;
+import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.response.SolrPingResponse;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.ContentStream;
+
+import java.util.Collection;
+
+/**
+ * Verify that there is a working Solr core at the URL of a {@link org.apache.solr.client.solrj.SolrClient}.
+ * To use this class, the solrconfig.xml for the relevant core must include the
+ * request handler for <code>/admin/ping</code>.
+ * 
+ * @since solr 1.3
+ */
+public class SolrPing extends SolrRequest<SolrPingResponse> {
+  
+  /** serialVersionUID. */
+  private static final long serialVersionUID = 5828246236669090017L;
+  
+  /** Request parameters. */
+  private ModifiableSolrParams params;
+  
+  /**
+   * Create a new SolrPing object.
+   */
+  public SolrPing() {
+    super(METHOD.GET, CommonParams.PING_HANDLER);
+    params = new ModifiableSolrParams();
+  }
+  
+  @Override
+  public Collection<ContentStream> getContentStreams() {
+    return null;
+  }
+
+  @Override
+  protected SolrPingResponse createResponse(SolrClient client) {
+    return new SolrPingResponse();
+  }
+
+  @Override
+  public ModifiableSolrParams getParams() {
+    return params;
+  }
+  
+  /**
+   * Remove the action parameter from this request. This will result in the same
+   * behavior as {@code SolrPing#setActionPing()}. For Solr server version 4.0
+   * and later.
+   * 
+   * @return this
+   */
+  public SolrPing removeAction() {
+    params.remove(CommonParams.ACTION);
+    return this;
+  }
+  
+  /**
+   * Set the action parameter on this request to enable. This will delete the
+   * health-check file for the Solr core. For Solr server version 4.0 and later.
+   * 
+   * @return this
+   */
+  public SolrPing setActionDisable() {
+    params.set(CommonParams.ACTION, CommonParams.DISABLE);
+    return this;
+  }
+  
+  /**
+   * Set the action parameter on this request to enable. This will create the
+   * health-check file for the Solr core. For Solr server version 4.0 and later.
+   * 
+   * @return this
+   */
+  public SolrPing setActionEnable() {
+    params.set(CommonParams.ACTION, CommonParams.ENABLE);
+    return this;
+  }
+  
+  /**
+   * Set the action parameter on this request to ping. This is the same as not
+   * including the action at all. For Solr server version 4.0 and later.
+   * 
+   * @return this
+   */
+  public SolrPing setActionPing() {
+    params.set(CommonParams.ACTION, CommonParams.PING);
+    return this;
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/UpdateRequest.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/UpdateRequest.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/UpdateRequest.java
new file mode 100644
index 0000000..0e6580c
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/UpdateRequest.java
@@ -0,0 +1,463 @@
+/*
+ * 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.request;
+
+import org.apache.solr.client.solrj.impl.LBHttpSolrClient;
+import org.apache.solr.client.solrj.util.ClientUtils;
+import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.cloud.DocCollection;
+import org.apache.solr.common.cloud.DocRouter;
+import org.apache.solr.common.cloud.Slice;
+import org.apache.solr.common.params.ModifiableSolrParams;
+import org.apache.solr.common.util.ContentStream;
+import org.apache.solr.common.util.XML;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * 
+ * 
+ * @since solr 1.3
+ */
+public class UpdateRequest extends AbstractUpdateRequest {
+
+  public static final String REPFACT = "rf";
+  public static final String MIN_REPFACT = "min_rf";
+  public static final String VER = "ver";
+  public static final String ROUTE = "_route_";
+  public static final String OVERWRITE = "ow";
+  public static final String COMMIT_WITHIN = "cw";
+  private Map<SolrInputDocument,Map<String,Object>> documents = null;
+  private Iterator<SolrInputDocument> docIterator = null;
+  private Map<String,Map<String,Object>> deleteById = null;
+  private List<String> deleteQuery = null;
+  
+  public UpdateRequest() {
+    super(METHOD.POST, "/update");
+  }
+  
+  public UpdateRequest(String url) {
+    super(METHOD.POST, url);
+  }
+  
+  // ---------------------------------------------------------------------------
+  // ---------------------------------------------------------------------------
+  
+  /**
+   * clear the pending documents and delete commands
+   */
+  public void clear() {
+    if (documents != null) {
+      documents.clear();
+    }
+    if (deleteById != null) {
+      deleteById.clear();
+    }
+    if (deleteQuery != null) {
+      deleteQuery.clear();
+    }
+  }
+  
+  // ---------------------------------------------------------------------------
+  // ---------------------------------------------------------------------------
+  
+  public UpdateRequest add(final SolrInputDocument doc) {
+    if (documents == null) {
+      documents = new LinkedHashMap<>();
+    }
+    documents.put(doc, null);
+    return this;
+  }
+  
+  public UpdateRequest add(final SolrInputDocument doc, Boolean overwrite) {
+    return add(doc, null, overwrite);
+  }
+  
+  public UpdateRequest add(final SolrInputDocument doc, Integer commitWithin) {
+    return add(doc, commitWithin, null);
+  }
+  
+  public UpdateRequest add(final SolrInputDocument doc, Integer commitWithin,
+      Boolean overwrite) {
+    if (documents == null) {
+      documents = new LinkedHashMap<>();
+    }
+    Map<String,Object> params = new HashMap<>(2);
+    if (commitWithin != null) params.put(COMMIT_WITHIN, commitWithin);
+    if (overwrite != null) params.put(OVERWRITE, overwrite);
+    
+    documents.put(doc, params);
+    
+    return this;
+  }
+  
+  public UpdateRequest add(final Collection<SolrInputDocument> docs) {
+    if (documents == null) {
+      documents = new LinkedHashMap<>();
+    }
+    for (SolrInputDocument doc : docs) {
+      documents.put(doc, null);
+    }
+    return this;
+  }
+  
+  public UpdateRequest deleteById(String id) {
+    if (deleteById == null) {
+      deleteById = new LinkedHashMap<>();
+    }
+    deleteById.put(id, null);
+    return this;
+  }
+
+  public UpdateRequest deleteById(String id, String route) {
+    return deleteById(id, route, null);
+  }
+
+  public UpdateRequest deleteById(String id, String route, Long version) {
+    if (deleteById == null) {
+      deleteById = new LinkedHashMap<>();
+    }
+    Map<String, Object> params = (route == null && version == null) ? null : new HashMap<String, Object>(1);
+    if (version != null)
+      params.put(VER, version);
+    if (route != null)
+      params.put(ROUTE, route);
+    deleteById.put(id, params);
+    return this;
+  }
+
+
+  public UpdateRequest deleteById(List<String> ids) {
+    if (deleteById == null) {
+      deleteById = new LinkedHashMap<>();
+    }
+    
+    for (String id : ids) {
+      deleteById.put(id, null);
+    }
+    
+    return this;
+  }
+  
+  public UpdateRequest deleteById(String id, Long version) {
+    return deleteById(id, null, version);
+  }
+  
+  public UpdateRequest deleteByQuery(String q) {
+    if (deleteQuery == null) {
+      deleteQuery = new ArrayList<>();
+    }
+    deleteQuery.add(q);
+    return this;
+  }
+  
+  /**
+   * @param router to route updates with
+   * @param col DocCollection for the updates
+   * @param urlMap of the cluster
+   * @param params params to use
+   * @param idField the id field
+   * @return a Map of urls to requests
+   */
+  public Map<String,LBHttpSolrClient.Req> getRoutes(DocRouter router,
+      DocCollection col, Map<String,List<String>> urlMap,
+      ModifiableSolrParams params, String idField) {
+    
+    if ((documents == null || documents.size() == 0)
+        && (deleteById == null || deleteById.size() == 0)) {
+      return null;
+    }
+    
+    Map<String,LBHttpSolrClient.Req> routes = new HashMap<>();
+    if (documents != null) {
+      Set<Entry<SolrInputDocument,Map<String,Object>>> entries = documents.entrySet();
+      for (Entry<SolrInputDocument,Map<String,Object>> entry : entries) {
+        SolrInputDocument doc = entry.getKey();
+        Object id = doc.getFieldValue(idField);
+        if (id == null) {
+          return null;
+        }
+        Slice slice = router.getTargetSlice(id
+            .toString(), doc, null, null, col);
+        if (slice == null) {
+          return null;
+        }
+        List<String> urls = urlMap.get(slice.getName());
+        String leaderUrl = urls.get(0);
+        LBHttpSolrClient.Req request = (LBHttpSolrClient.Req) routes
+            .get(leaderUrl);
+        if (request == null) {
+          UpdateRequest updateRequest = new UpdateRequest();
+          updateRequest.setMethod(getMethod());
+          updateRequest.setCommitWithin(getCommitWithin());
+          updateRequest.setParams(params);
+          updateRequest.setPath(getPath());
+          request = new LBHttpSolrClient.Req(updateRequest, urls);
+          routes.put(leaderUrl, request);
+        }
+        UpdateRequest urequest = (UpdateRequest) request.getRequest();
+        Map<String,Object> value = entry.getValue();
+        Boolean ow = null;
+        if (value != null) {
+          ow = (Boolean) value.get(OVERWRITE);
+        }
+        if (ow != null) {
+          urequest.add(doc, ow);
+        } else {
+          urequest.add(doc);
+        }
+      }
+    }
+    
+    // Route the deleteById's
+    
+    if (deleteById != null) {
+      
+      Iterator<Map.Entry<String,Map<String,Object>>> entries = deleteById.entrySet()
+          .iterator();
+      while (entries.hasNext()) {
+        
+        Map.Entry<String,Map<String,Object>> entry = entries.next();
+        
+        String deleteId = entry.getKey();
+        Map<String,Object> map = entry.getValue();
+        Long version = null;
+        if (map != null) {
+          version = (Long) map.get(VER);
+        }
+        Slice slice = router.getTargetSlice(deleteId, null, null, null, col);
+        if (slice == null) {
+          return null;
+        }
+        List<String> urls = urlMap.get(slice.getName());
+        String leaderUrl = urls.get(0);
+        LBHttpSolrClient.Req request = routes.get(leaderUrl);
+        if (request != null) {
+          UpdateRequest urequest = (UpdateRequest) request.getRequest();
+          urequest.deleteById(deleteId, version);
+        } else {
+          UpdateRequest urequest = new UpdateRequest();
+          urequest.setParams(params);
+          urequest.deleteById(deleteId, version);
+          request = new LBHttpSolrClient.Req(urequest, urls);
+          routes.put(leaderUrl, request);
+        }
+      }
+    }
+
+    return routes;
+  }
+  
+  public void setDocIterator(Iterator<SolrInputDocument> docIterator) {
+    this.docIterator = docIterator;
+  }
+  
+  public void setDeleteQuery(List<String> deleteQuery) {
+    this.deleteQuery = deleteQuery;
+  }
+  
+  // --------------------------------------------------------------------------
+  // --------------------------------------------------------------------------
+  
+  @Override
+  public Collection<ContentStream> getContentStreams() throws IOException {
+    return ClientUtils.toContentStreams(getXML(), ClientUtils.TEXT_XML);
+  }
+  
+  public String getXML() throws IOException {
+    StringWriter writer = new StringWriter();
+    writeXML(writer);
+    writer.flush();
+    
+    // If action is COMMIT or OPTIMIZE, it is sent with params
+    String xml = writer.toString();
+    // System.out.println( "SEND:"+xml );
+    return (xml.length() > 0) ? xml : null;
+  }
+  
+  private List<Map<SolrInputDocument,Map<String,Object>>> getDocLists(Map<SolrInputDocument,Map<String,Object>> documents) {
+    List<Map<SolrInputDocument,Map<String,Object>>> docLists = new ArrayList<>();
+    Map<SolrInputDocument,Map<String,Object>> docList = null;
+    if (this.documents != null) {
+      
+      Boolean lastOverwrite = true;
+      Integer lastCommitWithin = -1;
+      
+      Set<Entry<SolrInputDocument,Map<String,Object>>> entries = this.documents
+          .entrySet();
+      for (Entry<SolrInputDocument,Map<String,Object>> entry : entries) {
+        Map<String,Object> map = entry.getValue();
+        Boolean overwrite = null;
+        Integer commitWithin = null;
+        if (map != null) {
+          overwrite = (Boolean) entry.getValue().get(OVERWRITE);
+          commitWithin = (Integer) entry.getValue().get(COMMIT_WITHIN);
+        }
+        if (overwrite != lastOverwrite || commitWithin != lastCommitWithin
+            || docLists.size() == 0) {
+          docList = new LinkedHashMap<>();
+          docLists.add(docList);
+        }
+        docList.put(entry.getKey(), entry.getValue());
+        lastCommitWithin = commitWithin;
+        lastOverwrite = overwrite;
+      }
+    }
+    
+    if (docIterator != null) {
+      docList = new LinkedHashMap<>();
+      docLists.add(docList);
+      while (docIterator.hasNext()) {
+        SolrInputDocument doc = docIterator.next();
+        if (doc != null) {
+          docList.put(doc, null);
+        }
+      }
+      
+    }
+
+    return docLists;
+  }
+  
+  /**
+   * @since solr 1.4
+   */
+  public void writeXML(Writer writer) throws IOException {
+    List<Map<SolrInputDocument,Map<String,Object>>> getDocLists = getDocLists(documents);
+    
+    for (Map<SolrInputDocument,Map<String,Object>> docs : getDocLists) {
+      
+      if ((docs != null && docs.size() > 0)) {
+        Entry<SolrInputDocument,Map<String,Object>> firstDoc = docs.entrySet()
+            .iterator().next();
+        Map<String,Object> map = firstDoc.getValue();
+        Integer cw = null;
+        Boolean ow = null;
+        if (map != null) {
+          cw = (Integer) firstDoc.getValue().get(COMMIT_WITHIN);
+          ow = (Boolean) firstDoc.getValue().get(OVERWRITE);
+        }
+        if (ow == null) ow = true;
+        int commitWithin = (cw != null && cw != -1) ? cw : this.commitWithin;
+        boolean overwrite = ow;
+        if (commitWithin > -1 || overwrite != true) {
+          writer.write("<add commitWithin=\"" + commitWithin + "\" "
+              + "overwrite=\"" + overwrite + "\">");
+        } else {
+          writer.write("<add>");
+        }
+        
+        Set<Entry<SolrInputDocument,Map<String,Object>>> entries = docs
+            .entrySet();
+        for (Entry<SolrInputDocument,Map<String,Object>> entry : entries) {
+          ClientUtils.writeXML(entry.getKey(), writer);
+        }
+        
+        writer.write("</add>");
+      }
+    }
+    
+    // Add the delete commands
+    boolean deleteI = deleteById != null && deleteById.size() > 0;
+    boolean deleteQ = deleteQuery != null && deleteQuery.size() > 0;
+    if (deleteI || deleteQ) {
+      if (commitWithin > 0) {
+        writer.append("<delete commitWithin=\"" + commitWithin + "\">");
+      } else {
+        writer.append("<delete>");
+      }
+      if (deleteI) {
+        for (Map.Entry<String,Map<String,Object>> entry : deleteById.entrySet()) {
+          writer.append("<id");
+          Map<String,Object> map = entry.getValue();
+          if (map != null) {
+            Long version = (Long) map.get(VER);
+            String route = (String)map.get(ROUTE);
+            if (version != null) {
+              writer.append(" version=\"" + version + "\"");
+            }
+            
+            if (route != null) {
+              writer.append(" _route_=\"" + route + "\"");
+            }
+          }
+          writer.append(">");
+          
+          XML.escapeCharData(entry.getKey(), writer);
+          writer.append("</id>");
+        }
+      }
+      if (deleteQ) {
+        for (String q : deleteQuery) {
+          writer.append("<query>");
+          XML.escapeCharData(q, writer);
+          writer.append("</query>");
+        }
+      }
+      writer.append("</delete>");
+    }
+  }
+  
+  // --------------------------------------------------------------------------
+  // --------------------------------------------------------------------------
+  
+  // --------------------------------------------------------------------------
+  //
+  // --------------------------------------------------------------------------
+  
+  public List<SolrInputDocument> getDocuments() {
+    if (documents == null) return null;
+    List<SolrInputDocument> docs = new ArrayList<>(documents.size());
+    docs.addAll(documents.keySet());
+    return docs;
+  }
+  
+  public Map<SolrInputDocument,Map<String,Object>> getDocumentsMap() {
+    return documents;
+  }
+  
+  public Iterator<SolrInputDocument> getDocIterator() {
+    return docIterator;
+  }
+  
+  public List<String> getDeleteById() {
+    if (deleteById == null) return null;
+    List<String> deletes = new ArrayList<>(deleteById.keySet());
+    return deletes;
+  }
+  
+  public Map<String,Map<String,Object>> getDeleteByIdMap() {
+    return deleteById;
+  }
+  
+  public List<String> getDeleteQuery() {
+    return deleteQuery;
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/package-info.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/package-info.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/package-info.java
new file mode 100644
index 0000000..899a562
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/request/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.
+ */
+ 
+/** 
+ * Convenience classes for dealing with various types of Solr requests.
+ */
+package org.apache.solr.client.solrj.request;
+
+

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/AnalysisResponseBase.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/AnalysisResponseBase.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/AnalysisResponseBase.java
new file mode 100644
index 0000000..21396a5
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/AnalysisResponseBase.java
@@ -0,0 +1,252 @@
+/*
+ * 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.response;
+
+import org.apache.solr.common.util.NamedList;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A base class for all analysis responses.
+ *
+ *
+ * @since solr 1.4
+ */
+public class AnalysisResponseBase extends SolrResponseBase {
+
+  /**
+   * Parses the given named list and builds a list of analysis phases form it. Expects a named list of the form:
+   * <br>
+   * <pre><code>
+   *  &lt;lst name="index"&gt;
+   *      &lt;arr name="Tokenizer"&gt;
+   *          &lt;str name="text"&gt;the_text&lt;/str&gt;
+   *          &lt;str name="rawText"&gt;the_raw_text&lt;/str&gt; (optional)
+   *          &lt;str name="type"&gt;the_type&lt;/str&gt;
+   *          &lt;int name="start"&gt;1&lt;/str&gt;
+   *          &lt;int name="end"&gt;3&lt;/str&gt;
+   *          &lt;int name="position"&gt;1&lt;/str&gt;
+   *          &lt;bool name="match"&gt;true | false&lt;/bool&gt; (optional)
+   *      &lt;/arr&gt;
+   *      &lt;arr name="Filter1"&gt;
+   *          &lt;str name="text"&gt;the_text&lt;/str&gt;
+   *          &lt;str name="rawText"&gt;the_raw_text&lt;/str&gt; (optional)
+   *          &lt;str name="type"&gt;the_type&lt;/str&gt;
+   *          &lt;int name="start"&gt;1&lt;/str&gt;
+   *          &lt;int name="end"&gt;3&lt;/str&gt;
+   *          &lt;int name="position"&gt;1&lt;/str&gt;
+   *          &lt;bool name="match"&gt;true | false&lt;/bool&gt; (optional)
+   *      &lt;/arr&gt;
+   *      ...
+   *  &lt;/lst&gt;
+   * </code></pre>
+   *
+   * @param phaseNL The names list to parse.
+   *
+   * @return The built analysis phases list.
+   */
+  protected List<AnalysisPhase> buildPhases(NamedList<List<NamedList<Object>>> phaseNL) {
+    List<AnalysisPhase> phases = new ArrayList<>(phaseNL.size());
+    for (Map.Entry<String, List<NamedList<Object>>> phaseEntry : phaseNL) {
+      AnalysisPhase phase = new AnalysisPhase(phaseEntry.getKey());
+      List<NamedList<Object>> tokens = phaseEntry.getValue();
+      for (NamedList<Object> token : tokens) {
+        TokenInfo tokenInfo = buildTokenInfo(token);
+        phase.addTokenInfo(tokenInfo);
+      }
+      phases.add(phase);
+    }
+    return phases;
+  }
+
+  /**
+   * Parses the given named list and builds a token infoform it. Expects a named list of the form:
+   * <br>
+   * <pre><code>
+   *  &lt;arr name="Tokenizer"&gt;
+   *      &lt;str name="text"&gt;the_text&lt;/str&gt;
+   *      &lt;str name="rawText"&gt;the_raw_text&lt;/str&gt; (optional)
+   *      &lt;str name="type"&gt;the_type&lt;/str&gt;
+   *      &lt;int name="start"&gt;1&lt;/str&gt;
+   *      &lt;int name="end"&gt;3&lt;/str&gt;
+   *      &lt;int name="position"&gt;1&lt;/str&gt;
+   *      &lt;bool name="match"&gt;true | false&lt;/bool&gt; (optional)
+   *  &lt;/arr&gt;
+   * </code></pre>
+   *
+   * @param tokenNL The named list to parse.
+   *
+   * @return The built token info.
+   */
+  protected TokenInfo buildTokenInfo(NamedList<Object> tokenNL) {
+    String text = (String) tokenNL.get("text");
+    String rawText = (String) tokenNL.get("rawText");
+    String type = (String) tokenNL.get("type");
+    int start = (Integer) tokenNL.get("start");
+    int end = (Integer) tokenNL.get("end");
+    int position = (Integer) tokenNL.get("position");
+    Boolean match = (Boolean) tokenNL.get("match");
+    return new TokenInfo(text, rawText, type, start, end, position, (match == null ? false : match));
+  }
+
+
+  //================================================= Inner Classes ==================================================
+
+  /**
+   * A phase in the analysis process. The phase holds the tokens produced in this phase and the name of the class that
+   * produced them.
+   */
+  public static class AnalysisPhase {
+
+    private final String className;
+    private List<TokenInfo> tokens = new ArrayList<>();
+
+    AnalysisPhase(String className) {
+      this.className = className;
+    }
+
+    /**
+     * The name of the class (analyzer, tokenzier, or filter) that produced the token stream for this phase.
+     *
+     * @return The name of the class that produced the token stream for this phase.
+     */
+    public String getClassName() {
+      return className;
+    }
+
+    private void addTokenInfo(TokenInfo tokenInfo) {
+      tokens.add(tokenInfo);
+    }
+
+    /**
+     * Returns a list of tokens which represent the token stream produced in this phase.
+     *
+     * @return A list of tokens which represent the token stream produced in this phase.
+     */
+    public List<TokenInfo> getTokens() {
+      return tokens;
+    }
+
+  }
+
+  /**
+   * Holds all information of a token as part of an analysis phase.
+   */
+  public static class TokenInfo {
+
+    private final String text;
+    private final String rawText;
+    private final String type;
+    private final int start;
+    private final int end;
+    private final int position;
+    private final boolean match;
+
+    /**
+     * Constructs a new TokenInfo.
+     *
+     * @param text     The text of the token
+     * @param rawText  The raw text of the token. If the token is stored in the index in a special format (e.g.
+     *                 dates or padded numbers) this argument should hold this value. If the token is stored as is,
+     *                 then this value should be {@code null}.
+     * @param type     The type fo the token (typically either {@code word} or {@code <ALPHANUM>} though it depends
+     *                 on the tokenizer/filter used).
+     * @param start    The start position of the token in the original text where it was extracted from.
+     * @param end      The end position of the token in the original text where it was extracted from.
+     * @param position The position of the token within the token stream.
+     * @param match    Indicates whether this token matches one of the the query tokens.
+     */
+    TokenInfo(String text, String rawText, String type, int start, int end, int position, boolean match) {
+      this.text = text;
+      this.rawText = rawText;
+      this.type = type;
+      this.start = start;
+      this.end = end;
+      this.position = position;
+      this.match = match;
+    }
+
+    /**
+     * Returns the text of the token.
+     *
+     * @return The text of the token.
+     */
+    public String getText() {
+      return text;
+    }
+
+    /**
+     * Returns the raw text of the token. If the token is index in a special format (e.g. date or paddded numbers)
+     * it will be returned as the raw text. Returns {@code null} if the token is indexed as is.
+     *
+     * @return Returns the raw text of the token.
+     */
+    public String getRawText() {
+      return rawText;
+    }
+
+    /**
+     * Returns the type of the token. Typically this will be {@code word} or {@code <ALPHANUM>}, but it really
+     * depends on the tokenizer and filters that are used.
+     *
+     * @return The type of the token.
+     */
+    public String getType() {
+      return type;
+    }
+
+    /**
+     * Returns the start position of this token within the text it was originally extracted from.
+     *
+     * @return The start position of this token within the text it was originally extracted from.
+     */
+    public int getStart() {
+      return start;
+    }
+
+    /**
+     * Returns the end position of this token within the text it was originally extracted from.
+     *
+     * @return The end position of this token within the text it was originally extracted from.
+     */
+    public int getEnd() {
+      return end;
+    }
+
+    /**
+     * Returns the position of this token within the produced token stream.
+     *
+     * @return The position of this token within the produced token stream.
+     */
+    public int getPosition() {
+      return position;
+    }
+
+    /**
+     * Returns whether this token matches one of the query tokens (if query analysis is performed).
+     *
+     * @return Whether this token matches one of the query tokens (if query analysis is performed).
+     */
+    public boolean isMatch() {
+      return match;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/CollectionAdminResponse.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/CollectionAdminResponse.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/CollectionAdminResponse.java
new file mode 100644
index 0000000..8acf2e2
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/CollectionAdminResponse.java
@@ -0,0 +1,79 @@
+/*
+ * 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.response;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.solr.common.util.NamedList;
+
+public class CollectionAdminResponse extends SolrResponseBase
+{
+  @SuppressWarnings("unchecked")
+  public NamedList<NamedList<Object>> getCollectionStatus()
+  {
+    return (NamedList<NamedList<Object>>) getResponse().get( "success" );
+  }
+
+  public boolean isSuccess()
+  {
+    return getResponse().get( "success" ) != null;
+  }
+
+  // this messages are typically from individual nodes, since
+  // all the failures at the router are propagated as exceptions
+  @SuppressWarnings("unchecked")
+  public NamedList<String> getErrorMessages()
+  {
+     return (NamedList<String>) getResponse().get( "failure" );
+  }
+
+  @SuppressWarnings("unchecked")
+  public Map<String, NamedList<Integer>> getCollectionCoresStatus()
+  {
+    Map<String, NamedList<Integer>> res = new HashMap<>();
+    NamedList<NamedList<Object>> cols = getCollectionStatus();
+    if( cols != null ) {
+      for (Map.Entry<String, NamedList<Object>> e : cols) {
+        NamedList<Object> item = e.getValue();
+        String core = (String) item.get("core");
+        if (core != null) {
+          res.put(core, (NamedList<Integer>)item.get("responseHeader"));
+        }
+      }
+    }
+
+    return res;
+  }
+
+  @SuppressWarnings("unchecked")
+  public Map<String, NamedList<Integer>> getCollectionNodesStatus()
+  {
+    Map<String, NamedList<Integer>> res = new HashMap<>();
+    NamedList<NamedList<Object>> cols = getCollectionStatus();
+    if( cols != null ) {
+      for (Map.Entry<String,NamedList<Object>> e : cols) {
+        if (e.getKey() != null) {
+          res.put(e.getKey(), (NamedList<Integer>) (e.getValue().get("responseHeader")));
+        }
+      }
+    }
+
+    return res;
+  }
+}
\ 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/client/solrj/response/CoreAdminResponse.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/CoreAdminResponse.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/CoreAdminResponse.java
new file mode 100644
index 0000000..0492165
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/CoreAdminResponse.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.solr.client.solrj.response;
+
+import java.util.Date;
+import org.apache.solr.common.util.NamedList;
+
+/**
+ * 
+ *
+ * @since solr 1.3
+ */
+public class CoreAdminResponse extends SolrResponseBase
+{ 
+  @SuppressWarnings("unchecked")
+  public NamedList<NamedList<Object>> getCoreStatus()
+  {
+    return (NamedList<NamedList<Object>>) getResponse().get( "status" );
+  }
+
+  public NamedList<Object> getCoreStatus( String core )
+  {
+    return getCoreStatus().get( core );
+  }
+  
+  public Date getStartTime( String core )
+  {
+    NamedList<Object> v = getCoreStatus( core );
+    if( v == null ) {
+      return null;
+    }
+    return (Date) v.get( "startTime" );
+  }
+  
+  public Long getUptime( String core )
+  {
+    NamedList<Object> v = getCoreStatus( core );
+    if( v == null ) {
+      return null;
+    }
+    return (Long) v.get( "uptime" );
+  }
+}
\ 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/client/solrj/response/DocumentAnalysisResponse.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/DocumentAnalysisResponse.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/DocumentAnalysisResponse.java
new file mode 100644
index 0000000..2f11d78
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/DocumentAnalysisResponse.java
@@ -0,0 +1,258 @@
+/*
+ * 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.response;
+
+import org.apache.solr.common.util.NamedList;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A response that is returned by processing the {@link org.apache.solr.client.solrj.request.DocumentAnalysisRequest}.
+ * Holds a map of {@link DocumentAnalysis} objects by a document id (unique key).
+ *
+ *
+ * @since solr 1.4
+ */
+public class DocumentAnalysisResponse extends AnalysisResponseBase implements Iterable<Map.Entry<String, DocumentAnalysisResponse.DocumentAnalysis>> {
+
+  private final Map<String, DocumentAnalysis> documentAnalysisByKey = new HashMap<>();
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public void setResponse(NamedList<Object> response) {
+    super.setResponse(response);
+
+    @SuppressWarnings("unchecked")
+    NamedList<NamedList<NamedList<Object>>> analysis 
+      = (NamedList<NamedList<NamedList<Object>>>) response.get("analysis");
+    for (Map.Entry<String, NamedList<NamedList<Object>>> document : analysis) {
+      DocumentAnalysis documentAnalysis = new DocumentAnalysis(document.getKey());
+      for (Map.Entry<String, NamedList<Object>> fieldEntry : document.getValue()) {
+        FieldAnalysis fieldAnalysis = new FieldAnalysis(fieldEntry.getKey());
+
+        NamedList<Object> field = fieldEntry.getValue();
+
+        @SuppressWarnings("unchecked")
+        NamedList<List<NamedList<Object>>> query 
+          = (NamedList<List<NamedList<Object>>>) field.get("query");
+        if (query != null) {
+          List<AnalysisPhase> phases = buildPhases(query);
+          fieldAnalysis.setQueryPhases(phases);
+        }
+        
+        @SuppressWarnings("unchecked")
+        NamedList<NamedList<List<NamedList<Object>>>> index 
+          = (NamedList<NamedList<List<NamedList<Object>>>>) field.get("index");
+        for (Map.Entry<String, NamedList<List<NamedList<Object>>>> valueEntry : index) {
+          String fieldValue = valueEntry.getKey();
+          NamedList<List<NamedList<Object>>> valueNL = valueEntry.getValue();
+          List<AnalysisPhase> phases = buildPhases(valueNL);
+          fieldAnalysis.setIndexPhases(fieldValue, phases);
+        }
+
+        documentAnalysis.addFieldAnalysis(fieldAnalysis);
+      }
+
+      documentAnalysisByKey.put(documentAnalysis.getDocumentKey(), documentAnalysis);
+    }
+  }
+
+  /**
+   * Returns the number of document analyses in this response.
+   *
+   * @return The number of document analyses in this response.
+   */
+  public int getDocumentAnalysesCount() {
+    return documentAnalysisByKey.size();
+  }
+
+  /**
+   * Returns the document analysis for the document associated with the given unique key (id), {@code null} if no such
+   * association exists.
+   *
+   * @param documentKey The document unique key.
+   *
+   * @return The document analysis for the document associated with the given unique key (id).
+   */
+  public DocumentAnalysis getDocumentAnalysis(String documentKey) {
+    return documentAnalysisByKey.get(documentKey);
+  }
+
+  /**
+   * Returns an iterator over the document analyses map.
+   *
+   * @return An iterator over the document analyses map.
+   */
+  @Override
+  public Iterator<Map.Entry<String, DocumentAnalysis>> iterator() {
+    return documentAnalysisByKey.entrySet().iterator();
+  }
+
+  //================================================= Inner Classes ==================================================
+
+  /**
+   * An analysis process breakdown of a document. Holds a map of field analyses by the field name.
+   */
+  public static class DocumentAnalysis implements Iterable<Map.Entry<String, FieldAnalysis>> {
+
+    private final String documentKey;
+    private Map<String, FieldAnalysis> fieldAnalysisByFieldName = new HashMap<>();
+
+    private DocumentAnalysis(String documentKey) {
+      this.documentKey = documentKey;
+    }
+
+    private void addFieldAnalysis(FieldAnalysis fieldAnalysis) {
+      fieldAnalysisByFieldName.put(fieldAnalysis.getFieldName(), fieldAnalysis);
+    }
+
+    /**
+     * Returns the unique key of the analyzed document.
+     *
+     * @return The unique key of the analyzed document.
+     */
+    public String getDocumentKey() {
+      return documentKey;
+    }
+
+    /**
+     * Returns the number of field analyses for the documents.
+     *
+     * @return The number of field analyses for the documents.
+     */
+    public int getFieldAnalysesCount() {
+      return fieldAnalysisByFieldName.size();
+    }
+
+    public FieldAnalysis getFieldAnalysis(String fieldName) {
+      return fieldAnalysisByFieldName.get(fieldName);
+    }
+
+    /**
+     * Returns an iterator over the field analyses map.
+     *
+     * @return An iterator over the field analyses map.
+     */
+    @Override
+    public Iterator<Map.Entry<String, FieldAnalysis>> iterator() {
+      return fieldAnalysisByFieldName.entrySet().iterator();
+    }
+  }
+
+  /**
+   * An analysis process breakdown for a specific field. Holds a list of query time analysis phases (that is, if a
+   * query analysis was requested in the first place) and a list of index time analysis phases for each field value (a
+   * field can be multi-valued).
+   */
+  public static class FieldAnalysis {
+
+    private final String fieldName;
+    private List<AnalysisPhase> queryPhases;
+    private Map<String, List<AnalysisPhase>> indexPhasesByFieldValue = new HashMap<>();
+
+    private FieldAnalysis(String fieldName) {
+      this.fieldName = fieldName;
+    }
+
+    public void setQueryPhases(List<AnalysisPhase> queryPhases) {
+      this.queryPhases = queryPhases;
+    }
+
+    public void setIndexPhases(String fieldValue, List<AnalysisPhase> indexPhases) {
+      indexPhasesByFieldValue.put(fieldValue, indexPhases);
+    }
+
+    /**
+     * Returns the field name.
+     *
+     * @return The name of the field.
+     */
+    public String getFieldName() {
+      return fieldName;
+    }
+
+    /**
+     * Returns the number of query time analysis phases or {@code -1} if 
+     * this field analysis doesn't hold a query time analysis.
+     *
+     * @return Returns the number of query time analysis phases or {@code -1} 
+     *         if this field analysis doesn't hold a query time analysis.
+     */
+    public int getQueryPhasesCount() {
+      return queryPhases == null ? -1 : queryPhases.size();
+    }
+
+    /**
+     * Returns the query time analysis phases for the field or {@code null} 
+     * if this field doesn't hold a query time analysis.
+     *
+     * @return Returns the query time analysis phases for the field or 
+     *         {@code null} if this field doesn't hold a query time analysis.
+     */
+    public Iterable<AnalysisPhase> getQueryPhases() {
+      return queryPhases;
+    }
+
+    /**
+     * Returns the number of values the field has.
+     *
+     * @return The number of values the field has.
+     */
+    public int getValueCount() {
+      return indexPhasesByFieldValue.entrySet().size();
+    }
+
+    /**
+     * Returns the number of index time analysis phases the given field value has.
+     *
+     * @param fieldValue The field value.
+     *
+     * @return The number of index time analysis phases the given field value has.
+     */
+    public int getIndexPhasesCount(String fieldValue) {
+      return indexPhasesByFieldValue.get(fieldValue).size();
+    }
+
+    /**
+     * Returns the index time analysis phases for the given field value.
+     *
+     * @param fieldValue The field value.
+     *
+     * @return The index time analysis phases for the given field value.
+     */
+    public Iterable<AnalysisPhase> getIndexPhases(String fieldValue) {
+      return indexPhasesByFieldValue.get(fieldValue);
+    }
+
+    /**
+     * Returns the index time analysis phases for all field values.
+     *
+     * @return Returns the index time analysis phases for all field value.
+     */
+    public Iterable<Map.Entry<String, List<AnalysisPhase>>> getIndexPhasesByFieldValue() {
+      return indexPhasesByFieldValue.entrySet();
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-ranger/blob/40aa090d/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/FacetField.java
----------------------------------------------------------------------
diff --git a/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/FacetField.java b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/FacetField.java
new file mode 100644
index 0000000..086c999
--- /dev/null
+++ b/ranger_solrj/src/main/java/org/apache/solr/client/solrj/response/FacetField.java
@@ -0,0 +1,176 @@
+/*
+ * 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.response;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.solr.client.solrj.util.ClientUtils;
+ 
+ /**
+  * A utility class to hold the facet response.  It could use the NamedList container,
+  * but for JSTL, it is nice to have something that implements List so it can be iterated
+  * 
+  * @since solr 1.3
+  */
+ public class FacetField implements Serializable
+ {
+   public static class Count implements Serializable 
+   {
+     private String _name = null;
+     private long _count = 0;
+     // hang onto the FacetField for breadcrumb creation convenience
+     private FacetField _ff = null;
+     
+     public Count( FacetField ff, String n, long c )
+     {
+       _name = n;
+       _count = c;
+       _ff = ff;
+     }
+     
+     public String getName() {
+       return _name;
+     }
+     
+     public void setName( String n )
+     {
+       _name = n;
+     }
+
+     public long getCount() {
+       return _count;
+     }
+     
+     public void setCount( long c )
+     {
+       _count = c;
+     }
+     
+     public FacetField getFacetField() {
+       return _ff;
+     }
+     
+     @Override
+     public String toString()
+     {
+       return _name+" ("+_count+")";
+     }
+     
+     public String getAsFilterQuery() {
+       if (_ff.getName().equals("facet_queries")) {
+         return _name;
+       }
+       return 
+          ClientUtils.escapeQueryChars( _ff._name ) + ":" + 
+          ClientUtils.escapeQueryChars( _name );
+     }
+   }
+   
+   private String      _name   = null;
+   private List<Count> _values = null;
+   private String _gap = null;
+   private Date _end = null;
+   
+   public FacetField( final String n )
+   {
+     _name = n;
+   }
+   
+   public FacetField(String name, String gap, Date end) {
+     _name = name;
+     _gap = gap;
+     _end = end;
+   }
+   
+   /**
+    * Date Gap Facet parameter
+    * 
+    * @return the value specified for facet.date.gap
+    */
+   public String getGap()   {
+     return _gap;
+   }
+   
+   /**
+    * Date End Facet parameter
+    * 
+    * @return the value specified for facet.date.end
+    */
+   public Date getEnd() {
+     return _end;
+   }
+
+   /**
+    * Insert at the end of the list
+    */
+   public void add( String name, long cnt )
+   {
+     if( _values == null ) {
+       _values = new ArrayList<>( 30 );
+     }
+     _values.add( new Count( this, name, cnt ) );
+   }
+
+   /**
+    * Insert at the beginning of the list.
+    */
+   public void insert( String name, long cnt )
+   {
+     if( _values == null ) {
+       _values = new ArrayList<>( 30 );
+     }
+     _values.add( 0, new Count( this, name, cnt ) );
+   }
+
+   public String getName() {
+     return _name;
+   }
+
+   public List<Count> getValues() {
+     return _values == null ? Collections.<Count>emptyList() : _values;
+   }
+   
+   public int getValueCount()
+   {
+     return _values == null ? 0 : _values.size();
+   }
+
+   public FacetField getLimitingFields(long max) 
+   {
+     FacetField ff = new FacetField( _name );
+     if( _values != null ) {
+       ff._values = new ArrayList<>( _values.size() );
+       for( Count c : _values ) {
+         if( c._count < max ) { // !equal to
+           ff._values.add( c );
+         }
+       }
+     }
+     return ff;
+   }
+   
+   @Override
+   public String toString()
+   {
+     return _name + ":" + _values;
+   }
+ }