You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2014/08/30 04:53:27 UTC

svn commit: r1621414 - in /lucene/dev/trunk/solr: ./ core/src/java/org/apache/solr/core/ core/src/java/org/apache/solr/handler/ core/src/java/org/apache/solr/util/ core/src/test-files/solr/collection1/conf/ core/src/test/org/apache/solr/core/ solrj/src...

Author: noble
Date: Sat Aug 30 02:53:26 2014
New Revision: 1621414

URL: http://svn.apache.org/r1621414
Log:
SOLR-6365: specify appends, defaults, invariants outside of the request handler

Added:
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ParamSet.java   (with props)
    lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/solrconfig-paramset.xml   (with props)
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestParamSet.java   (with props)
Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java
    lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1621414&r1=1621413&r2=1621414&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Sat Aug 30 02:53:26 2014
@@ -119,6 +119,9 @@ New Features
 
 * SOLR-4580: Support for protecting content in ZooKeeper. (Per Steffensen, Mark Miller)
 
+* SOLR-6365: specify appends, defaults, invariants outside of the request handler.
+  (Noble Paul, Erik Hatcher, shalin)
+
 Bug Fixes
 ----------------------
 

Added: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ParamSet.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ParamSet.java?rev=1621414&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ParamSet.java (added)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/ParamSet.java Sat Aug 30 02:53:26 2014
@@ -0,0 +1,117 @@
+package org.apache.solr.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.StrUtils;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+/**
+ * An Object which represents a paramSet tag
+ *
+ */
+public class ParamSet {
+  public static final String TYPE = "paramSet";
+  public final String name;
+  public final Set<String> paths;
+  public final NamedList defaults,invariants,appends;
+
+  public ParamSet(PluginInfo p) {
+    this.name = p.attributes.get("name");
+    Set<String> paths = null;
+    String pathStr = p.attributes.get("path");
+    if(pathStr!=null) {
+      paths = Collections.unmodifiableSet(new HashSet<>(StrUtils.splitSmart(pathStr, ',')));
+    }
+    this.paths = paths;
+    NamedList nl = (NamedList) p.initArgs.get(PluginInfo.DEFAULTS);
+    defaults = nl == null ? null: nl.getImmutableCopy();
+    nl = (NamedList) p.initArgs.get(PluginInfo.INVARIANTS);
+    invariants = nl == null ? null: nl.getImmutableCopy();
+    nl = (NamedList) p.initArgs.get(PluginInfo.APPENDS);
+    appends = nl == null ? null: nl.getImmutableCopy();
+  }
+
+  public boolean matchPath(String name) {
+    if(paths == null) return false;
+    if(paths.contains(name)) return true;
+
+    for (String path : paths) {
+      if(matchPath(path,name)) return true;
+    }
+
+    return false;
+  }
+
+  private static boolean matchPath(String path, String name){
+    List<String> pathSplit = StrUtils.splitSmart(path, '/');
+    List<String> nameSplit = StrUtils.splitSmart(name, '/');
+    for (int i = 0; i < nameSplit.size(); i++) {
+      String s = nameSplit.get(i);
+      String ps = pathSplit.size()>i ?  pathSplit.get(i) :null;
+      if(ps == null) return false;
+      if(s.equals(ps)) continue;
+      if("*".equals(ps) && nameSplit.size()==i+1) return true;
+      if("**".equals(ps)) return true;
+      return false;
+    }
+    return true;
+
+  }
+
+  public void apply(NamedList initArgs) {
+    merge(defaults, (NamedList) initArgs.get(PluginInfo.DEFAULTS), initArgs, PluginInfo.DEFAULTS, false);
+    merge((NamedList) initArgs.get(PluginInfo.INVARIANTS), invariants, initArgs, PluginInfo.INVARIANTS, false);
+    merge((NamedList) initArgs.get(PluginInfo.APPENDS), appends, initArgs, PluginInfo.APPENDS, true);
+  }
+
+  private static  void merge(NamedList first, NamedList second, NamedList sink, String name, boolean appends) {
+    if(first == null && second == null) return;
+    if(first == null) first = new NamedList();
+    NamedList nl = first.clone();
+    if(appends) {
+      nl.addAll(second);
+    } else {
+      Set<String> a = new HashSet<>();
+      Set<String> b = new HashSet<>();
+      for (Object o : first)    {
+        Map.Entry<String,Object> e = (Map.Entry) o;
+        a.add(e.getKey() );
+      }
+      if(second!=null) {
+        for (Object o : second) {
+          Map.Entry<String, Object> e = (Map.Entry) o;
+          b.add(e.getKey());
+        }
+      }
+      for (String s : b) {
+        if (a.contains(s)) continue;
+        for (Object v : second.getAll(s)) nl.add(s, v);
+      }
+    }
+    if(sink.indexOf(name,0) >-1) {
+      sink.setVal(sink.indexOf(name, 0), nl);
+    } else {
+      sink.add(name,nl);
+    }
+  }
+}

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java?rev=1621414&r1=1621413&r2=1621414&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/PluginInfo.java Sat Aug 30 02:53:26 2014
@@ -111,4 +111,7 @@ public class PluginInfo {
                    "str",
                    "int","long",
                    "float","double"));
