Moves system endpoints into the system package
Project: http://git-wip-us.apache.org/repos/asf/usergrid/repo Commit: http://git-wip-us.apache.org/repos/asf/usergrid/commit/7a4f36ab Tree: http://git-wip-us.apache.org/repos/asf/usergrid/tree/7a4f36ab Diff: http://git-wip-us.apache.org/repos/asf/usergrid/diff/7a4f36ab Branch: refs/heads/USERGRID-909 Commit: 7a4f36ab9c0e504133f80f4d0ad8a70d115ee4f4 Parents: 3b43624 Author: Todd Nine <tn...@apigee.com> Authored: Tue Oct 27 09:46:06 2015 -0600 Committer: Todd Nine <tn...@apigee.com> Committed: Tue Oct 27 09:46:06 2015 -0600 ---------------------------------------------------------------------- .../usergrid/rest/ApplicationsResource.java | 178 ---------- .../usergrid/rest/ConnectionResource.java | 199 ----------- .../apache/usergrid/rest/DatabaseResource.java | 98 ------ .../org/apache/usergrid/rest/IndexResource.java | 328 ------------------ .../apache/usergrid/rest/MigrateResource.java | 268 --------------- .../apache/usergrid/rest/SystemResource.java | 108 ------ .../rest/system/ApplicationsResource.java | 178 ++++++++++ .../rest/system/ConnectionResource.java | 202 +++++++++++ .../usergrid/rest/system/DatabaseResource.java | 100 ++++++ .../usergrid/rest/system/IndexResource.java | 331 +++++++++++++++++++ .../usergrid/rest/system/MigrateResource.java | 270 +++++++++++++++ .../usergrid/rest/system/SystemResource.java | 108 ++++++ 12 files changed, 1189 insertions(+), 1179 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/ApplicationsResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/ApplicationsResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/ApplicationsResource.java deleted file mode 100644 index 55cf0f6..0000000 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/ApplicationsResource.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * - * * Licensed to the Apache Software Foundation (ASF) under one or more - * * contributor license agreements. 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. For additional information regarding - * * copyright in this work, please see the NOTICE file in the top level - * * directory of this distribution. - * - */ -package org.apache.usergrid.rest; - -import com.sun.jersey.api.json.JSONWithPadding; -import org.apache.usergrid.corepersistence.service.StatusService; -import org.apache.usergrid.persistence.Entity; -import org.apache.usergrid.persistence.EntityManager; -import org.apache.usergrid.persistence.core.util.StringUtils; -import org.apache.usergrid.persistence.model.util.UUIDGenerator; -import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -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.HashMap; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * Classy class class. - */ -@Component -@Scope( "singleton" ) -@Produces( { - MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", - "application/ecmascript", "text/jscript" -} ) -public class ApplicationsResource extends AbstractContextResource { - - private static final Logger logger = LoggerFactory.getLogger(ApplicationsResource.class); - - - public ApplicationsResource() { - - logger.info( "ApplicationsResource initialized" ); - } { - - } - - @RequireSystemAccess - @DELETE - @Path( "{applicationId}" ) - public JSONWithPadding clearApplication( @Context UriInfo ui, - @PathParam("applicationId") UUID applicationId, - @QueryParam( "confirmApplicationName" ) String confirmApplicationName, - @QueryParam( "limit" ) int limit, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - if(confirmApplicationName == null){ - throw new IllegalArgumentException("please make add a QueryString for confirmApplicationName"); - } - - final UUID jobId = UUIDGenerator.newTimeUUID(); - - final EntityManager em = emf.getEntityManager(applicationId); - final String name = em.getApplication().getApplicationName(); - if(!name.toLowerCase().equals(confirmApplicationName.toLowerCase())){ - throw new IllegalArgumentException("confirmApplicationName: " + confirmApplicationName + " does not equal " + name); - } - final StatusService statusService = injector.getInstance(StatusService.class); - - final ApiResponse response = createApiResponse(); - - response.setAction( "clear application" ); - - logger.info("clearing up application"); - - - final Thread delete = new Thread() { - - @Override - public void run() { - final AtomicInteger itemsDeleted = new AtomicInteger(0); - try { - management.deleteAllEntities(applicationId, limit) - .map(id -> itemsDeleted.incrementAndGet()) - .doOnNext(count -> { - if( count % 100 == 0 ){ - Map<String,Object> map = new LinkedHashMap<>(); - map.put("count",itemsDeleted.intValue()); - final StatusService statusService = injector.getInstance(StatusService.class); - statusService.setStatus(applicationId, jobId, StatusService.Status.INPROGRESS,map) - .subscribe();//do not want to throw this exception - } - }) - .doOnCompleted(() -> { - Map<String, Object> map = new LinkedHashMap<>(); - map.put("count", itemsDeleted.intValue()); - final StatusService statusService = injector.getInstance(StatusService.class); - statusService.setStatus(applicationId, jobId, StatusService.Status.COMPLETE, map) - .toBlocking().lastOrDefault(null);//want to rethrow this exception - }) - .toBlocking().lastOrDefault(null);//expecting exception to be caught if job fails - - } catch ( Exception e ) { - Map<String,Object> map = new LinkedHashMap<>(); - map.put("exception",e); - try { - statusService.setStatus(applicationId, jobId, StatusService.Status.FAILED, map).toBlocking().lastOrDefault(null);//leave as subscribe if fails retry - }catch (Exception subE){ - logger.error("failed to update status "+jobId,subE); - } - logger.error( "Failed to delete appid:"+applicationId + " jobid:"+jobId+" count:"+itemsDeleted, e ); - } - } - }; - - delete.setName("Delete for app : " + applicationId + " job: " + jobId); - delete.setDaemon(true); - delete.start(); - - try { - //should throw exception if can't start - statusService.setStatus(applicationId, jobId, StatusService.Status.STARTED, new LinkedHashMap<>()).toBlocking().lastOrDefault(null); - }catch (Exception e){ - logger.error("failed to set status for " + jobId, e); - } - Map<String,Object> data = new HashMap<>(); - data.put("jobId",jobId); - data.put("status",StatusService.Status.STARTED); - response.setData(data); - response.setSuccess(); - return new JSONWithPadding( response, callback ); - } - - @RequireSystemAccess - @GET - @Path( "{applicationId}/job/{jobId}" ) - public JSONWithPadding getStatus( @Context UriInfo ui, - @PathParam("applicationId") UUID applicationId, - @PathParam("jobId") UUID jobId, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) throws Exception{ - final StatusService statusService = injector.getInstance(StatusService.class); - - final ApiResponse response = createApiResponse(); - - response.setAction( "clear application" ); - - StatusService.JobStatus jobStatus = statusService.getStatus(applicationId, jobId).toBlocking().lastOrDefault(null); - - Map<String,Object> data = new HashMap<>(); - data.put("jobId",jobId); - data.put( "status", jobStatus.getStatus().toString() ); - data.put( "metadata", jobStatus.getData() ); - response.setData(data); - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - - } - -} http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/ConnectionResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/ConnectionResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/ConnectionResource.java deleted file mode 100644 index dfa4781..0000000 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/ConnectionResource.java +++ /dev/null @@ -1,199 +0,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. - */ - -package org.apache.usergrid.rest; - - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import javax.ws.rs.DefaultValue; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -import org.apache.usergrid.corepersistence.service.ConnectionService; -import org.apache.usergrid.corepersistence.service.ConnectionServiceImpl; -import org.apache.usergrid.corepersistence.service.StatusService; -import org.apache.usergrid.corepersistence.util.CpNamingUtils; -import org.apache.usergrid.persistence.core.scope.ApplicationScope; -import org.apache.usergrid.persistence.index.query.Identifier; -import org.apache.usergrid.persistence.index.utils.UUIDUtils; -import org.apache.usergrid.persistence.model.util.UUIDGenerator; -import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; - -import com.google.common.base.Preconditions; -import com.sun.jersey.api.json.JSONWithPadding; - -import rx.Observable; -import rx.schedulers.Schedulers; - - -/** - * system/index/otherstuff - */ -@Component -@Scope( "singleton" ) -@Produces( { - MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", - "application/ecmascript", "text/jscript" -} ) -public class ConnectionResource extends AbstractContextResource { - - private static final Logger logger = LoggerFactory.getLogger( ConnectionResource.class ); - - public ConnectionResource() { - super(); - } - - - @RequireSystemAccess - @POST - @Path( "dedup/" + RootResource.APPLICATION_ID_PATH ) - public JSONWithPadding rebuildIndexesPost( @PathParam( "applicationId" ) String applicationIdStr, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - - logger.info( "Rebuilding all applications" ); - - final UUID applicationId = UUIDUtils.tryGetUUID( applicationIdStr ); - - Preconditions.checkNotNull( applicationId, "applicationId must be specified" ); - - return executeAndCreateResponse( applicationId, callback ); - } - - - @RequireSystemAccess - @GET - @Path( "dedup/{jobId: " + Identifier.UUID_REX + "}" ) - public JSONWithPadding rebuildIndexesGet( @PathParam( "jobId" ) String jobId, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - logger.info( "Getting status for index jobs" ); - - Preconditions.checkNotNull( jobId, "query param jobId must not be null" ); - - - final UUID jobUUID = UUIDUtils.tryGetUUID( jobId ); - - final StatusService.JobStatus - job = getStatusService().getStatus( CpNamingUtils.MANAGEMENT_APPLICATION_ID, jobUUID ).toBlocking().lastOrDefault( - null ); - - Preconditions.checkNotNull( job, "job with id '" + jobId + "' does not exist" ); - - - return createResult( job, callback ); - } - - - private ConnectionService getConnectionService() { - return injector.getInstance( ConnectionServiceImpl.class ); - } - - - private StatusService getStatusService() { - return injector.getInstance( StatusService.class ); - } - - - - /** - * Execute the request and return the response. - */ - private JSONWithPadding executeAndCreateResponse( final UUID applicationId, final String callback ) { - - final Observable<ApplicationScope> applicationScopeObservable = - Observable.just( CpNamingUtils.getApplicationScope( applicationId ) ); - - final UUID jobId = UUIDGenerator.newTimeUUID(); - - final StatusService statusService = getStatusService(); - final ConnectionService connectionService = getConnectionService(); - - final AtomicLong count = new AtomicLong( 0 ); - - //start de duping and run in the background - connectionService.deDupeConnections( applicationScopeObservable ).buffer( 10, TimeUnit.SECONDS, 1000 ) - .doOnNext( buffer -> { - - - final long runningTotal = count.addAndGet( buffer.size() ); - - final Map<String, Object> status = new HashMap<String, Object>() {{ - put( "countProcessed", runningTotal ); - put( "updatedTimestamp", System.currentTimeMillis() ); - }}; - - statusService.setStatus( CpNamingUtils.MANAGEMENT_APPLICATION_ID, jobId, - StatusService.Status.INPROGRESS, status ).toBlocking().lastOrDefault( null ); - } ).doOnSubscribe( () -> { - statusService.setStatus( CpNamingUtils.MANAGEMENT_APPLICATION_ID, jobId, StatusService.Status.STARTED, - new HashMap<>() ).toBlocking().lastOrDefault( null ); - } ).doOnCompleted( () -> { - - final long runningTotal = count.get(); - - final Map<String, Object> status = new HashMap<String, Object>() {{ - put( "countProcessed", runningTotal ); - put( "updatedTimestamp", System.currentTimeMillis() ); - }}; - - statusService - .setStatus( CpNamingUtils.MANAGEMENT_APPLICATION_ID, jobId, StatusService.Status.COMPLETE, status ); - } ).subscribeOn( Schedulers.newThread() ).subscribe(); - - - final StatusService.JobStatus status = new StatusService.JobStatus( jobId, StatusService.Status.STARTED, new HashMap<>( ) ); - return createResult( status, callback ); - } - - - /** - * Create a response with the specified data. - * @param jobStatus - * @param callback - * @return - */ - private JSONWithPadding createResult(final StatusService.JobStatus jobStatus, final String callback){ - - final ApiResponse response = createApiResponse(); - - response.setAction( "de-dup connections" ); - response.setProperty( "status", jobStatus ); - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } -} - - - http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/DatabaseResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/DatabaseResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/DatabaseResource.java deleted file mode 100644 index a8c5fee..0000000 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/DatabaseResource.java +++ /dev/null @@ -1,98 +0,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. - */ -package org.apache.usergrid.rest; - - -import javax.ws.rs.DefaultValue; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.UriInfo; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; - -import com.sun.jersey.api.json.JSONWithPadding; - - -@Component -@Scope( "singleton" ) -@Produces( { - MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", - "application/ecmascript", "text/jscript" -} ) -public class DatabaseResource extends AbstractContextResource { - - private static final Logger logger = LoggerFactory.getLogger( DatabaseResource.class ); - - - public DatabaseResource() { - logger.info( "DatabaseResource initialized" ); - } - - - @RequireSystemAccess - @PUT - @Path( "setup" ) - public JSONWithPadding runDatabaseSetup( @Context UriInfo ui, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - ApiResponse response = createApiResponse(); - response.setAction( "cassandra setup" ); - - logger.info( "Setting up Cassandra" ); - - - emf.setup(); - - - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } - - - @RequireSystemAccess - @PUT - @Path( "bootstrap" ) - public JSONWithPadding runSystemSetup( @Context UriInfo ui, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - ApiResponse response = createApiResponse(); - response.setAction( "cassandra setup" ); - - logger.info( "Setting up Cassandra" ); - - - emf.boostrap(); - management.setup(); - - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } -} - http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/IndexResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/IndexResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/IndexResource.java deleted file mode 100644 index a4a56bc..0000000 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/IndexResource.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * - * * Licensed to the Apache Software Foundation (ASF) under one or more - * * contributor license agreements. 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. For additional information regarding - * * copyright in this work, please see the NOTICE file in the top level - * * directory of this distribution. - * - */ - -package org.apache.usergrid.rest; - - -import com.google.common.base.Preconditions; -import com.sun.jersey.api.json.JSONWithPadding; -import org.apache.usergrid.corepersistence.index.ReIndexRequestBuilder; -import org.apache.usergrid.corepersistence.index.ReIndexRequestBuilderImpl; -import org.apache.usergrid.corepersistence.index.ReIndexService; -import org.apache.usergrid.persistence.EntityManager; -import org.apache.usergrid.persistence.index.utils.ConversionUtils; -import org.apache.usergrid.persistence.index.utils.UUIDUtils; -import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -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.HashMap; -import java.util.Map; -import java.util.UUID; - - -/** - * system/index/otherstuff - */ -@Component -@Scope( "singleton" ) -@Produces( { - MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", - "application/ecmascript", "text/jscript" -} ) -public class IndexResource extends AbstractContextResource { - - private static final Logger logger = LoggerFactory.getLogger( IndexResource.class ); - private static final String UPDATED_FIELD = "updated"; - - - - public IndexResource() { - super(); - } - - - @RequireSystemAccess - @POST - @Path( "rebuild" ) - public JSONWithPadding rebuildIndexesPost( @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - - logger.info("Rebuilding all applications"); - - final ReIndexRequestBuilder request = createRequest(); - - return executeAndCreateResponse( request, callback ); - } - - @RequireSystemAccess - @GET - @Path( "rebuild/{jobId}" ) - public JSONWithPadding rebuildIndexesGet(@PathParam( "jobId" ) String jobId, @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - logger.info("Getting status for index jobs"); - - Preconditions - .checkNotNull(jobId, "query param jobId must not be null" ); - - - ReIndexService.ReIndexStatus status = getReIndexService().getStatus(jobId); - - final ApiResponse response = createApiResponse(); - - response.setAction( "rebuild indexes" ); - response.setProperty( "jobId", status.getJobId() ); - response.setProperty( "status", status.getStatus() ); - response.setProperty( "lastUpdatedEpoch", status.getLastUpdated() ); - response.setProperty( "numberQueued", status.getNumberProcessed() ); - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } - - @RequireSystemAccess - @PUT - @Path( "rebuild" ) - public JSONWithPadding rebuildIndexesPut( final Map<String, Object> payload, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - - logger.info( "Resuming rebuilding all applications" ); - final ReIndexRequestBuilder request = createRequest(); - - return executeResumeAndCreateResponse( payload, request, callback ); - } - - - @RequireSystemAccess - @POST - @Path( "rebuild/" + RootResource.APPLICATION_ID_PATH ) - public JSONWithPadding rebuildIndexesPut( @PathParam( "applicationId" ) String applicationIdStr, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback, - @QueryParam( "delay" ) @DefaultValue( "10" ) final long delay ) - - throws Exception { - - - logger.info( "Rebuilding application {}", applicationIdStr ); - - - final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); - - final ReIndexRequestBuilder request = createRequest().withApplicationId( appId ); - - return executeAndCreateResponse( request, callback ); - } - - - @RequireSystemAccess - @PUT - @Path( "rebuild/" + RootResource.APPLICATION_ID_PATH ) - public JSONWithPadding rebuildIndexesPut( final Map<String, Object> payload, - @PathParam( "applicationId" ) String applicationIdStr, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback, - @QueryParam( "delay" ) @DefaultValue( "10" ) final long delay ) - - throws Exception { - - logger.info( "Resuming rebuilding application {}", applicationIdStr ); - - final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); - - final ReIndexRequestBuilder request = createRequest().withApplicationId( appId ); - - return executeResumeAndCreateResponse( payload, request, callback ); - } - - - @RequireSystemAccess - @POST - @Path( "rebuild/" + RootResource.APPLICATION_ID_PATH + "/{collectionName}" ) - public JSONWithPadding rebuildIndexesPost( @PathParam( "applicationId" ) final String applicationIdStr, - @PathParam( "collectionName" ) final String collectionName, - @QueryParam( "reverse" ) @DefaultValue( "false" ) final Boolean reverse, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - - logger.info( "Rebuilding collection {} in application {}", collectionName, applicationIdStr ); - - final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); - - final ReIndexRequestBuilder request = - createRequest().withApplicationId( appId ).withCollection( collectionName ); - - return executeAndCreateResponse( request, callback ); - } - - - @RequireSystemAccess - @PUT - @Path( "rebuild/" + RootResource.APPLICATION_ID_PATH + "/{collectionName}" ) - public JSONWithPadding rebuildIndexesPut( final Map<String, Object> payload, - @PathParam( "applicationId" ) final String applicationIdStr, - @PathParam( "collectionName" ) final String collectionName, - @QueryParam( "reverse" ) @DefaultValue( "false" ) final Boolean reverse, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - logger.info( "Resuming rebuilding collection {} in application {}", collectionName, applicationIdStr ); - - final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); - - final ReIndexRequestBuilder request = - createRequest().withApplicationId( appId ).withCollection( collectionName ); - - return executeResumeAndCreateResponse( payload, request, callback ); - } - - - @RequireSystemAccess - @POST - @Path( "rebuild/management" ) - public JSONWithPadding rebuildInternalIndexesPost( - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) throws Exception { - - - final UUID managementAppId = emf.getManagementAppId(); - - logger.info( "Rebuilding management application with id {} ", managementAppId ); - final ReIndexRequestBuilder request = createRequest().withApplicationId( managementAppId ); - - return executeAndCreateResponse( request, callback ); - } - - - @RequireSystemAccess - @PUT - @Path( "rebuild/management" ) - public JSONWithPadding rebuildInternalIndexesPut( final Map<String, Object> payload, - @QueryParam( "callback" ) @DefaultValue( "callback" ) - String callback ) throws Exception { - - - final UUID managementAppId = emf.getManagementAppId(); - - logger.info( "Resuming rebuilding management application with id {} ", managementAppId ); - final ReIndexRequestBuilder request = createRequest().withApplicationId( managementAppId ); - - return executeResumeAndCreateResponse( payload, request, callback ); - } - - - @RequireSystemAccess - @POST - @Path(RootResource.APPLICATION_ID_PATH) - public JSONWithPadding addIndex( @Context UriInfo ui, - @PathParam( "applicationId" ) final String applicationIdStr, - Map<String, Object> config, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - Preconditions - .checkNotNull( config, "Payload for config is null, please pass {replicas:int, shards:int} in body" ); - - ApiResponse response = createApiResponse(); - - if ( !config.containsKey( "replicas" ) || !config.containsKey( "shards" ) || - !( config.get( "replicas" ) instanceof Integer ) || !( config.get( "shards" ) instanceof Integer ) ) { - throw new IllegalArgumentException( "body must contains 'replicas' of type int and 'shards' of type int" ); - } - - if ( !config.containsKey( "indexSuffix" ) ) { - throw new IllegalArgumentException( "Please add an indexSuffix to your post" ); - } - final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); - - if(appId == null){ - throw new IllegalArgumentException("app id was not parsed"); - } - - EntityManager em = emf.getEntityManager(appId); - em.addIndex(config.get("indexSuffix").toString(), (int) config.get("shards"), - (int) config.get("replicas"), (String) config.get("writeConsistency")); - response.setAction( "Add index to alias" ); - - return new JSONWithPadding( response, callback ); - } - - - private ReIndexService getReIndexService() { - return injector.getInstance( ReIndexService.class ); - } - - - private ReIndexRequestBuilder createRequest() { - //TODO: wire this up through spring, and in the future guice. - return new ReIndexRequestBuilderImpl(); - } - - - private JSONWithPadding executeResumeAndCreateResponse( final Map<String, Object> payload, - final ReIndexRequestBuilder request, - final String callback ) { - - Map<String,Object> newPayload = payload; - if(newPayload == null || !payload.containsKey( UPDATED_FIELD )){ - newPayload = new HashMap<>(1); - newPayload.put(UPDATED_FIELD,0); - } - - Preconditions.checkArgument(newPayload.get(UPDATED_FIELD) instanceof Number, - "You must specified the field \"updated\" in the payload and it must be a timestamp" ); - - //add our updated timestamp to the request - if ( newPayload.containsKey( UPDATED_FIELD ) ) { - final long timestamp = ConversionUtils.getLong(newPayload.get(UPDATED_FIELD)); - request.withStartTimestamp( timestamp ); - } - - return executeAndCreateResponse( request, callback ); - } - - - /** - * Execute the request and return the response. - */ - private JSONWithPadding executeAndCreateResponse( final ReIndexRequestBuilder request, final String callback ) { - - - final ReIndexService.ReIndexStatus status = getReIndexService().rebuildIndex( request ); - - final ApiResponse response = createApiResponse(); - - response.setAction( "rebuild indexes" ); - response.setProperty( "jobId", status.getJobId() ); - response.setProperty( "status", status.getStatus() ); - response.setProperty( "lastUpdatedEpoch", status.getLastUpdated() ); - response.setProperty( "numberQueued", status.getNumberProcessed() ); - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } -} http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/MigrateResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/MigrateResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/MigrateResource.java deleted file mode 100644 index 7410927..0000000 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/MigrateResource.java +++ /dev/null @@ -1,268 +0,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. - */ -package org.apache.usergrid.rest; - - -import java.util.Map; -import java.util.Set; - -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.UriInfo; - -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 org.apache.usergrid.persistence.core.migration.data.DataMigrationManager; -import org.apache.usergrid.persistence.core.migration.schema.MigrationManager; -import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; - -import com.fasterxml.jackson.databind.node.JsonNodeFactory; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.base.Preconditions; -import com.google.inject.Injector; -import com.sun.jersey.api.json.JSONWithPadding; - - -@Component -@Scope( "singleton" ) -@Produces( { - MediaType.APPLICATION_JSON, - "application/javascript", - "application/x-javascript", - "text/ecmascript", - "application/ecmascript", - "text/jscript" -} ) -public class MigrateResource extends AbstractContextResource { - - private static final Logger logger = LoggerFactory.getLogger( MigrateResource.class ); - - public MigrateResource() { - logger.info( "SystemResource initialized" ); - } - - @Autowired - private Injector guiceInjector; - - @RequireSystemAccess - @PUT - @Path( "run" ) - public JSONWithPadding migrateData( @Context UriInfo ui, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - ApiResponse response = createApiResponse(); - response.setAction( "Migrate Data" ); - //TODO make this use the task scheduler - - - final Thread migrate = new Thread() { - - @Override - public void run() { - - logger.info( "Migrating Schema" ); - - try { - getMigrationManager().migrate(); - } - catch ( Exception e ) { - logger.error( "Unable to migrate data", e ); - } - - logger.info( "Migrating Data" ); - - try { - getDataMigrationManager().migrate(); - } - catch ( Exception e ) { - logger.error( "Unable to migrate data", e ); - } - } - }; - - migrate.setName( "Index migrate data formats" ); - migrate.setDaemon( true ); - migrate.start(); - - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } - - @RequireSystemAccess - @PUT - @Path( "run/{pluginName}" ) - public JSONWithPadding migrateData(@PathParam("pluginName") String pluginName , @Context UriInfo ui, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - if(!getDataMigrationManager().pluginExists(pluginName)){ - throw new IllegalArgumentException("Plugin doesn't exits name:"+pluginName); - } - - ApiResponse response = createApiResponse(); - response.setAction( "Migrate Data: "+ pluginName ); - //TODO make this use the task scheduler - - - - - final Thread migrate = new Thread() { - - @Override - public void run() { - - logger.info( "Migrating Data for plugin: " + pluginName ); - - try { - getDataMigrationManager().migrate(pluginName); - } - catch ( Exception e ) { - logger.error( "Unable to migrate data for plugin: " + pluginName, e ); - } - } - }; - - migrate.setName( "Index migrate data formats: "+pluginName ); - migrate.setDaemon( true ); - migrate.start(); - - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } - - @RequireSystemAccess - @PUT - @Path( "set" ) - public JSONWithPadding setMigrationVersion( - @Context UriInfo ui, Map<String, Object> json, - @QueryParam( "callback" ) @DefaultValue( "" ) String callback ) - throws Exception { - - logger.debug( "setMigrationVersion" ); - - Preconditions.checkNotNull( json, "You must provide a json body" ); - Preconditions.checkArgument( json.keySet().size() > 0, "You must specify at least one module and version" ); - - ApiResponse response = createApiResponse(); - response.setAction("Set Migration Versions"); - - ObjectNode node = JsonNodeFactory.instance.objectNode(); - - final DataMigrationManager dataMigrationManager = getDataMigrationManager(); - final Set<String> plugins = dataMigrationManager.getPluginNames(); - - /** - * Set the migration version for the plugins specified - */ - for ( final String key : json.keySet() ) { - - int version = ( int ) json.get( key ); - - dataMigrationManager.resetToVersion(key, version); - } - - - /** - * Echo back a response of the current versions for all plugins - */ - for(final String pluginName: plugins){ - node.put(pluginName, dataMigrationManager.getCurrentVersion(pluginName)); - } - - - response.setData( node ); - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } - - - @RequireSystemAccess - @GET - @Path( "status" ) - public JSONWithPadding migrateStatus( - @Context UriInfo ui, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - ApiResponse response = createApiResponse(); - response.setAction( "Migrate Schema indexes" ); - - ObjectNode node = JsonNodeFactory.instance.objectNode(); - - - - final DataMigrationManager dataMigrationManager = getDataMigrationManager(); - - final Set<String> plugins = dataMigrationManager.getPluginNames(); - - for(final String pluginName: plugins){ - node.put( pluginName, dataMigrationManager.getCurrentVersion( pluginName ) ); - } - - response.setData( node ); - - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } - - - @RequireSystemAccess - @GET - @Path( "count" ) - public JSONWithPadding migrateCount( - @Context UriInfo ui, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - ApiResponse response = createApiResponse(); - response.setAction( "Current entity count in system" ); - - response.setProperty( "count", emf.performEntityCount() ); - - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } - - - /** - * Get the schema migration manager - */ - private MigrationManager getMigrationManager() { - return guiceInjector.getInstance( MigrationManager.class ); - } - - /** - * Get the Data migration manager - */ - private DataMigrationManager getDataMigrationManager() { - return guiceInjector.getInstance( DataMigrationManager.class ); - } -} - http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/SystemResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/SystemResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/SystemResource.java deleted file mode 100644 index aaee596..0000000 --- a/stack/rest/src/main/java/org/apache/usergrid/rest/SystemResource.java +++ /dev/null @@ -1,108 +0,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. - */ -package org.apache.usergrid.rest; - - -import javax.ws.rs.*; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.UriInfo; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; - -import com.sun.jersey.api.json.JSONWithPadding; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; - - -@Path( "/system" ) -@Component -@Scope( "singleton" ) -@Produces( { - MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", - "application/ecmascript", "text/jscript" -} ) -public class SystemResource extends AbstractContextResource { - - private static final Logger logger = LoggerFactory.getLogger( SystemResource.class ); - - - public SystemResource() { - logger.info( "SystemResource initialized" ); - } - - - @RequireSystemAccess - @GET - @Path( "superuser/setup" ) - public JSONWithPadding getSetupSuperuser( @Context UriInfo ui, - @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) - throws Exception { - - ApiResponse response = createApiResponse(); - response.setAction( "superuser setup" ); - - logger.info( "Setting up Superuser" ); - - try { - management.provisionSuperuser(); - } - catch ( Exception e ) { - logger.error( "Unable to complete superuser setup", e ); - } - - response.setSuccess(); - - return new JSONWithPadding( response, callback ); - } - - - - @Path( "migrate" ) - public MigrateResource migrate() { - return getSubResource( MigrateResource.class ); - } - - - @Path( "index" ) - public IndexResource index() { return getSubResource( IndexResource.class ); } - - - @Path( "database" ) - public DatabaseResource database() { - return getSubResource( DatabaseResource.class ); - } - - @Path( "applications" ) - public ApplicationsResource applications() { - return getSubResource( ApplicationsResource.class ); - } - - - @Path( "connection" ) - public ConnectionResource connection() { return getSubResource( ConnectionResource.class ); } - -} http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/system/ApplicationsResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/system/ApplicationsResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/system/ApplicationsResource.java new file mode 100644 index 0000000..82088f9 --- /dev/null +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/system/ApplicationsResource.java @@ -0,0 +1,178 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. 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. For additional information regarding + * * copyright in this work, please see the NOTICE file in the top level + * * directory of this distribution. + * + */ +package org.apache.usergrid.rest.system; + +import com.sun.jersey.api.json.JSONWithPadding; +import org.apache.usergrid.corepersistence.service.StatusService; +import org.apache.usergrid.persistence.EntityManager; +import org.apache.usergrid.persistence.model.util.UUIDGenerator; +import org.apache.usergrid.rest.AbstractContextResource; +import org.apache.usergrid.rest.ApiResponse; +import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +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.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Classy class class. + */ +@Component +@Scope( "singleton" ) +@Produces( { + MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", + "application/ecmascript", "text/jscript" +} ) +public class ApplicationsResource extends AbstractContextResource { + + private static final Logger logger = LoggerFactory.getLogger(ApplicationsResource.class); + + + public ApplicationsResource() { + + logger.info( "ApplicationsResource initialized" ); + } { + + } + + @RequireSystemAccess + @DELETE + @Path( "{applicationId}" ) + public JSONWithPadding clearApplication( @Context UriInfo ui, + @PathParam("applicationId") UUID applicationId, + @QueryParam( "confirmApplicationName" ) String confirmApplicationName, + @QueryParam( "limit" ) int limit, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + if(confirmApplicationName == null){ + throw new IllegalArgumentException("please make add a QueryString for confirmApplicationName"); + } + + final UUID jobId = UUIDGenerator.newTimeUUID(); + + final EntityManager em = emf.getEntityManager(applicationId); + final String name = em.getApplication().getApplicationName(); + if(!name.toLowerCase().equals(confirmApplicationName.toLowerCase())){ + throw new IllegalArgumentException("confirmApplicationName: " + confirmApplicationName + " does not equal " + name); + } + final StatusService statusService = injector.getInstance(StatusService.class); + + final ApiResponse response = createApiResponse(); + + response.setAction( "clear application" ); + + logger.info("clearing up application"); + + + final Thread delete = new Thread() { + + @Override + public void run() { + final AtomicInteger itemsDeleted = new AtomicInteger(0); + try { + management.deleteAllEntities(applicationId, limit) + .map(id -> itemsDeleted.incrementAndGet()) + .doOnNext(count -> { + if( count % 100 == 0 ){ + Map<String,Object> map = new LinkedHashMap<>(); + map.put("count",itemsDeleted.intValue()); + final StatusService statusService = injector.getInstance(StatusService.class); + statusService.setStatus(applicationId, jobId, StatusService.Status.INPROGRESS,map) + .subscribe();//do not want to throw this exception + } + }) + .doOnCompleted(() -> { + Map<String, Object> map = new LinkedHashMap<>(); + map.put("count", itemsDeleted.intValue()); + final StatusService statusService = injector.getInstance(StatusService.class); + statusService.setStatus(applicationId, jobId, StatusService.Status.COMPLETE, map) + .toBlocking().lastOrDefault(null);//want to rethrow this exception + }) + .toBlocking().lastOrDefault(null);//expecting exception to be caught if job fails + + } catch ( Exception e ) { + Map<String,Object> map = new LinkedHashMap<>(); + map.put("exception",e); + try { + statusService.setStatus(applicationId, jobId, StatusService.Status.FAILED, map).toBlocking().lastOrDefault(null);//leave as subscribe if fails retry + }catch (Exception subE){ + logger.error("failed to update status "+jobId,subE); + } + logger.error( "Failed to delete appid:"+applicationId + " jobid:"+jobId+" count:"+itemsDeleted, e ); + } + } + }; + + delete.setName("Delete for app : " + applicationId + " job: " + jobId); + delete.setDaemon(true); + delete.start(); + + try { + //should throw exception if can't start + statusService.setStatus(applicationId, jobId, StatusService.Status.STARTED, new LinkedHashMap<>()).toBlocking().lastOrDefault(null); + }catch (Exception e){ + logger.error("failed to set status for " + jobId, e); + } + Map<String,Object> data = new HashMap<>(); + data.put("jobId",jobId); + data.put("status",StatusService.Status.STARTED); + response.setData(data); + response.setSuccess(); + return new JSONWithPadding( response, callback ); + } + + @RequireSystemAccess + @GET + @Path( "{applicationId}/job/{jobId}" ) + public JSONWithPadding getStatus( @Context UriInfo ui, + @PathParam("applicationId") UUID applicationId, + @PathParam("jobId") UUID jobId, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) throws Exception{ + final StatusService statusService = injector.getInstance(StatusService.class); + + final ApiResponse response = createApiResponse(); + + response.setAction( "clear application" ); + + StatusService.JobStatus jobStatus = statusService.getStatus(applicationId, jobId).toBlocking().lastOrDefault(null); + + Map<String,Object> data = new HashMap<>(); + data.put("jobId",jobId); + data.put( "status", jobStatus.getStatus().toString() ); + data.put( "metadata", jobStatus.getData() ); + response.setData(data); + response.setSuccess(); + + return new JSONWithPadding( response, callback ); + + } + +} http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/system/ConnectionResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/system/ConnectionResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/system/ConnectionResource.java new file mode 100644 index 0000000..6e683ed --- /dev/null +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/system/ConnectionResource.java @@ -0,0 +1,202 @@ +/* + * 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.system; + + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import org.apache.usergrid.corepersistence.service.ConnectionService; +import org.apache.usergrid.corepersistence.service.ConnectionServiceImpl; +import org.apache.usergrid.corepersistence.service.StatusService; +import org.apache.usergrid.corepersistence.util.CpNamingUtils; +import org.apache.usergrid.persistence.core.scope.ApplicationScope; +import org.apache.usergrid.persistence.index.query.Identifier; +import org.apache.usergrid.persistence.index.utils.UUIDUtils; +import org.apache.usergrid.persistence.model.util.UUIDGenerator; +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 com.google.common.base.Preconditions; +import com.sun.jersey.api.json.JSONWithPadding; + +import rx.Observable; +import rx.schedulers.Schedulers; + + +/** + * system/index/otherstuff + */ +@Component +@Scope( "singleton" ) +@Produces( { + MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", + "application/ecmascript", "text/jscript" +} ) +public class ConnectionResource extends AbstractContextResource { + + private static final Logger logger = LoggerFactory.getLogger( ConnectionResource.class ); + + public ConnectionResource() { + super(); + } + + + @RequireSystemAccess + @POST + @Path( "dedup/" + RootResource.APPLICATION_ID_PATH ) + public JSONWithPadding rebuildIndexesPost( @PathParam( "applicationId" ) String applicationIdStr, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + + logger.info( "Rebuilding all applications" ); + + final UUID applicationId = UUIDUtils.tryGetUUID( applicationIdStr ); + + Preconditions.checkNotNull( applicationId, "applicationId must be specified" ); + + return executeAndCreateResponse( applicationId, callback ); + } + + + @RequireSystemAccess + @GET + @Path( "dedup/{jobId: " + Identifier.UUID_REX + "}" ) + public JSONWithPadding rebuildIndexesGet( @PathParam( "jobId" ) String jobId, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + logger.info( "Getting status for index jobs" ); + + Preconditions.checkNotNull( jobId, "query param jobId must not be null" ); + + + final UUID jobUUID = UUIDUtils.tryGetUUID( jobId ); + + final StatusService.JobStatus + job = getStatusService().getStatus( CpNamingUtils.MANAGEMENT_APPLICATION_ID, jobUUID ).toBlocking().lastOrDefault( + null ); + + Preconditions.checkNotNull( job, "job with id '" + jobId + "' does not exist" ); + + + return createResult( job, callback ); + } + + + private ConnectionService getConnectionService() { + return injector.getInstance( ConnectionServiceImpl.class ); + } + + + private StatusService getStatusService() { + return injector.getInstance( StatusService.class ); + } + + + + /** + * Execute the request and return the response. + */ + private JSONWithPadding executeAndCreateResponse( final UUID applicationId, final String callback ) { + + final Observable<ApplicationScope> applicationScopeObservable = + Observable.just( CpNamingUtils.getApplicationScope( applicationId ) ); + + final UUID jobId = UUIDGenerator.newTimeUUID(); + + final StatusService statusService = getStatusService(); + final ConnectionService connectionService = getConnectionService(); + + final AtomicLong count = new AtomicLong( 0 ); + + //start de duping and run in the background + connectionService.deDupeConnections( applicationScopeObservable ).buffer( 10, TimeUnit.SECONDS, 1000 ) + .doOnNext( buffer -> { + + + final long runningTotal = count.addAndGet( buffer.size() ); + + final Map<String, Object> status = new HashMap<String, Object>() {{ + put( "countProcessed", runningTotal ); + put( "updatedTimestamp", System.currentTimeMillis() ); + }}; + + statusService.setStatus( CpNamingUtils.MANAGEMENT_APPLICATION_ID, jobId, + StatusService.Status.INPROGRESS, status ).toBlocking().lastOrDefault( null ); + } ).doOnSubscribe( () -> { + statusService.setStatus( CpNamingUtils.MANAGEMENT_APPLICATION_ID, jobId, StatusService.Status.STARTED, + new HashMap<>() ).toBlocking().lastOrDefault( null ); + } ).doOnCompleted( () -> { + + final long runningTotal = count.get(); + + final Map<String, Object> status = new HashMap<String, Object>() {{ + put( "countProcessed", runningTotal ); + put( "updatedTimestamp", System.currentTimeMillis() ); + }}; + + statusService + .setStatus( CpNamingUtils.MANAGEMENT_APPLICATION_ID, jobId, StatusService.Status.COMPLETE, status ); + } ).subscribeOn( Schedulers.newThread() ).subscribe(); + + + final StatusService.JobStatus status = new StatusService.JobStatus( jobId, StatusService.Status.STARTED, new HashMap<>( ) ); + return createResult( status, callback ); + } + + + /** + * Create a response with the specified data. + * @param jobStatus + * @param callback + * @return + */ + private JSONWithPadding createResult(final StatusService.JobStatus jobStatus, final String callback){ + + final ApiResponse response = createApiResponse(); + + response.setAction( "de-dup connections" ); + response.setProperty( "status", jobStatus ); + response.setSuccess(); + + return new JSONWithPadding( response, callback ); + } +} + + + http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/stack/rest/src/main/java/org/apache/usergrid/rest/system/DatabaseResource.java ---------------------------------------------------------------------- diff --git a/stack/rest/src/main/java/org/apache/usergrid/rest/system/DatabaseResource.java b/stack/rest/src/main/java/org/apache/usergrid/rest/system/DatabaseResource.java new file mode 100644 index 0000000..42a63ca --- /dev/null +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/system/DatabaseResource.java @@ -0,0 +1,100 @@ +/* + * 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.system; + + +import javax.ws.rs.DefaultValue; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriInfo; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import org.apache.usergrid.rest.AbstractContextResource; +import org.apache.usergrid.rest.ApiResponse; +import org.apache.usergrid.rest.security.annotations.RequireSystemAccess; + +import com.sun.jersey.api.json.JSONWithPadding; + + +@Component +@Scope( "singleton" ) +@Produces( { + MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", + "application/ecmascript", "text/jscript" +} ) +public class DatabaseResource extends AbstractContextResource { + + private static final Logger logger = LoggerFactory.getLogger( DatabaseResource.class ); + + + public DatabaseResource() { + logger.info( "DatabaseResource initialized" ); + } + + + @RequireSystemAccess + @PUT + @Path( "setup" ) + public JSONWithPadding runDatabaseSetup( @Context UriInfo ui, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + ApiResponse response = createApiResponse(); + response.setAction( "cassandra setup" ); + + logger.info( "Setting up Cassandra" ); + + + emf.setup(); + + + response.setSuccess(); + + return new JSONWithPadding( response, callback ); + } + + + @RequireSystemAccess + @PUT + @Path( "bootstrap" ) + public JSONWithPadding runSystemSetup( @Context UriInfo ui, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + ApiResponse response = createApiResponse(); + response.setAction( "cassandra setup" ); + + logger.info( "Setting up Cassandra" ); + + + emf.boostrap(); + management.setup(); + + response.setSuccess(); + + return new JSONWithPadding( response, callback ); + } +} + http://git-wip-us.apache.org/repos/asf/usergrid/blob/7a4f36ab/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 new file mode 100644 index 0000000..8e2946c --- /dev/null +++ b/stack/rest/src/main/java/org/apache/usergrid/rest/system/IndexResource.java @@ -0,0 +1,331 @@ +/* + * + * * Licensed to the Apache Software Foundation (ASF) under one or more + * * contributor license agreements. 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. For additional information regarding + * * copyright in this work, please see the NOTICE file in the top level + * * directory of this distribution. + * + */ + +package org.apache.usergrid.rest.system; + + +import com.google.common.base.Preconditions; +import com.sun.jersey.api.json.JSONWithPadding; +import org.apache.usergrid.corepersistence.index.ReIndexRequestBuilder; +import org.apache.usergrid.corepersistence.index.ReIndexRequestBuilderImpl; +import org.apache.usergrid.corepersistence.index.ReIndexService; +import org.apache.usergrid.persistence.EntityManager; +import org.apache.usergrid.persistence.index.utils.ConversionUtils; +import org.apache.usergrid.persistence.index.utils.UUIDUtils; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +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.HashMap; +import java.util.Map; +import java.util.UUID; + + +/** + * system/index/otherstuff + */ +@Component +@Scope( "singleton" ) +@Produces( { + MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", + "application/ecmascript", "text/jscript" +} ) +public class IndexResource extends AbstractContextResource { + + private static final Logger logger = LoggerFactory.getLogger( IndexResource.class ); + private static final String UPDATED_FIELD = "updated"; + + + + public IndexResource() { + super(); + } + + + @RequireSystemAccess + @POST + @Path( "rebuild" ) + public JSONWithPadding rebuildIndexesPost( @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + + logger.info("Rebuilding all applications"); + + final ReIndexRequestBuilder request = createRequest(); + + return executeAndCreateResponse( request, callback ); + } + + @RequireSystemAccess + @GET + @Path( "rebuild/{jobId}" ) + public JSONWithPadding rebuildIndexesGet(@PathParam( "jobId" ) String jobId, @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + logger.info("Getting status for index jobs"); + + Preconditions + .checkNotNull(jobId, "query param jobId must not be null" ); + + + ReIndexService.ReIndexStatus status = getReIndexService().getStatus(jobId); + + final ApiResponse response = createApiResponse(); + + response.setAction( "rebuild indexes" ); + response.setProperty( "jobId", status.getJobId() ); + response.setProperty( "status", status.getStatus() ); + response.setProperty( "lastUpdatedEpoch", status.getLastUpdated() ); + response.setProperty( "numberQueued", status.getNumberProcessed() ); + response.setSuccess(); + + return new JSONWithPadding( response, callback ); + } + + @RequireSystemAccess + @PUT + @Path( "rebuild" ) + public JSONWithPadding rebuildIndexesPut( final Map<String, Object> payload, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + + logger.info( "Resuming rebuilding all applications" ); + final ReIndexRequestBuilder request = createRequest(); + + return executeResumeAndCreateResponse( payload, request, callback ); + } + + + @RequireSystemAccess + @POST + @Path( "rebuild/" + RootResource.APPLICATION_ID_PATH ) + public JSONWithPadding rebuildIndexesPut( @PathParam( "applicationId" ) String applicationIdStr, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback, + @QueryParam( "delay" ) @DefaultValue( "10" ) final long delay ) + + throws Exception { + + + logger.info( "Rebuilding application {}", applicationIdStr ); + + + final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); + + final ReIndexRequestBuilder request = createRequest().withApplicationId( appId ); + + return executeAndCreateResponse( request, callback ); + } + + + @RequireSystemAccess + @PUT + @Path( "rebuild/" + RootResource.APPLICATION_ID_PATH ) + public JSONWithPadding rebuildIndexesPut( final Map<String, Object> payload, + @PathParam( "applicationId" ) String applicationIdStr, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback, + @QueryParam( "delay" ) @DefaultValue( "10" ) final long delay ) + + throws Exception { + + logger.info( "Resuming rebuilding application {}", applicationIdStr ); + + final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); + + final ReIndexRequestBuilder request = createRequest().withApplicationId( appId ); + + return executeResumeAndCreateResponse( payload, request, callback ); + } + + + @RequireSystemAccess + @POST + @Path( "rebuild/" + RootResource.APPLICATION_ID_PATH + "/{collectionName}" ) + public JSONWithPadding rebuildIndexesPost( @PathParam( "applicationId" ) final String applicationIdStr, + @PathParam( "collectionName" ) final String collectionName, + @QueryParam( "reverse" ) @DefaultValue( "false" ) final Boolean reverse, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + + logger.info( "Rebuilding collection {} in application {}", collectionName, applicationIdStr ); + + final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); + + final ReIndexRequestBuilder request = + createRequest().withApplicationId( appId ).withCollection( collectionName ); + + return executeAndCreateResponse( request, callback ); + } + + + @RequireSystemAccess + @PUT + @Path( "rebuild/" + RootResource.APPLICATION_ID_PATH + "/{collectionName}" ) + public JSONWithPadding rebuildIndexesPut( final Map<String, Object> payload, + @PathParam( "applicationId" ) final String applicationIdStr, + @PathParam( "collectionName" ) final String collectionName, + @QueryParam( "reverse" ) @DefaultValue( "false" ) final Boolean reverse, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + logger.info( "Resuming rebuilding collection {} in application {}", collectionName, applicationIdStr ); + + final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); + + final ReIndexRequestBuilder request = + createRequest().withApplicationId( appId ).withCollection( collectionName ); + + return executeResumeAndCreateResponse( payload, request, callback ); + } + + + @RequireSystemAccess + @POST + @Path( "rebuild/management" ) + public JSONWithPadding rebuildInternalIndexesPost( + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) throws Exception { + + + final UUID managementAppId = emf.getManagementAppId(); + + logger.info( "Rebuilding management application with id {} ", managementAppId ); + final ReIndexRequestBuilder request = createRequest().withApplicationId( managementAppId ); + + return executeAndCreateResponse( request, callback ); + } + + + @RequireSystemAccess + @PUT + @Path( "rebuild/management" ) + public JSONWithPadding rebuildInternalIndexesPut( final Map<String, Object> payload, + @QueryParam( "callback" ) @DefaultValue( "callback" ) + String callback ) throws Exception { + + + final UUID managementAppId = emf.getManagementAppId(); + + logger.info( "Resuming rebuilding management application with id {} ", managementAppId ); + final ReIndexRequestBuilder request = createRequest().withApplicationId( managementAppId ); + + return executeResumeAndCreateResponse( payload, request, callback ); + } + + + @RequireSystemAccess + @POST + @Path(RootResource.APPLICATION_ID_PATH) + public JSONWithPadding addIndex( @Context UriInfo ui, + @PathParam( "applicationId" ) final String applicationIdStr, + Map<String, Object> config, + @QueryParam( "callback" ) @DefaultValue( "callback" ) String callback ) + throws Exception { + + Preconditions + .checkNotNull( config, "Payload for config is null, please pass {replicas:int, shards:int} in body" ); + + ApiResponse response = createApiResponse(); + + if ( !config.containsKey( "replicas" ) || !config.containsKey( "shards" ) || + !( config.get( "replicas" ) instanceof Integer ) || !( config.get( "shards" ) instanceof Integer ) ) { + throw new IllegalArgumentException( "body must contains 'replicas' of type int and 'shards' of type int" ); + } + + if ( !config.containsKey( "indexSuffix" ) ) { + throw new IllegalArgumentException( "Please add an indexSuffix to your post" ); + } + final UUID appId = UUIDUtils.tryExtractUUID( applicationIdStr ); + + if(appId == null){ + throw new IllegalArgumentException("app id was not parsed"); + } + + EntityManager em = emf.getEntityManager(appId); + em.addIndex(config.get("indexSuffix").toString(), (int) config.get("shards"), + (int) config.get("replicas"), (String) config.get("writeConsistency")); + response.setAction( "Add index to alias" ); + + return new JSONWithPadding( response, callback ); + } + + + private ReIndexService getReIndexService() { + return injector.getInstance( ReIndexService.class ); + } + + + private ReIndexRequestBuilder createRequest() { + //TODO: wire this up through spring, and in the future guice. + return new ReIndexRequestBuilderImpl(); + } + + + private JSONWithPadding executeResumeAndCreateResponse( final Map<String, Object> payload, + final ReIndexRequestBuilder request, + final String callback ) { + + Map<String,Object> newPayload = payload; + if(newPayload == null || !payload.containsKey( UPDATED_FIELD )){ + newPayload = new HashMap<>(1); + newPayload.put(UPDATED_FIELD,0); + } + + Preconditions.checkArgument(newPayload.get(UPDATED_FIELD) instanceof Number, + "You must specified the field \"updated\" in the payload and it must be a timestamp" ); + + //add our updated timestamp to the request + if ( newPayload.containsKey( UPDATED_FIELD ) ) { + final long timestamp = ConversionUtils.getLong(newPayload.get(UPDATED_FIELD)); + request.withStartTimestamp( timestamp ); + } + + return executeAndCreateResponse( request, callback ); + } + + + /** + * Execute the request and return the response. + */ + private JSONWithPadding executeAndCreateResponse( final ReIndexRequestBuilder request, final String callback ) { + + + final ReIndexService.ReIndexStatus status = getReIndexService().rebuildIndex( request ); + + final ApiResponse response = createApiResponse(); + + response.setAction( "rebuild indexes" ); + response.setProperty( "jobId", status.getJobId() ); + response.setProperty( "status", status.getStatus() ); + response.setProperty( "lastUpdatedEpoch", status.getLastUpdated() ); + response.setProperty( "numberQueued", status.getNumberProcessed() ); + response.setSuccess(); + + return new JSONWithPadding( response, callback ); + } +}