Update the KVM resource endpoints to be more client friendly.
diff --git a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java index 87a8649..489ffdf 100644 --- a/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java +++ b/stack/core/src/main/java/org/apache/usergrid/corepersistence/CpEntityManager.java
@@ -290,8 +290,11 @@ public <A extends Entity> A create( String entityType, Class<A> entityClass, Map<String, Object> properties ) throws Exception { - if ( ( entityType != null ) && ( entityType.startsWith( TYPE_ENTITY ) || entityType - .startsWith( "entities" ) ) ) { + if ( ( entityType != null ) && + ( entityType.startsWith( TYPE_ENTITY ) || entityType.startsWith( "entities" ) + // safeguard against creating entities with type keyvaluemaps since we have specific Usergrid + // keyvaluemap implementation + || entityType.startsWith( "keyvaluemaps" ) || entityType.startsWith( "keyvaluemap" )) ) { throw new IllegalArgumentException( "Invalid entity type" ); } A e = null;
diff --git a/stack/core/src/main/java/org/apache/usergrid/system/UsergridFeatures.java b/stack/core/src/main/java/org/apache/usergrid/system/UsergridFeatures.java index 22ba48c..2826f66 100644 --- a/stack/core/src/main/java/org/apache/usergrid/system/UsergridFeatures.java +++ b/stack/core/src/main/java/org/apache/usergrid/system/UsergridFeatures.java
@@ -63,7 +63,7 @@ public static boolean isKvmFeatureEnabled(){ - return getFeaturesEnabled().contains(Feature.KVM); + return true; } }
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ApplicationResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ApplicationResource.java index 228598c..e73277c 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ApplicationResource.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ApplicationResource.java
@@ -148,8 +148,8 @@ return getEventsResource( ui ); } - //@RequireApplicationAccess - @Path("maps") + @RequireApplicationAccess + @Path("keyvaluemaps") public KvmResource getKvmResource(@Context UriInfo ui ) throws Exception { return getSubResource( KvmResource.class ); }
diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/applications/kvm/KvmResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/kvm/KvmResource.java index 264f968..4d6107e 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/applications/kvm/KvmResource.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/kvm/KvmResource.java
@@ -43,9 +43,7 @@ @Component("org.apache.usergrid.rest.applications.kvm.KvmResource") @Scope("prototype") -@Produces({ MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", - "application/ecmascript", "text/jscript" -}) +@Produces(MediaType.APPLICATION_JSON) public class KvmResource extends AbstractContextResource { private static final Logger logger = LoggerFactory.getLogger( KvmResource.class ); @@ -87,26 +85,34 @@ throw new IllegalArgumentException("Only 1 map can be created at a time."); } + enforceQueryFeature(ui); + final String mapName = json.keySet().iterator().next(); - final Object meta = json.get(mapName); - if( !(meta instanceof Map) ){ + + if( !(json.get(mapName) instanceof Map) ){ throw new IllegalArgumentException("New map details must be provided as a JSON object."); } + final Map<String, Object> meta = (Map<String, Object>)json.get(mapName); if(StringUtils.isEmpty(mapName)){ throw new IllegalArgumentException("Property mapName is required."); } + if( json.containsKey("metadata") ){ + json.remove("metadata"); + } + final String appMap = services.getApplicationId().toString(); final MapScope mapScope = new MapScopeImpl(services.getApplication().asId(), appMap); final MapManagerFactory mmf = injector.getInstance(MapManagerFactory.class); final MapManager mapManager = mmf.createMapManager(mapScope); final Map<String, Object> mapDetails = new HashMap<String, Object>(){{ - - put("active", true); - put("modified", System.currentTimeMillis() ); - put("details", meta); + put("metadata", new HashMap<String, Object>(){{ + put("active", true); + put("modified", System.currentTimeMillis() ); + }}); + putAll(meta); }}; @@ -121,7 +127,7 @@ response.setAction( "post" ); response.setApplication( services.getApplication() ); response.setParams( ui.getQueryParameters() ); - response.setProperty("maps", Collections.singletonList(map)); + response.setProperty("maps", map); return response; @@ -135,6 +141,7 @@ @QueryParam("cursor") String cursor) { limit = validateLimit(limit); + enforceQueryFeature(ui); final String appMap = services.getApplicationId().toString(); @@ -144,14 +151,12 @@ MapKeyResults mapKeyResults = mapManager.getKeys(cursor, limit ); - List<Map<String, Object>> results = new ArrayList<>(); + Map<String, Object> results = new HashMap<>(); Observable.from(mapKeyResults.getKeys()).flatMap(key -> { - return Observable.just(new HashMap<String, Object>() {{ - put(key, JsonUtils.parse(mapManager.getString(key))); - }}); + return Observable.just(results.put(key, JsonUtils.parse(mapManager.getString(key)))); - }).doOnNext(entry -> results.add(entry)).toBlocking().lastOrDefault(null); + }).toBlocking().lastOrDefault(null); ApiResponse response = createApiResponse(); @@ -177,6 +182,7 @@ @PathParam("mapName") String mapName ) { limit = validateLimit(limit); + enforceQueryFeature(ui); final String appMap = services.getApplicationId().toString(); @@ -193,7 +199,7 @@ response.setAction( "get" ); response.setApplication( services.getApplication() ); response.setParams( ui.getQueryParameters() ); - response.setProperty("maps", Collections.singletonList(map)); + response.setProperty("maps", map); return response; @@ -205,7 +211,7 @@ @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public ApiResponse createEntries( @Context UriInfo ui, - List<Map<String,Object>> json, + Map<String,Object> json, @PathParam("mapName") String mapName ) { if ( json.size() > BATCH_SIZE_MAX ){ @@ -216,19 +222,17 @@ throw new IllegalArgumentException("Property mapName is required."); } + enforceQueryFeature(ui); + final MapScope mapScope = new MapScopeImpl(services.getApplication().asId(), mapName); final MapManagerFactory mmf = injector.getInstance(MapManagerFactory.class); final MapManager mapManager = mmf.createMapManager(mapScope); //TODO maybe RX flatmap this or parallel stream - json.forEach( item -> { - - String key = item.keySet().iterator().next(); - Object value = item.get(key); + json.forEach( (key, value) -> { mapManager.putString(key, value.toString()); - }); @@ -236,7 +240,6 @@ response.setAction( "post" ); response.setApplication( services.getApplication() ); response.setParams( ui.getQueryParameters() ); - response.setProperty("mapName", mapName); response.setProperty("entries", json); return response; @@ -257,6 +260,7 @@ } limit = validateLimit(limit); + enforceQueryFeature(ui); final MapScope mapScope = new MapScopeImpl(services.getApplication().asId(), mapName); final MapManagerFactory mmf = injector.getInstance(MapManagerFactory.class); @@ -264,7 +268,6 @@ MapKeyResults mapKeyResults = mapManager.getKeys(cursor, limit ); - ApiResponse response = createApiResponse(); response.setAction( "get" ); response.setApplication( services.getApplication() ); @@ -292,6 +295,7 @@ } limit = validateLimit(limit); + enforceQueryFeature(ui); final MapScope mapScope = new MapScopeImpl(services.getApplication().asId(), mapName); final MapManagerFactory mmf = injector.getInstance(MapManagerFactory.class); @@ -299,11 +303,10 @@ MapKeyResults mapKeyResults = mapManager.getKeys(cursor, limit ); - List<Map<String, String>> results = new ArrayList<>(); + Map<String, Object> results = new HashMap<>(); Observable.from(mapKeyResults.getKeys()).flatMap(key ->{ - return Observable.just(new HashMap<String, String>(){{put(key, mapManager.getString(key));}}); - - }).doOnNext(entry -> results.add(entry)).toBlocking().lastOrDefault(null); + return Observable.just(results.put(key, mapManager.getString(key))); + }).toBlocking().lastOrDefault(null); ApiResponse response = createApiResponse(); @@ -323,27 +326,34 @@ @GET @Path("{mapName}/entries/{keyName}") @Produces(MediaType.APPLICATION_JSON) - public ApiResponse getEntry( @Context UriInfo ui, + public Object getEntry( @Context UriInfo ui, @PathParam("mapName") String mapName, - @PathParam("keyName") String keyName ) { + @PathParam("keyName") String keyName, + @QueryParam("rawData") @DefaultValue("false") boolean rawData) { + enforceQueryFeature(ui); final MapScope mapScope = new MapScopeImpl(services.getApplication().asId(), mapName); final MapManagerFactory mmf = injector.getInstance(MapManagerFactory.class); final MapManager mapManager = mmf.createMapManager(mapScope); - List<Map<String, String>> results = new ArrayList<>(); - results.add(new HashMap<String, String>(){{put(keyName, mapManager.getString(keyName));}}); + Map<String, Object> results = new HashMap<>(); + Object value = mapManager.getString(keyName); + results.put(keyName, value); + + if( !rawData ) { + ApiResponse response = createApiResponse(); + response.setAction("get"); + response.setApplication(services.getApplication()); + response.setParams(ui.getQueryParameters()); + response.setProperty("entries", results); + return response; + }else{ + return value; + } - ApiResponse response = createApiResponse(); - response.setAction( "get" ); - response.setApplication( services.getApplication() ); - response.setParams( ui.getQueryParameters() ); - response.setProperty("entries", results); - - return response; } @@ -354,5 +364,15 @@ } + private void enforceQueryFeature(UriInfo ui) { + + if( StringUtils.isNotEmpty(ui.getQueryParameters().getFirst("ql"))){ + + throw new IllegalArgumentException("Query feature not supported for keyvaluemaps"); + + } + + } + }