+  public static final String DEFAULTS = "defaults";
+  public static final String APPENDS = "appends";
+  public static final String INVARIANTS = "invariants";
 }

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java?rev=1621414&r1=1621413&r2=1621414&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/RequestHandlers.java Sat Aug 30 02:53:26 2014
@@ -31,6 +31,7 @@ import org.apache.solr.common.SolrExcept
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.SolrQueryResponse;
@@ -178,8 +179,9 @@ public final class RequestHandlers {
     for (Map.Entry<PluginInfo,SolrRequestHandler> entry : handlers.entrySet()) {
       PluginInfo info = entry.getKey();
       SolrRequestHandler requestHandler = entry.getValue();
+      info = applyParamSet(config, info);
       if (requestHandler instanceof PluginInfoInitialized) {
-        ((PluginInfoInitialized) requestHandler).init(info);
+       ((PluginInfoInitialized) requestHandler).init(info);
       } else{
         requestHandler.init(info.initArgs);
       }
@@ -190,7 +192,28 @@ public final class RequestHandlers {
     if(get("") == null)
       log.warn("no default request handler is registered (either '/select' or 'standard')");
   }
-    
+
+  private PluginInfo applyParamSet(SolrConfig config, PluginInfo info) {
+    List<ParamSet> paramSets= new ArrayList<>();
+    String p = info.attributes.get("paramSet");
+    if(p!=null) {
+      for (String paramSet : StrUtils.splitSmart(p, ',')) {
+        if(config.getParamSets().containsKey(paramSet)) paramSets.add(config.getParamSets().get(paramSet));
+        else log.warn("INVALID paramSet {} in requestHandler {}", paramSet, info.toString());
+      }
+    }
+    for (ParamSet paramSet : config.getParamSets().values()) {
+      if(paramSet.matchPath(info.name)) paramSets.add(paramSet);
+    }
+    if(!paramSets.isEmpty()){
+      info = new PluginInfo(info.type, info.attributes, info.initArgs.clone(), info.children);
+      for (ParamSet paramSet : paramSets) {
+        paramSet.apply(info.initArgs);
+      }
+    }
+    return info;
+  }
+
 
   /**
    * The <code>LazyRequestHandlerWrapper</code> wraps any {@link SolrRequestHandler}.  

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java?rev=1621414&r1=1621413&r2=1621414&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/core/SolrConfig.java Sat Aug 30 02:53:26 2014
@@ -23,6 +23,8 @@ import org.apache.lucene.search.BooleanQ
 import org.apache.lucene.util.Version;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.handler.component.SearchComponent;
 import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.response.QueryResponseWriter;
@@ -57,10 +59,13 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -81,7 +86,7 @@ public class SolrConfig extends Config {
   
   public static final String DEFAULT_CONF_FILE = "solrconfig.xml";
 
-  static enum PluginOpts { 
+  static enum PluginOpts {
     MULTI_OK, 
     REQUIRE_NAME,
     REQUIRE_CLASS,
@@ -305,12 +310,27 @@ public class SolrConfig extends Config {
          "requestDispatcher/@handleSelect", true ); 
      
      addHttpRequestToContext = getBool( 
-         "requestDispatcher/requestParsers/@addHttpRequestToContext", false ); 
+         "requestDispatcher/requestParsers/@addHttpRequestToContext", false );
+
+    loadPluginInfo(ParamSet.class,ParamSet.TYPE);
+    List<PluginInfo> paramSetInfos =  pluginStore.get(ParamSet.class.getName()) ;
+    if(paramSetInfos!=null){
+      Map<String,ParamSet> paramSets = new HashMap<>();
+      for (PluginInfo p : paramSetInfos) {
+        ParamSet paramSet = new ParamSet(p);
+        paramSets.put(paramSet.name == null ? String.valueOf(paramSet.hashCode()) : paramSet.name , paramSet );
+      }
+      this.paramSets = Collections.unmodifiableMap(paramSets);
+
+    }
 
     solrRequestParsers = new SolrRequestParsers(this);
     Config.log.info("Loaded SolrConfig: " + name);
   }
-
+  private Map<String,ParamSet>  paramSets = Collections.emptyMap();
+  public Map<String, ParamSet> getParamSets() {
+    return paramSets;
+  }
   protected UpdateHandlerInfo loadUpdatehandlerInfo() {
     return new UpdateHandlerInfo(get("updateHandler/@class",null),
             getInt("updateHandler/autoCommit/maxDocs",-1),
@@ -607,4 +627,6 @@ public class SolrConfig extends Config {
   public boolean isEnableRemoteStreams() {
     return enableRemoteStreams;
   }
+
+
 }

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java?rev=1621414&r1=1621413&r2=1621414&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/DumpRequestHandler.java Sat Aug 30 02:53:26 2014
@@ -35,6 +35,21 @@ public class DumpRequestHandler extends 
   {
     // Show params
     rsp.add( "params", req.getParams().toNamedList() );
+    String[] returnParams = req.getParams().getParams("param");
+    if(returnParams !=null) {
+      NamedList params = (NamedList) rsp.getValues().get("params");
+      for (String returnParam : returnParams) {
+        String[] vals = req.getParams().getParams(returnParam);
+        if(vals != null){
+          for (String val : vals) {
+            params.add(returnParam,val);
+          }
+        }
+
+      }
+    }
+
+    if(Boolean.TRUE.equals( req.getParams().getBool("initArgs"))) rsp.add("initArgs", initArgs);
         
     // Write the streams...
     if( req.getContentStreams() != null ) {

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java?rev=1621414&r1=1621413&r2=1621414&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/SolrPluginUtils.java Sat Aug 30 02:53:26 2014
@@ -48,6 +48,7 @@ import org.apache.solr.common.params.Sol
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.core.ParamSet;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.handler.component.HighlightComponent;
 import org.apache.solr.handler.component.ResponseBuilder;
@@ -124,6 +125,17 @@ public class SolrPluginUtils {
    */
   public static void setDefaults(SolrQueryRequest req, SolrParams defaults,
                                  SolrParams appends, SolrParams invariants) {
+      String paramSetNames = req.getParams().get(ParamSet.TYPE);
+      if(paramSetNames !=null){
+        for (String name : StrUtils.splitSmart(paramSetNames,',')) {
+          ParamSet paramSet = req.getCore().getSolrConfig().getParamSets().get(name);
+          if(paramSet!=null){
+            if(paramSet.defaults != null) defaults = SolrParams.wrapDefaults(SolrParams.toSolrParams(paramSet.defaults) , defaults);
+            if(paramSet.invariants != null) invariants = SolrParams.wrapDefaults(invariants, SolrParams.toSolrParams(paramSet.invariants));
+            if(paramSet.appends != null)  appends = SolrParams.wrapAppended(appends, SolrParams.toSolrParams(paramSet.appends));
+          }
+        }
+      }
 
       SolrParams p = req.getParams();
       p = SolrParams.wrapDefaults(p, defaults);

Added: lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/solrconfig-paramset.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/solrconfig-paramset.xml?rev=1621414&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/solrconfig-paramset.xml (added)
+++ lucene/dev/trunk/solr/core/src/test-files/solr/collection1/conf/solrconfig-paramset.xml Sat Aug 30 02:53:26 2014
@@ -0,0 +1,58 @@
+<?xml version="1.0" ?>
+
+<!--
+ 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.
+-->
+
+<!-- a basic solrconfig that tests can use when they want simple minimal solrconfig/schema
+     DO NOT ADD THINGS TO THIS CONFIG! -->
+<config>
+  <luceneMatchVersion>${tests.luceneMatchVersion:LUCENE_CURRENT}</luceneMatchVersion>
+  <dataDir>${solr.data.dir:}</dataDir>
+  <xi:include href="solrconfig.snippet.randomindexconfig.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+  <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
+  <requestHandler name="standard" class="solr.StandardRequestHandler"/>
+  <requestHandler name="/update" class="solr.UpdateRequestHandler"/>
+  <paramSet name="a" path="/dump3,/root/*,/root1/**">
+    <lst name="defaults">
+      <str name="a">A</str>
+    </lst>
+    <lst name="invariants">
+      <str name="b">B</str>
+    </lst>
+    <lst name="appends">
+      <str name="c">C</str>
+    </lst>
+  </paramSet>
+  <requestHandler name="/dump3" class="DumpRequestHandler"/>
+  <requestHandler name="/dump4" class="DumpRequestHandler"/>
+  <requestHandler name="/root/dump5" class="DumpRequestHandler"/>
+  <requestHandler name="/root1/anotherlevel/dump6" class="DumpRequestHandler"/>
+  <requestHandler name="/dump1" class="DumpRequestHandler" paramSet="a"/>
+  <requestHandler name="/dump2" class="DumpRequestHandler" paramSet="a">
+    <lst name="defaults">
+      <str name="a">A1</str>
+    </lst>
+    <lst name="invariants">
+      <str name="b">B1</str>
+    </lst>
+    <lst name="appends">
+      <str name="c">C1</str>
+    </lst>
+  </requestHandler>
+
+
+</config>

Added: lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestParamSet.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestParamSet.java?rev=1621414&view=auto
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestParamSet.java (added)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/core/TestParamSet.java Sat Aug 30 02:53:26 2014
@@ -0,0 +1,80 @@
+package org.apache.solr.core;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.request.SolrRequestHandler;
+import org.apache.solr.response.SolrQueryResponse;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+public class TestParamSet  extends SolrTestCaseJ4 {
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-paramset.xml","schema.xml");
+  }
+  @Test
+  public void testComponentWithParamSet(){
+
+    for (String s : Arrays.asList("/dump1", "/dump3","/root/dump5" , "/root1/anotherlevel/dump6")) {
+      SolrRequestHandler handler = h.getCore().getRequestHandler(s);
+      SolrQueryResponse rsp = new SolrQueryResponse();
+      handler.handleRequest(req("initArgs", "true"), rsp);
+      NamedList nl = (NamedList) rsp.getValues().get("initArgs");
+      NamedList def = (NamedList) nl.get(PluginInfo.DEFAULTS);
+      assertEquals("A", def.get("a"));
+      def = (NamedList) nl.get(PluginInfo.INVARIANTS);
+      assertEquals("B", def.get("b"));
+      def = (NamedList) nl.get(PluginInfo.APPENDS);
+      assertEquals("C", def.get("c"));
+    }
+  }
+
+  @Test
+  public void testComponentWithParamSetRequestParam(){
+    for (String s : Arrays.asList("/dump4")) {
+      SolrRequestHandler handler = h.getCore().getRequestHandler(s);
+      SolrQueryResponse rsp = new SolrQueryResponse();
+      handler.handleRequest(req("param", "a","param","b" ,"param","c", "paramSet","a"), rsp);
+      NamedList def = (NamedList) rsp.getValues().get("params");
+      assertEquals("A", def.get("a"));
+      assertEquals("B", def.get("b"));
+      assertEquals("C", def.get("c"));
+    }
+  }
+  @Test
+  public void testComponentWithConflictingParamSet(){
+    SolrRequestHandler handler = h.getCore().getRequestHandler("/dump2");
+    SolrQueryResponse rsp = new SolrQueryResponse();
+    handler.handleRequest(req("initArgs", "true"), rsp);
+    NamedList nl = (NamedList) rsp.getValues().get("initArgs");
+    NamedList def = (NamedList) nl.get(PluginInfo.DEFAULTS);
+    assertEquals("A" ,def.get("a"));
+    def = (NamedList) nl.get(PluginInfo.INVARIANTS);
+    assertEquals("B1" ,def.get("b"));
+    def = (NamedList) nl.get(PluginInfo.APPENDS);
+    assertEquals(Arrays.asList("C1","C") ,def.getAll("c"));
+  }
+
+
+
+
+}

Modified: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java?rev=1621414&r1=1621413&r2=1621414&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java (original)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/NamedList.java Sat Aug 30 02:53:26 2014
@@ -21,6 +21,7 @@ import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -384,6 +385,11 @@ public class NamedList<T> implements Clo
     return sb.toString();
   }
 
+  public NamedList getImmutableCopy() {
+    NamedList copy = clone();
+    return new NamedList<>( Collections.unmodifiableList(copy.nvPairs));
+  }
+
   /**
    * 
    * Helper class implementing Map.Entry&lt;String, T&gt; to store the key-value