Repository: usergrid Updated Branches: refs/heads/feature-flags [created] 5b42c0a60
http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/main/java/org/apache/usergrid/rest/JobServiceBoostrap.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/JobServiceBoostrap.java b/stack/rest/src/main/java/org/apache/usergrid/rest/JobServiceBoostrap.java index ed45c91..2c262c7 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/JobServiceBoostrap.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/JobServiceBoostrap.java @@ -19,6 +19,7 @@ package org.apache.usergrid.rest; import org.apache.usergrid.batch.service.JobSchedulerService; import org.apache.usergrid.persistence.EntityManager; import org.apache.usergrid.services.notifications.QueueListener; +import org.apache.usergrid.system.UsergridFeatures; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -61,7 +62,7 @@ public class JobServiceBoostrap implements @Override public void onApplicationEvent( ContextRefreshedEvent event ) { String start = properties.getProperty( START_SCHEDULER_PROP, "true" ); - if ( Boolean.parseBoolean( start ) ) { + if ( Boolean.parseBoolean( start ) && (UsergridFeatures.isGraphFeatureEnabled() || UsergridFeatures.isQueryFeatureEnabled()) ) { logger.info( "Starting Scheduler Service..." ); jobScheduler.startAsync(); jobScheduler.awaitRunning(); http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/main/java/org/apache/usergrid/rest/RootResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/RootResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/RootResource.java index b8abe54..55f12e4 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/RootResource.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/RootResource.java @@ -34,6 +34,7 @@ import org.apache.usergrid.rest.applications.ApplicationResource; import org.apache.usergrid.rest.exceptions.NoOpException; import org.apache.usergrid.rest.organizations.OrganizationResource; import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; +import org.apache.usergrid.system.UsergridFeatures; import org.apache.usergrid.system.UsergridSystemMonitor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -197,8 +198,10 @@ public class RootResource extends AbstractContextResource implements MetricProce // Core Persistence Collections module status node.put( "cassandraStatus", emf.getEntityStoreHealth().toString() ); - // Core Persistence Query Index module status for Management App Index - node.put( "managementAppIndexStatus", emf.getIndexHealth().toString() ); + if(UsergridFeatures.isQueryFeatureEnabled()) { + // Core Persistence Query Index module status for Management App Index + node.put("managementAppIndexStatus", emf.getIndexHealth().toString()); + } dumpMetrics(node); http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ApplicationResource.java ---------------------------------------------------------------------- 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 9836f1c..228598c 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 @@ -41,6 +41,7 @@ import org.apache.usergrid.rest.AbstractContextResource; import org.apache.usergrid.rest.ApiResponse; import org.apache.usergrid.rest.applications.assets.AssetsResource; import org.apache.usergrid.rest.applications.events.EventsResource; +import org.apache.usergrid.rest.applications.kvm.KvmResource; import org.apache.usergrid.rest.applications.queues.QueueResource; import org.apache.usergrid.rest.applications.users.UsersResource; import org.apache.usergrid.rest.exceptions.AuthErrorInfo; @@ -147,6 +148,12 @@ public class ApplicationResource extends CollectionResource { return getEventsResource( ui ); } + //@RequireApplicationAccess + @Path("maps") + public KvmResource getKvmResource(@Context UriInfo ui ) throws Exception { + return getSubResource( KvmResource.class ); + } + @RequireApplicationAccess @Path("assets") http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ServiceResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ServiceResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ServiceResource.java index 91c7db9..c2e61a9 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ServiceResource.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/ServiceResource.java @@ -81,7 +81,7 @@ public class ServiceResource extends AbstractContextResource { @Autowired private AwsSdkS3BinaryStore awsSdkS3BinaryStore; - protected ServiceManager services; + public ServiceManager services; List<ServiceParameter> serviceParameters = null; http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/main/java/org/apache/usergrid/rest/applications/kvm/KvmResource.java ---------------------------------------------------------------------- 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 new file mode 100644 index 0000000..264f968 --- /dev/null +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/applications/kvm/KvmResource.java @@ -0,0 +1,358 @@ +/* + * 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.usergrid.rest.applications.kvm; + +import com.google.inject.Injector; +import org.apache.commons.lang.StringUtils; +import org.apache.usergrid.persistence.map.MapKeyResults; +import org.apache.usergrid.persistence.map.MapManager; +import org.apache.usergrid.persistence.map.MapManagerFactory; +import org.apache.usergrid.persistence.map.MapScope; +import org.apache.usergrid.persistence.map.impl.MapScopeImpl; +import org.apache.usergrid.rest.AbstractContextResource; +import org.apache.usergrid.rest.ApiResponse; +import org.apache.usergrid.rest.applications.ServiceResource; +import org.apache.usergrid.services.ServiceManager; +import org.apache.usergrid.utils.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import rx.Observable; + +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriInfo; +import java.util.*; + +@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" +}) +public class KvmResource extends AbstractContextResource { + + private static final Logger logger = LoggerFactory.getLogger( KvmResource.class ); + + + private final int PAGE_SIZE_MAX = 1000; + private final int PAGE_SIZE_DEFAULT = 10; + private final int BATCH_SIZE_MAX = 10; + + ServiceManager services = null; + + @Autowired + private Injector injector; + + public KvmResource(){ + if(logger.isTraceEnabled()) { + logger.trace("kvm.KvmResource"); + } + } + + @Override + public void setParent( AbstractContextResource parent ) { + super.setParent( parent ); + if ( parent instanceof ServiceResource ) { + services = ( ( ServiceResource ) parent ).services; + } + } + + @POST + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public ApiResponse createMap( @Context UriInfo ui, + Map<String, Object> json ) { + + if( json.keySet().size() < 1 ){ + throw new IllegalArgumentException("New map must be specified"); + } + if( json.keySet().size() > 1 ){ + throw new IllegalArgumentException("Only 1 map can be created at a time."); + } + + final String mapName = json.keySet().iterator().next(); + final Object meta = json.get(mapName); + if( !(meta instanceof Map) ){ + throw new IllegalArgumentException("New map details must be provided as a JSON object."); + } + + if(StringUtils.isEmpty(mapName)){ + throw new IllegalArgumentException("Property mapName is required."); + } + + 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); + + }}; + + mapManager.putString(mapName, JsonUtils.mapToJsonString(mapDetails)); + + // This used for response format + final Map<String, Object> map = new HashMap<>(2); + map.put(mapName, mapDetails); + + + ApiResponse response = createApiResponse(); + response.setAction( "post" ); + response.setApplication( services.getApplication() ); + response.setParams( ui.getQueryParameters() ); + response.setProperty("maps", Collections.singletonList(map)); + + return response; + + } + + + @GET + @Produces(MediaType.APPLICATION_JSON) + public ApiResponse getMaps( @Context UriInfo ui, + @QueryParam("limit") int limit, + @QueryParam("cursor") String cursor) { + + limit = validateLimit(limit); + + 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); + + MapKeyResults mapKeyResults = mapManager.getKeys(cursor, limit ); + + List<Map<String, Object>> results = new ArrayList<>(); + + Observable.from(mapKeyResults.getKeys()).flatMap(key -> { + return Observable.just(new HashMap<String, Object>() {{ + put(key, JsonUtils.parse(mapManager.getString(key))); + }}); + + }).doOnNext(entry -> results.add(entry)).toBlocking().lastOrDefault(null); + + + ApiResponse response = createApiResponse(); + response.setAction( "get" ); + response.setApplication( services.getApplication() ); + response.setParams( ui.getQueryParameters() ); + response.setProperty("maps", results); + + if( StringUtils.isNotEmpty(mapKeyResults.getCursor())){ + response.setProperty("cursor", mapKeyResults.getCursor()); + } + + return response; + + } + + @GET + @Path("{mapName}") + @Produces(MediaType.APPLICATION_JSON) + public ApiResponse getSingleMap( @Context UriInfo ui, + @QueryParam("limit") int limit, + @QueryParam("cursor") String cursor, + @PathParam("mapName") String mapName ) { + + limit = validateLimit(limit); + + 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); + + + Map<String, Object> map = new HashMap<>(); + map.put(mapName, JsonUtils.parse(mapManager.getString(mapName))); + + + ApiResponse response = createApiResponse(); + response.setAction( "get" ); + response.setApplication( services.getApplication() ); + response.setParams( ui.getQueryParameters() ); + response.setProperty("maps", Collections.singletonList(map)); + + return response; + + } + + + @POST + @Path("{mapName}/entries") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + public ApiResponse createEntries( @Context UriInfo ui, + List<Map<String,Object>> json, + @PathParam("mapName") String mapName ) { + + if ( json.size() > BATCH_SIZE_MAX ){ + throw new IllegalArgumentException("Batch size "+json.size()+" is more than max size of "+BATCH_SIZE_MAX); + } + + if(StringUtils.isEmpty(mapName)){ + throw new IllegalArgumentException("Property mapName is required."); + } + + 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); + + mapManager.putString(key, value.toString()); + + + }); + + + ApiResponse response = createApiResponse(); + response.setAction( "post" ); + response.setApplication( services.getApplication() ); + response.setParams( ui.getQueryParameters() ); + response.setProperty("mapName", mapName); + response.setProperty("entries", json); + + return response; + + } + + @GET + @Path("{mapName}/keys") + @Produces(MediaType.APPLICATION_JSON) + public ApiResponse getKeys( @Context UriInfo ui, + @QueryParam("limit") int limit, + @QueryParam("cursor") String cursor, + @PathParam("mapName") String mapName ) { + + + if(StringUtils.isEmpty(mapName)){ + throw new IllegalArgumentException("Property mapName is required."); + } + + limit = validateLimit(limit); + + final MapScope mapScope = new MapScopeImpl(services.getApplication().asId(), mapName); + final MapManagerFactory mmf = injector.getInstance(MapManagerFactory.class); + final MapManager mapManager = mmf.createMapManager(mapScope); + + MapKeyResults mapKeyResults = mapManager.getKeys(cursor, limit ); + + + ApiResponse response = createApiResponse(); + response.setAction( "get" ); + response.setApplication( services.getApplication() ); + response.setParams( ui.getQueryParameters() ); + response.setProperty("keys", mapKeyResults.getKeys()); + + if( StringUtils.isNotEmpty(mapKeyResults.getCursor())){ + response.setProperty("cursor", mapKeyResults.getCursor()); + } + + return response; + + } + + @GET + @Path("{mapName}/entries") + @Produces(MediaType.APPLICATION_JSON) + public ApiResponse getEntries( @Context UriInfo ui, + @QueryParam("limit") int limit, + @QueryParam("cursor") String cursor, + @PathParam("mapName") String mapName ) { + + if(StringUtils.isEmpty(mapName)){ + throw new IllegalArgumentException("Property mapName is required."); + } + + limit = validateLimit(limit); + + final MapScope mapScope = new MapScopeImpl(services.getApplication().asId(), mapName); + final MapManagerFactory mmf = injector.getInstance(MapManagerFactory.class); + final MapManager mapManager = mmf.createMapManager(mapScope); + + MapKeyResults mapKeyResults = mapManager.getKeys(cursor, limit ); + + List<Map<String, String>> results = new ArrayList<>(); + 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); + + + ApiResponse response = createApiResponse(); + response.setAction( "get" ); + response.setApplication( services.getApplication() ); + response.setParams( ui.getQueryParameters() ); + response.setProperty("entries", results); + + if( StringUtils.isNotEmpty(mapKeyResults.getCursor())){ + response.setProperty("cursor", mapKeyResults.getCursor()); + } + + return response; + + } + + @GET + @Path("{mapName}/entries/{keyName}") + @Produces(MediaType.APPLICATION_JSON) + public ApiResponse getEntry( @Context UriInfo ui, + @PathParam("mapName") String mapName, + @PathParam("keyName") String keyName ) { + + + 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));}}); + + + ApiResponse response = createApiResponse(); + response.setAction( "get" ); + response.setApplication( services.getApplication() ); + response.setParams( ui.getQueryParameters() ); + response.setProperty("entries", results); + + return response; + + } + + + private int validateLimit(final int limit){ + + return limit > 0 && limit < PAGE_SIZE_MAX ? limit : PAGE_SIZE_DEFAULT; + + } + + +} http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/UnsupportedOperationExceptionMapper.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/UnsupportedOperationExceptionMapper.java b/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/UnsupportedOperationExceptionMapper.java index 8f9455e..9f1d4b5 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/UnsupportedOperationExceptionMapper.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/exceptions/UnsupportedOperationExceptionMapper.java @@ -20,6 +20,7 @@ package org.apache.usergrid.rest.exceptions; import javax.ws.rs.core.Response; import javax.ws.rs.ext.Provider; +import static javax.ws.rs.core.Response.Status.BAD_REQUEST; import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR; import static javax.ws.rs.core.Response.Status.METHOD_NOT_ALLOWED; @@ -30,6 +31,6 @@ public class UnsupportedOperationExceptionMapper extends AbstractExceptionMapper @Override public Response toResponse( UnsupportedOperationException e ) { - return toResponse( INTERNAL_SERVER_ERROR, e ); + return toResponse( BAD_REQUEST, e ); } } http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/main/java/org/apache/usergrid/rest/system/IndexResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/system/IndexResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/system/IndexResource.java index be60177..d7a4eef 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/system/IndexResource.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/system/IndexResource.java @@ -35,6 +35,7 @@ import org.apache.usergrid.rest.AbstractContextResource; import org.apache.usergrid.rest.ApiResponse; import org.apache.usergrid.rest.RootResource; import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; +import org.apache.usergrid.system.UsergridFeatures; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Scope; @@ -358,4 +359,10 @@ public class IndexResource extends AbstractContextResource { return response; } + + @Override + public boolean isEnabled(){ + + return UsergridFeatures.isQueryFeatureEnabled(); + } } http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/main/java/org/apache/usergrid/rest/system/SystemResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/system/SystemResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/system/SystemResource.java index a83756d..72ca294 100644 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/system/SystemResource.java +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/system/SystemResource.java @@ -94,7 +94,6 @@ public class SystemResource extends AbstractContextResource { return getSubResource( MigrateResource.class ); } - @Path( "index" ) public IndexResource index() { return getSubResource( IndexResource.class ); } http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/AbstractRestIT.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/AbstractRestIT.java b/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/AbstractRestIT.java index 6e5e4f9..e25deb6 100644 --- a/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/AbstractRestIT.java +++ b/stack/rest/src/test/java/org/apache/usergrid/rest/test/resource/AbstractRestIT.java @@ -30,7 +30,6 @@ import org.apache.usergrid.rest.test.resource.model.Token; import org.apache.usergrid.rest.test.resource.state.ClientContext; import org.glassfish.jersey.client.ClientConfig; import org.glassfish.jersey.jackson.JacksonFeature; -import org.glassfish.jersey.test.DeploymentContext; import org.glassfish.jersey.test.JerseyTest; import org.glassfish.jersey.test.external.ExternalTestContainerFactory; import org.glassfish.jersey.test.spi.TestContainer; http://git-wip-us.apache.org/repos/asf/usergrid/blob/5b42c0a6/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java ---------------------------------------------------------------------- diff --git a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java index 21c6983..a2cdc80 100644 --- a/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java +++ b/stack/services/src/main/java/org/apache/usergrid/management/cassandra/ManagementServiceImpl.java @@ -70,6 +70,7 @@ import org.apache.usergrid.security.tokens.TokenInfo; import org.apache.usergrid.security.tokens.TokenService; import org.apache.usergrid.security.tokens.exceptions.TokenException; import org.apache.usergrid.services.*; +import org.apache.usergrid.system.UsergridFeatures; import org.apache.usergrid.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -166,7 +167,7 @@ public class ManagementServiceImpl implements ManagementService { protected CacheFactory cacheFactory; - protected AggregationServiceFactory aggregationServiceFactory; + protected AggregationServiceFactory aggregationServiceFactory = null; protected ApplicationService service; @@ -211,7 +212,13 @@ public class ManagementServiceImpl implements ManagementService { // Use the injector to get our guice dependencies this.lockManager = injector.getInstance(LockManager.class); this.cacheFactory = injector.getInstance( CacheFactory.class ); - this.aggregationServiceFactory = injector.getInstance(AggregationServiceFactory.class); + + if(UsergridFeatures.isQueryFeatureEnabled()) { + + this.aggregationServiceFactory = injector.getInstance(AggregationServiceFactory.class); + + + } this.service = injector.getInstance(ApplicationService.class); this.localShiroCache = injector.getInstance(LocalShiroCache.class);
