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 2015/08/11 16:28:50 UTC
svn commit: r1695308 - in /lucene/dev/trunk/solr:
core/src/java/org/apache/solr/handler/admin/
core/src/java/org/apache/solr/security/ core/src/java/org/apache/solr/util/
core/src/test/org/apache/solr/handler/admin/
core/src/test/org/apache/solr/securi...
Author: noble
Date: Tue Aug 11 14:28:50 2015
New Revision: 1695308
URL: http://svn.apache.org/r1695308
Log:
SOLR-7838: changed the permissions froma map to an array so that order is obvious
Modified:
lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java
lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java
lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java
lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java
lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java
lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/admin/SecurityConfHandler.java Tue Aug 11 14:28:50 2015
@@ -18,6 +18,7 @@ package org.apache.solr.handler.admin;
*/
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -141,9 +142,14 @@ public class SecurityConfHandler extends
}
public static Map<String, Object> getMapValue(Map<String, Object> lookupMap, String key) {
- Map<String, Object> roleMap = (Map<String, Object>) lookupMap.get(key);
- if (roleMap == null) lookupMap.put(key, roleMap = new LinkedHashMap<>());
- return roleMap;
+ Map<String, Object> m = (Map<String, Object>) lookupMap.get(key);
+ if (m == null) lookupMap.put(key, m = new LinkedHashMap<>());
+ return m;
+ }
+ public static List getListValue(Map<String, Object> lookupMap, String key) {
+ List l = (List) lookupMap.get(key);
+ if (l == null) lookupMap.put(key, l= new ArrayList());
+ return l;
}
@Override
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/security/RuleBasedAuthorizationPlugin.java Tue Aug 11 14:28:50 2015
@@ -39,6 +39,8 @@ import org.apache.solr.util.CommandOpera
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static java.util.Collections.singleton;
+import static org.apache.solr.handler.admin.SecurityConfHandler.getListValue;
import static org.apache.solr.handler.admin.SecurityConfHandler.getMapValue;
import static org.apache.solr.common.params.CommonParams.NAME;
import static org.apache.solr.common.util.Utils.getDeepCopy;
@@ -86,12 +88,15 @@ public class RuleBasedAuthorizationPlugi
@Override
public AuthorizationResponse authorize(AuthorizationContext context) {
List<AuthorizationContext.CollectionRequest> collectionRequests = context.getCollectionRequests();
- if (collectionRequests != null) {
- for (AuthorizationContext.CollectionRequest collreq : collectionRequests) {
- //check permissions for each collection
- MatchStatus flag = checkCollPerm(mapping.get(collreq.collectionName), context);
- if (flag != MatchStatus.NO_PERMISSIONS_FOUND) return flag.rsp;
- }
+ if (collectionRequests.isEmpty()) {
+ MatchStatus flag = checkCollPerm(mapping.get(""), context);
+ return flag.rsp;
+ }
+
+ for (AuthorizationContext.CollectionRequest collreq : collectionRequests) {
+ //check permissions for each collection
+ MatchStatus flag = checkCollPerm(mapping.get(collreq.collectionName), context);
+ if (flag != MatchStatus.NO_PERMISSIONS_FOUND) return flag.rsp;
}
//check global permissions.
MatchStatus flag = checkCollPerm(mapping.get(null), context);
@@ -160,12 +165,11 @@ public class RuleBasedAuthorizationPlugi
String roleName = (String) e.getKey();
usersVsRoles.put(roleName, readValueAsSet(map, roleName));
}
- map = getMapValue(initInfo, "permissions");
- for (Object o : map.entrySet()) {
- Map.Entry e = (Map.Entry) o;
+ List<Map> perms = getListValue(initInfo, "permissions");
+ for (Map o : perms) {
Permission p;
try {
- p = Permission.load((String) e.getKey(), (Map) e.getValue());
+ p = Permission.load(o);
} catch (Exception exp) {
log.error("Invalid permission ", exp);
continue;
@@ -175,8 +179,8 @@ public class RuleBasedAuthorizationPlugi
}
}
+ //this is to do optimized lookup of permissions for a given collection/path
private void add2Mapping(Permission permission) {
- //this is to do optimized lookup of permissions for a given collection/path
for (String c : permission.collections) {
WildCardSupportMap m = mapping.get(c);
if (m == null) mapping.put(c, m = new WildCardSupportMap());
@@ -186,7 +190,6 @@ public class RuleBasedAuthorizationPlugi
perms.add(permission);
}
}
-
}
/**
@@ -199,7 +202,14 @@ public class RuleBasedAuthorizationPlugi
static Set<String> readValueAsSet(Map m, String key) {
Set<String> result = new HashSet<>();
Object val = m.get(key);
- if (val == null) return null;
+ if (val == null) {
+ if("collection".equals(key)){
+ //for collection collection: null means a core admin/ collection admin request
+ // otherwise it means a request where collection name is ignored
+ return m.containsKey(key) ? singleton("") : singleton(null);
+ }
+ return null;
+ }
if (val instanceof Collection) {
Collection list = (Collection) val;
for (Object o : list) result.add(String.valueOf(o));
@@ -223,13 +233,15 @@ public class RuleBasedAuthorizationPlugi
private Permission() {
}
- static Permission load(String name, Map m) {
+ static Permission load(Map m) {
Permission p = new Permission();
+ String name = (String) m.get(NAME);
if (!m.containsKey("role")) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "role not specified");
p.role = readValueAsSet(m, "role");
if (well_known_permissions.containsKey(name)) {
HashSet<String> disAllowed = new HashSet<>(knownKeys);
- disAllowed.remove("role");
+ disAllowed.remove("role");//these are the only
+ disAllowed.remove(NAME);//allowed keys for well-known permissions
for (String s : disAllowed) {
if (m.containsKey(s))
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, s + " is not a valid key for the permission : " + name);
@@ -245,7 +257,7 @@ public class RuleBasedAuthorizationPlugi
return p;
}
- static final Set<String> knownKeys = ImmutableSet.of("collection", "role", "params", "path", "method");
+ static final Set<String> knownKeys = ImmutableSet.of("collection", "role", "params", "path", "method", NAME);
}
enum MatchStatus {
@@ -275,7 +287,7 @@ public class RuleBasedAuthorizationPlugi
}
return set;
}
- return set == null ? Collections.singleton(null) : set;
+ return set == null ? singleton(null) : set;
}
@Override
@@ -328,36 +340,53 @@ public class RuleBasedAuthorizationPlugi
Map<String, Object> dataMap = op.getDataMap();
if (op.hasError()) return null;
dataMap = getDeepCopy(dataMap, 3);
- dataMap.remove(NAME);
String before = (String) dataMap.remove("before");
for (String key : dataMap.keySet()) {
if (!Permission.knownKeys.contains(key)) op.addError("Unknown key, " + key);
}
try {
- Permission.load(name, dataMap);
+ Permission.load(dataMap);
} catch (Exception e) {
op.addError(e.getMessage());
return null;
}
- Map<String, Object> permissions = getMapValue(latestConf, "permissions");
- if (before == null) {
- permissions.put(name, dataMap);
- } else {
- Map<String, Object> permissionsCopy = new LinkedHashMap<>();
- for (Map.Entry<String, Object> e : permissions.entrySet()) {
- if (e.getKey().equals(before)) permissionsCopy.put(name, dataMap);
- permissionsCopy.put(e.getKey(), e.getValue());
- }
- if (!permissionsCopy.containsKey(name)) {
- op.addError("Invalid 'before' :" + before);
- return null;
+ List<Map> permissions = getListValue(latestConf, "permissions");
+ List<Map> permissionsCopy = new ArrayList<>();
+ boolean added = false;
+ for (Map e : permissions) {
+ Object n = e.get(NAME);
+ if (n.equals(before) || n.equals(name)) {
+ added = true;
+ permissionsCopy.add(dataMap);
}
- latestConf.put("permissions", permissionsCopy);
+ if (!n.equals(name)) permissionsCopy.add(e);
}
-
+ if (!added && before != null) {
+ op.addError("Invalid 'before' :" + before);
+ return null;
+ }
+ if (!added) permissionsCopy.add(dataMap);
+ latestConf.put("permissions", permissionsCopy);
return latestConf;
}
},
+ UPDATE_PERMISSION("update-permission") {
+ @Override
+ public Map<String, Object> edit(Map<String, Object> latestConf, CommandOperation op) {
+ String name = op.getStr(NAME);
+ if (op.hasError()) return null;
+ for (Map permission : (List<Map>) getListValue(latestConf, "permissions")) {
+ if (name.equals(permission.get(NAME))) {
+ LinkedHashMap copy = new LinkedHashMap<>(permission);
+ copy.putAll(op.getDataMap());
+ op.setCommandData(copy);
+ return SET_PERMISSION.edit(latestConf, op);
+ }
+ }
+ op.addError("No such permission " + name);
+ return null;
+ }
+ },
DELETE_PERMISSION("delete-permission") {
@Override
public Map<String, Object> edit(Map<String, Object> latestConf, CommandOperation op) {
@@ -366,13 +395,23 @@ public class RuleBasedAuthorizationPlugi
op.addError("Invalid command");
return null;
}
- Map<String, Object> p = getMapValue(latestConf, "permissions");
- for (String s : names) {
- if (p.remove(s) == null) {
- op.addError("Unknown permission : " + s);
- return null;
+ names = new ArrayList<>(names);
+ List<Map> copy = new ArrayList<>();
+ List<Map> p = getListValue(latestConf, "permissions");
+ for (Map map : p) {
+ Object n = map.get(NAME);
+ if (names.contains(n)) {
+ names.remove(n);
+ continue;
+ } else {
+ copy.add(map);
}
}
+ if (!names.isEmpty()) {
+ op.addError("Unknown permission name(s) " + names);
+ return null;
+ }
+ latestConf.put("permissions", copy);
return latestConf;
}
};
@@ -397,16 +436,20 @@ public class RuleBasedAuthorizationPlugi
" { " +
" security-edit :{" +
" path:['/admin/authentication','/admin/authorization']," +
+ " collection:null," +
" method:POST }," +
" security-read :{" +
" path:['/admin/authentication','/admin/authorization']," +
- " method:GET }," +
+ " collection:null," +
+ " method:GET}," +
" schema-edit :{" +
" method:POST," +
" path:'/schema/*'}," +
" collection-admin-edit :{" +
+ " collection:null," +
" path:'/admin/collections'}," +
" collection-admin-read :{" +
+ " collection:null," +
" path:'/admin/collections'}," +
" schema-read :{" +
" method:GET," +
Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/CommandOperation.java Tue Aug 11 14:28:50 2015
@@ -59,6 +59,9 @@ public class CommandOperation {
Object o = getMapVal(key);
return o == null ? def : String.valueOf(o);
}
+ public void setCommandData(Object o){
+ commandData = o;
+ }
public Map<String,Object> getDataMap() {
if (commandData instanceof Map) {
Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/admin/SecurityConfHandlerTest.java Tue Aug 11 14:28:50 2015
@@ -97,13 +97,56 @@ public class SecurityConfHandlerTest ext
List tomRoles = (List) userRoles.get("tom");
assertTrue(tomRoles.contains("admin"));
assertTrue(tomRoles.contains("dev"));
- Map permissions = (Map) authzconf.get("permissions");
+ List<Map> permissions = (List<Map>) authzconf.get("permissions");
assertEquals(2, permissions.size());
- for (Object p : permissions.entrySet()) {
- Map.Entry e = (Map.Entry) p;
- assertEquals("some-permission", e.getKey());
+ for (Map p : permissions) {
+ assertEquals("some-permission", p.get("name"));
break;
}
+
+
+ command = "{\n" +
+ "'set-permission':{'name': 'security-edit',\n" +
+ " 'role': ['admin','dev']\n" +
+ " }}";
+ req = new LocalSolrQueryRequest(null, new ModifiableSolrParams());
+ req.getContext().put("httpMethod","POST");
+ req.getContext().put("path","/admin/authorization");
+ o = new ContentStreamBase.ByteArrayStream(command.getBytes(StandardCharsets.UTF_8),"");
+ req.setContentStreams(Collections.singletonList(o));
+ rsp = new SolrQueryResponse();
+ handler.handleRequestBody(req, rsp);
+ authzconf = (Map) ((ConfigData) handler.m.get("/security.json")).data.get("authorization");
+ permissions = (List<Map>) authzconf.get("permissions");
+
+ Map p = permissions.get(1);
+ assertEquals("security-edit", p.get("name"));
+ List rol = (List) p.get("role");
+ assertEquals( "admin", rol.get(0));
+ assertEquals( "dev", rol.get(1));
+
+ command = "{\n" +
+ "'update-permission':{'name': 'some-permission',\n" +
+ " 'role': ['guest','admin']\n" +
+ " }}";
+ req = new LocalSolrQueryRequest(null, new ModifiableSolrParams());
+ req.getContext().put("httpMethod","POST");
+ req.getContext().put("path","/admin/authorization");
+ o = new ContentStreamBase.ByteArrayStream(command.getBytes(StandardCharsets.UTF_8),"");
+ req.setContentStreams(Collections.singletonList(o));
+ rsp = new SolrQueryResponse();
+ handler.handleRequestBody(req, rsp);
+ authzconf = (Map) ((ConfigData) handler.m.get("/security.json")).data.get("authorization");
+ permissions = (List<Map>) authzconf.get("permissions");
+
+ p = permissions.get(0);
+ assertEquals("some-permission", p.get("name"));
+ rol = (List) p.get("role");
+ assertEquals( "guest", rol.get(0));
+ assertEquals( "admin", rol.get(1));
+
+
+
command = "{\n" +
"'delete-permission': 'some-permission',\n" +
"'set-user-role':{'tom':null}\n" +
@@ -119,12 +162,15 @@ public class SecurityConfHandlerTest ext
authzconf = (Map) ((ConfigData) handler.m.get("/security.json")).data.get("authorization");
userRoles = (Map) authzconf.get("user-role");
assertEquals(0, userRoles.size());
- permissions = (Map) authzconf.get("permissions");
+ permissions = (List<Map>) authzconf.get("permissions");
assertEquals(1, permissions.size());
- assertNull(permissions.get("some-permission"));
+
+ for (Map permission : permissions) {
+ assertFalse("some-permission".equals(permission.get("name")));
+ }
command = "{\n" +
"'set-permission':{'name': 'security-edit',\n" +
- " 'method':'POST',"+ // security edit is a well-known permission , only role attribute should be provided
+ " 'method':'POST',"+ // -ve test security edit is a well-known permission , only role attribute should be provided
" 'role': 'admin'\n" +
" }}";
req = new LocalSolrQueryRequest(null, new ModifiableSolrParams());
@@ -136,7 +182,6 @@ public class SecurityConfHandlerTest ext
handler.handleRequestBody(req, rsp);
List l = (List) ((Map) ((List)rsp.getValues().get("errorMessages")).get(0)).get("errorMessages");
assertEquals(1, l.size());
-
}
Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/BasicAuthIntegrationTest.java Tue Aug 11 14:28:50 2015
@@ -131,7 +131,7 @@ public class BasicAuthIntegrationTest ex
r = cl.execute(httpPost);
assertEquals(200, r.getStatusLine().getStatusCode());
- verifySecurityStatus(cl, baseUrl+"/admin/authorization", "authorization/permissions/x-update/collection", "x", 20);
+ verifySecurityStatus(cl, baseUrl+"/admin/authorization", "authorization/permissions[1]/collection", "x", 20);
}
@@ -206,5 +206,5 @@ public class BasicAuthIntegrationTest ex
" 'authorization':{\n" +
" 'class':'solr.RuleBasedAuthorizationPlugin',\n" +
" 'user-role':{'solr':'admin'},\n" +
- " 'permissions':{'security-edit':{'role':'admin'}}}}";
+ " 'permissions':[{'name':'security-edit','role':'admin'}]}}";
}
Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/security/TestRuleBasedAuthorizationPlugin.java Tue Aug 11 14:28:50 2015
@@ -19,6 +19,7 @@ package org.apache.solr.security;
import java.nio.charset.StandardCharsets;
import java.security.Principal;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
@@ -44,21 +45,18 @@ public class TestRuleBasedAuthorizationP
" joe: [user]," +
" noble:[dev,user]" +
" }," +
- " permissions : {" +
- " schema-edit :{" +
- " role:admin" +
- " }," +
- " collection-admin-read :{" +
- " role:null" +
- " }," +
- " collection-admin-edit :{" +
- " role:admin" +
- " }," +
- " mycoll_update: {" +
+ " permissions : [" +
+ " {name:'schema-edit'," +
+ " role:admin}," +
+ " {name:'collection-admin-read'," +
+ " role:null}," +
+ " {name:collection-admin-edit ," +
+ " role:admin}," +
+ " {name:mycoll_update," +
" collection:mycoll," +
" path:'/update/*'," +
" role:[dev,admin]" +
- " }}}" ;
+ " }]}" ;
Map initConfig = (Map) Utils.fromJSON(jsonRules.getBytes(StandardCharsets.UTF_8));
RuleBasedAuthorizationPlugin plugin= new RuleBasedAuthorizationPlugin();
@@ -97,6 +95,7 @@ public class TestRuleBasedAuthorizationP
assertEquals(FORBIDDEN,authResp.statusCode);
values.put("resource","/admin/collections");
+ values.put("collectionRequests",new ArrayList<>());
values.put("params", new MapSolrParams(Collections.singletonMap("action", "LIST")));
values.put("httpMethod","GET");
authResp = plugin.authorize(context);
Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/util/TestUtils.java Tue Aug 11 14:28:50 2015
@@ -26,6 +26,7 @@ import java.util.Map;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.common.util.Utils;
import org.junit.Assert;
/**
@@ -154,4 +155,26 @@ public class TestUtils extends SolrTestC
assertEquals( num, NumberUtils.SortableStr2long(sortable, 0, sortable.length() ) );
assertEquals( Long.toString(num), NumberUtils.SortableStr2long(sortable) );
}
+
+ public void testUtilsJSPath(){
+
+ String json = "{\n" +
+ " 'authorization':{\n" +
+ " 'class':'solr.RuleBasedAuthorizationPlugin',\n" +
+ " 'user-role':{\n" +
+ " 'solr':'admin',\n" +
+ " 'harry':'admin'},\n" +
+ " 'permissions':[{\n" +
+ " 'name':'security-edit',\n" +
+ " 'role':'admin'},\n" +
+ " {\n" +
+ " 'name':'x-update',\n" +
+ " 'collection':'x',\n" +
+ " 'path':'/update/*',\n" +
+ " 'role':'dev'}],\n" +
+ " '':{'v':4}}}";
+ Map m = (Map) Utils.fromJSONString(json);
+ assertEquals("x-update", Utils.getObjectByPath(m,false, "authorization/permissions[1]/name"));
+
+ }
}
Modified: lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java?rev=1695308&r1=1695307&r2=1695308&view=diff
==============================================================================
--- lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java (original)
+++ lucene/dev/trunk/solr/solrj/src/java/org/apache/solr/common/util/Utils.java Tue Aug 11 14:28:50 2015
@@ -30,6 +30,8 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.solr.common.SolrException;
import org.noggit.CharArr;
@@ -121,16 +123,37 @@ public class Utils {
}
}
+ public static Object getObjectByPath(Map root, boolean onlyPrimitive, String hierarchy) {
+ return getObjectByPath(root, onlyPrimitive, StrUtils.splitSmart(hierarchy, '/'));
+ }
+
public static Object getObjectByPath(Map root, boolean onlyPrimitive, List<String> hierarchy) {
Map obj = root;
for (int i = 0; i < hierarchy.size(); i++) {
+ int idx = -1;
String s = hierarchy.get(i);
+ if (s.endsWith("]")) {
+ Matcher matcher = ARRAY_ELEMENT_INDEX.matcher(s);
+ if (matcher.find()) {
+ s = matcher.group(1);
+ idx = Integer.parseInt(matcher.group(2));
+ }
+ }
if (i < hierarchy.size() - 1) {
- if (!(obj.get(s) instanceof Map)) return null;
- obj = (Map) obj.get(s);
- if (obj == null) return null;
+ Object o = obj.get(s);
+ if (o == null) return null;
+ if (idx > -1) {
+ List l = (List) o;
+ o = idx < l.size() ? l.get(idx) : null;
+ }
+ if (!(o instanceof Map)) return null;
+ obj = (Map) o;
} else {
Object val = obj.get(s);
+ if (idx > -1) {
+ List l = (List) val;
+ val = idx < l.size() ? l.get(idx) : null;
+ }
if (onlyPrimitive && val instanceof Map) {
return null;
}
@@ -140,4 +163,7 @@ public class Utils {
return false;
}
+
+ public static final Pattern ARRAY_ELEMENT_INDEX = Pattern
+ .compile("(\\S*?)\\[(\\d+)\\]");
}