| /* |
| * 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; |
| |
| |
| import com.amazonaws.AmazonServiceException; |
| import com.fasterxml.jackson.databind.ObjectMapper; |
| import com.fasterxml.jackson.jaxrs.json.annotation.JSONP; |
| import com.google.cloud.storage.StorageException; |
| import org.apache.commons.lang.StringUtils; |
| import org.apache.usergrid.management.OrganizationConfig; |
| import org.apache.usergrid.management.OrganizationConfigProps; |
| import org.apache.usergrid.persistence.Entity; |
| import org.apache.usergrid.persistence.EntityManager; |
| import org.apache.usergrid.persistence.Query; |
| import org.apache.usergrid.persistence.QueryUtils; |
| import org.apache.usergrid.rest.AbstractContextResource; |
| import org.apache.usergrid.rest.ApiResponse; |
| import org.apache.usergrid.rest.RootResource; |
| import org.apache.usergrid.rest.applications.assets.AssetsResource; |
| import org.apache.usergrid.rest.security.annotations.CheckPermissionsForPath; |
| import org.apache.usergrid.security.oauth.AccessInfo; |
| import org.apache.usergrid.security.shiro.utils.SubjectUtils; |
| import org.apache.usergrid.services.*; |
| import org.apache.usergrid.services.assets.BinaryStoreFactory; |
| import org.apache.usergrid.services.assets.data.*; |
| import org.apache.usergrid.services.exceptions.AwsPropertiesNotFoundException; |
| import org.apache.usergrid.utils.JsonUtils; |
| import org.glassfish.jersey.media.multipart.BodyPart; |
| import org.glassfish.jersey.media.multipart.BodyPartEntity; |
| import org.glassfish.jersey.media.multipart.FormDataBodyPart; |
| import org.glassfish.jersey.media.multipart.FormDataMultiPart; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| import org.springframework.beans.BeanInfoFactory; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.context.annotation.Scope; |
| import org.springframework.stereotype.Component; |
| |
| import javax.security.auth.Subject; |
| import javax.ws.rs.*; |
| import javax.ws.rs.core.*; |
| import java.io.InputStream; |
| import java.util.*; |
| |
| import static javax.ws.rs.core.MediaType.APPLICATION_JSON_TYPE; |
| import static org.apache.usergrid.management.AccountCreationProps.PROPERTIES_USERGRID_BINARY_UPLOADER; |
| |
| |
| @Component |
| @Scope("prototype") |
| @Produces({ |
| MediaType.APPLICATION_JSON, "application/javascript", "application/x-javascript", "text/ecmascript", |
| "application/ecmascript", "text/jscript" |
| }) |
| public class ServiceResource extends AbstractContextResource { |
| |
| protected static final Logger logger = LoggerFactory.getLogger( ServiceResource.class ); |
| private static final String FILE_FIELD_NAME = "file"; |
| |
| private BinaryStore binaryStore; |
| |
| @Autowired |
| private BinaryStoreFactory binaryStoreFactory; |
| |
| protected ServiceManager services; |
| |
| List<ServiceParameter> serviceParameters = null; |
| |
| |
| public ServiceResource() { |
| } |
| |
| |
| |
| @Override |
| public void setParent( AbstractContextResource parent ) { |
| super.setParent( parent ); |
| if ( parent instanceof ServiceResource ) { |
| services = ( ( ServiceResource ) parent ).services; |
| } |
| } |
| |
| |
| public ServiceResource getServiceResourceParent() { |
| if ( parent instanceof ServiceResource ) { |
| return ( ServiceResource ) parent; |
| } |
| return null; |
| } |
| |
| |
| public ServiceManager getServices() { |
| return services; |
| } |
| |
| |
| public UUID getApplicationId() { |
| return services.getApplicationId(); |
| } |
| |
| |
| public String getOrganizationName() { |
| return services.getApplication().getOrganizationName(); |
| } |
| |
| |
| public List<ServiceParameter> getServiceParameters() { |
| if ( serviceParameters != null ) { |
| return serviceParameters; |
| } |
| if ( getServiceResourceParent() != null ) { |
| return getServiceResourceParent().getServiceParameters(); |
| } |
| serviceParameters = new ArrayList<>(); |
| return serviceParameters; |
| } |
| |
| |
| public static List<ServiceParameter> addMatrixParams( List<ServiceParameter> parameters, UriInfo ui, |
| PathSegment ps ) throws Exception { |
| |
| MultivaluedMap<String, String> params = ps.getMatrixParameters(); |
| |
| if ( params != null && params.size() > 0) { |
| Query query = Query.fromQueryParams( params ); |
| if ( query != null ) { |
| parameters = ServiceParameter.addParameter( parameters, query ); |
| } |
| } |
| |
| return parameters; |
| } |
| |
| |
| public static List<ServiceParameter> addQueryParams( List<ServiceParameter> parameters, UriInfo ui ) |
| throws Exception { |
| |
| MultivaluedMap<String, String> params = ui.getQueryParameters(); |
| if ( params != null && params.size() > 0) { |
| //TODO TN query parameters are not being correctly decoded here. The URL encoded strings |
| //aren't getting decoded properly |
| Query query = Query.fromQueryParams( params ); |
| |
| if(query == null && parameters.size() > 0 && parameters.get( 0 ).isId()){ |
| query = Query.fromUUID( parameters.get( 0 ).getId() ); |
| } |
| |
| if ( query != null ) { |
| parameters = ServiceParameter.addParameter( parameters, query ); |
| } |
| } |
| |
| return parameters; |
| } |
| |
| |
| @Path("file") |
| public AbstractContextResource getFileResource( @Context UriInfo ui ) throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.getFileResource" ); |
| } |
| |
| ServiceParameter.addParameter( getServiceParameters(), "assets" ); |
| |
| PathSegment ps = getFirstPathSegment( "assets" ); |
| if ( ps != null ) { |
| addMatrixParams( getServiceParameters(), ui, ps ); |
| } |
| |
| return getSubResource( AssetsResource.class ); |
| } |
| |
| |
| @Path(RootResource.ENTITY_ID_PATH) |
| public AbstractContextResource addIdParameter( @Context UriInfo ui, @PathParam("entityId") PathSegment entityId ) |
| throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.addIdParameter" ); |
| } |
| |
| UUID itemId = UUID.fromString( entityId.getPath() ); |
| |
| ServiceParameter.addParameter( getServiceParameters(), itemId ); |
| |
| addMatrixParams( getServiceParameters(), ui, entityId ); |
| |
| return getSubResource( ServiceResource.class ); |
| } |
| |
| |
| @Path("{itemName}") |
| public AbstractContextResource addNameParameter( @Context UriInfo ui, @PathParam("itemName") PathSegment itemName ) |
| throws Exception { |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.addNameParameter" ); |
| logger.trace( "Current segment is {}", itemName.getPath() ); |
| } |
| |
| |
| if ( itemName.getPath().startsWith( "{" ) ) { |
| Query query = Query.fromJsonString( itemName.getPath() ); |
| if ( query != null ) { |
| ServiceParameter.addParameter( getServiceParameters(), query ); |
| } |
| } |
| else { |
| ServiceParameter.addParameter( getServiceParameters(), itemName.getPath() ); |
| } |
| |
| addMatrixParams( getServiceParameters(), ui, itemName ); |
| |
| return getSubResource( ServiceResource.class ); |
| } |
| |
| |
| public ServiceResults executeServiceGetRequestForSettings(UriInfo ui, ApiResponse response, ServiceAction action, |
| ServicePayload payload) throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executeServiceRequest" ); |
| } |
| |
| |
| boolean tree = "true".equalsIgnoreCase( ui.getQueryParameters().getFirst( "tree" ) ); |
| |
| String connectionQueryParm = ui.getQueryParameters().getFirst("connections"); |
| boolean returnInboundConnections = true; |
| boolean returnOutboundConnections = true; |
| |
| addQueryParams( getServiceParameters(), ui ); |
| |
| ServiceRequest r = services.newRequest( action, tree, getServiceParameters(), payload, |
| returnInboundConnections, returnOutboundConnections, false, false); |
| |
| response.setServiceRequest( r ); |
| |
| |
| AbstractCollectionService abstractCollectionService = new AbstractCollectionService(); |
| |
| // abstractCollectionService |
| ServiceResults results = abstractCollectionService.getCollectionSettings( r ); |
| |
| // ServiceResults results = r.execute(); |
| if ( results != null ) { |
| if ( results.hasData() ) { |
| response.setData( results.getData() ); |
| } |
| if ( results.getServiceMetadata() != null ) { |
| response.setMetadata( results.getServiceMetadata() ); |
| } |
| Query query = r.getLastQuery(); |
| if ( query != null ) { |
| if ( query.hasSelectSubjects() ) { |
| response.setList( QueryUtils.getSelectionResults( query, results ) ); |
| response.setCount( response.getList().size() ); |
| response.setNext( results.getNextResult() ); |
| response.setPath( results.getPath() ); |
| return results; |
| } |
| } |
| |
| response.setResults( results ); |
| } |
| |
| httpServletRequest.setAttribute( "applicationId", services.getApplicationId() ); |
| |
| return results; |
| } |
| |
| public ServiceResults executeServicePostRequestForSettings(UriInfo ui, ApiResponse response, ServiceAction action, |
| ServicePayload payload) throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executeServiceRequest" ); |
| } |
| |
| |
| boolean tree = "true".equalsIgnoreCase( ui.getQueryParameters().getFirst( "tree" ) ); |
| |
| String connectionQueryParm = ui.getQueryParameters().getFirst("connections"); |
| boolean returnInboundConnections = true; |
| boolean returnOutboundConnections = true; |
| |
| addQueryParams( getServiceParameters(), ui ); |
| |
| ServiceRequest r = services.newRequest( action, tree, getServiceParameters(), payload, |
| returnInboundConnections, returnOutboundConnections, false, false); |
| |
| response.setServiceRequest( r ); |
| |
| |
| AbstractCollectionService abstractCollectionService = new AbstractCollectionService(); |
| |
| ServiceResults results = abstractCollectionService.postCollectionSettings( r ); |
| |
| // ServiceResults results = r.execute(); |
| if ( results != null ) { |
| if ( results.hasData() ) { |
| response.setData( results.getData() ); |
| } |
| if ( results.getServiceMetadata() != null ) { |
| response.setMetadata( results.getServiceMetadata() ); |
| } |
| Query query = r.getLastQuery(); |
| if ( query != null ) { |
| if ( query.hasSelectSubjects() ) { |
| response.setList( QueryUtils.getSelectionResults( query, results ) ); |
| response.setCount( response.getList().size() ); |
| response.setNext( results.getNextResult() ); |
| response.setPath( results.getPath() ); |
| return results; |
| } |
| } |
| |
| response.setResults( results ); |
| } |
| |
| httpServletRequest.setAttribute( "applicationId", services.getApplicationId() ); |
| |
| return results; |
| |
| |
| } |
| |
| |
| public ServiceResults executeServiceRequest( UriInfo ui, ApiResponse response, ServiceAction action, |
| ServicePayload payload ) throws Exception { |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executeServiceRequest" ); |
| } |
| |
| |
| boolean tree = "true".equalsIgnoreCase( ui.getQueryParameters().getFirst( "tree" ) ); |
| |
| String connectionQueryParm = ui.getQueryParameters().getFirst("connections"); |
| boolean returnInboundConnections = true; |
| boolean returnOutboundConnections = true; |
| |
| // connection info can be blocked only for GETs |
| if (action == ServiceAction.GET) { |
| if ("none".equalsIgnoreCase(connectionQueryParm)) { |
| returnInboundConnections = false; |
| returnOutboundConnections = false; |
| } else if ("in".equalsIgnoreCase(connectionQueryParm)) { |
| returnInboundConnections = true; |
| returnOutboundConnections = false; |
| } else if ("out".equalsIgnoreCase(connectionQueryParm)) { |
| returnInboundConnections = false; |
| returnOutboundConnections = true; |
| } else if ("all".equalsIgnoreCase(connectionQueryParm)) { |
| returnInboundConnections = true; |
| returnOutboundConnections = true; |
| } else { |
| if (connectionQueryParm != null) { |
| // unrecognized parameter |
| logger.error(String.format( |
| "Invalid connections query parameter=%s, ignoring.", connectionQueryParm)); |
| } |
| // use the default query parameter functionality |
| OrganizationConfig orgConfig = |
| management.getOrganizationConfigForApplication(services.getApplicationId()); |
| String defaultConnectionQueryParm = |
| orgConfig.getProperty(OrganizationConfigProps.ORGPROPERTIES_DEFAULT_CONNECTION_PARAM); |
| returnInboundConnections = |
| (defaultConnectionQueryParm.equals("in")) || (defaultConnectionQueryParm.equals("all")); |
| returnOutboundConnections = |
| (defaultConnectionQueryParm.equals("out")) || (defaultConnectionQueryParm.equals("all")); |
| } |
| } |
| |
| boolean analyzeQueryOnly = Boolean.valueOf(ui.getQueryParameters().getFirst("analyzeOnly")); |
| boolean returnQuery = false; |
| // currently only allow query return if service admin |
| if (SubjectUtils.isServiceAdmin()) { |
| returnQuery = Boolean.valueOf(ui.getQueryParameters().getFirst("returnQuery")); |
| } |
| |
| boolean collectionGet = false; |
| if ( action == ServiceAction.GET ) { |
| collectionGet = getServiceParameters().size() == 1; |
| } |
| addQueryParams( getServiceParameters(), ui ); |
| ServiceRequest r = services.newRequest( action, tree, getServiceParameters(), payload, |
| returnInboundConnections, returnOutboundConnections, analyzeQueryOnly, returnQuery); |
| response.setServiceRequest( r ); |
| ServiceResults results = r.execute(); |
| if ( results != null ) { |
| if ( results.hasData() ) { |
| response.setData( results.getData() ); |
| } |
| if ( results.getServiceMetadata() != null ) { |
| response.setMetadata( results.getServiceMetadata() ); |
| } |
| Query query = r.getLastQuery(); |
| if ( query != null ) { |
| if ( query.hasSelectSubjects() ) { |
| response.setList( QueryUtils.getSelectionResults( query, results ) ); |
| response.setCount( response.getList().size() ); |
| response.setNext( results.getNextResult() ); |
| response.setPath( results.getPath() ); |
| return results; |
| } |
| } |
| if ( collectionGet ) { |
| response.setCount( results.size() ); |
| } |
| |
| response.setResults( results ); |
| } |
| |
| httpServletRequest.setAttribute( "applicationId", services.getApplicationId() ); |
| |
| return results; |
| } |
| |
| |
| @CheckPermissionsForPath |
| @GET |
| @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_HTML, "application/javascript"}) |
| @JSONP |
| public ApiResponse executeGet( @Context UriInfo ui, |
| @QueryParam("callback") @DefaultValue("callback") String callback ) |
| throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executeGet" ); |
| } |
| |
| ApiResponse response = createApiResponse(); |
| |
| response.setAction( "get" ); |
| response.setApplication( services.getApplication() ); |
| response.setParams( ui.getQueryParameters() ); |
| |
| executeServiceRequest( ui, response, ServiceAction.GET, null ); |
| |
| return response; |
| } |
| |
| @SuppressWarnings({ "unchecked" }) |
| public ServicePayload getPayload( Object json ) { |
| ServicePayload payload = null; |
| json = JsonUtils.normalizeJsonTree( json ); |
| if ( json instanceof Map ) { |
| Map<String, Object> jsonMap = ( Map<String, Object> ) json; |
| payload = ServicePayload.payload( jsonMap ); |
| } |
| else if ( json instanceof List ) { |
| List<?> jsonList = ( List<?> ) json; |
| if ( jsonList.size() > 0 ) { |
| if ( jsonList.get( 0 ) instanceof UUID ) { |
| payload = ServicePayload.idListPayload( ( List<UUID> ) json ); |
| } |
| else if ( jsonList.get( 0 ) instanceof Map ) { |
| payload = ServicePayload.batchPayload( ( List<Map<String, Object>> ) jsonList ); |
| } |
| } |
| } |
| if ( payload == null ) { |
| payload = new ServicePayload(); |
| } |
| return payload; |
| } |
| |
| |
| |
| |
| /** |
| * Necessary to work around inexplicable problems with EntityHolder. |
| * See above. |
| */ |
| public ApiResponse executePostWithObject( @Context UriInfo ui, Object json, |
| @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executePostWithMap" ); |
| } |
| |
| ApiResponse response = createApiResponse(); |
| |
| |
| response.setAction( "post" ); |
| response.setApplication( services.getApplication() ); |
| response.setParams( ui.getQueryParameters() ); |
| |
| ServicePayload payload = getPayload( json ); |
| |
| executeServiceRequest( ui, response, ServiceAction.POST, payload ); |
| |
| return response; |
| } |
| |
| |
| /** |
| * Necessary to work around inexplicable problems with EntityHolder. |
| * See above. |
| */ |
| public ApiResponse executePutWithMap( @Context UriInfo ui, Map<String, Object> json, |
| @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { |
| |
| ApiResponse response = createApiResponse(); |
| response.setAction( "put" ); |
| |
| response.setApplication( services.getApplication() ); |
| response.setParams( ui.getQueryParameters() ); |
| |
| ServicePayload payload = getPayload( json ); |
| |
| executeServiceRequest( ui, response, ServiceAction.PUT, payload ); |
| |
| return response; |
| } |
| |
| |
| @CheckPermissionsForPath |
| @POST |
| @Consumes(MediaType.APPLICATION_JSON) |
| @JSONP |
| @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) |
| public ApiResponse executePost( @Context UriInfo ui, String body, |
| @QueryParam("callback") @DefaultValue("callback") String callback ) throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executePost: body = {}", body ); |
| } |
| |
| Object json; |
| if ( StringUtils.isEmpty( body ) ) { |
| json = null; |
| } else { |
| json = readJsonToObject( body ); |
| } |
| |
| ApiResponse response = createApiResponse(); |
| |
| |
| response.setAction( "post" ); |
| response.setApplication( services.getApplication() ); |
| response.setParams( ui.getQueryParameters() ); |
| |
| ServicePayload payload = getPayload( json ); |
| |
| executeServiceRequest( ui, response, ServiceAction.POST, payload ); |
| |
| return response; |
| } |
| |
| |
| |
| @CheckPermissionsForPath |
| @PUT |
| @Consumes(MediaType.APPLICATION_JSON) |
| @JSONP |
| @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) |
| public ApiResponse executePut( @Context UriInfo ui, String body, |
| @QueryParam("callback") @DefaultValue("callback") String callback ) |
| throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executePut" ); |
| } |
| |
| ObjectMapper mapper = new ObjectMapper(); |
| Map<String, Object> json = mapper.readValue( body, mapTypeReference ); |
| |
| return executePutWithMap(ui, json, callback); |
| } |
| |
| |
| @CheckPermissionsForPath |
| @DELETE |
| @JSONP |
| @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) |
| public ApiResponse executeDelete( |
| @Context UriInfo ui, |
| @QueryParam("callback") @DefaultValue("callback") String callback, |
| @QueryParam("app_delete_confirm") String confirmAppDelete ) |
| throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executeDelete" ); |
| } |
| |
| ApiResponse response = createApiResponse(); |
| response.setAction( "delete" ); |
| response.setApplication( services.getApplication() ); |
| response.setParams( ui.getQueryParameters() ); |
| |
| ServiceResults sr = executeServiceRequest( ui, response, ServiceAction.DELETE, null ); |
| |
| // if we deleted an entity (and not a connection or collection) then |
| // we may need to clean up binary asset data associated with that entity |
| |
| if ( !sr.getResultsType().equals( ServiceResults.Type.CONNECTION ) |
| && !sr.getResultsType().equals( ServiceResults.Type.COLLECTION )) { |
| |
| for ( Entity entity : sr.getEntities() ) { |
| if ( entity.getProperty( AssetUtils.FILE_METADATA ) != null ) { |
| try { |
| binaryStore.delete( services.getApplicationId(), entity ); |
| }catch(AwsPropertiesNotFoundException apnfe){ |
| logger.error( "Amazon Property needed for this operation not found",apnfe ); |
| response.setError( "500","Amazon Property needed for this operation not found",apnfe ); |
| } |
| } |
| } |
| } |
| |
| return response; |
| } |
| |
| // TODO Temporarily removed until we test further |
| // @Produces("text/csv") |
| // @GET |
| // @RequireApplicationAccess |
| // @Consumes("text/csv") |
| // public String executeGetCsv(@Context UriInfo ui, |
| // @QueryParam("callback") @DefaultValue("callback") String callback) |
| // throws Exception { |
| // ui.getQueryParameters().putSingle("pad", "true"); |
| // JSONWithPadding jsonp = executeGet(ui, callback); |
| // |
| // StringBuilder builder = new StringBuilder(); |
| // if ((jsonp != null) && (jsonp.getJsonSource() instanceof ApiResponse)) { |
| // ApiResponse apiResponse = (ApiResponse) jsonp.getJsonSource(); |
| // if ((apiResponse.getCounters() != null) |
| // && (apiResponse.getCounters().size() > 0)) { |
| // List<AggregateCounterSet> counters = apiResponse.getCounters(); |
| // int size = counters.get(0).getValues().size(); |
| // List<AggregateCounter> firstCounterList = counters.get(0) |
| // .getValues(); |
| // if (size > 0) { |
| // builder.append("timestamp"); |
| // for (AggregateCounterSet counterSet : counters) { |
| // builder.append(","); |
| // builder.append(counterSet.getName()); |
| // } |
| // builder.append("\n"); |
| // SimpleDateFormat formatter = new SimpleDateFormat( |
| // "yyyy-MM-dd HH:mm:ss.SSS"); |
| // for (int i = 0; i < size; i++) { |
| // // yyyy-mm-dd hh:mm:ss.000 |
| // builder.append(formatter.format(new Date( |
| // firstCounterList.get(i).getTimestamp()))); |
| // for (AggregateCounterSet counterSet : counters) { |
| // List<AggregateCounter> counterList = counterSet |
| // .getValues(); |
| // builder.append(","); |
| // builder.append(counterList.get(i).getValue()); |
| // } |
| // builder.append("\n"); |
| // } |
| // } |
| // } else if ((apiResponse.getEntities() != null) |
| // && (apiResponse.getEntities().size() > 0)) { |
| // for (Entity entity : apiResponse.getEntities()) { |
| // builder.append(entity.getUuid()); |
| // builder.append(","); |
| // builder.append(entity.getType()); |
| // builder.append(","); |
| // builder.append(mapToJsonString(entity)); |
| // } |
| // |
| // } |
| // } |
| // return builder.toString(); |
| // } |
| |
| |
| public static String wrapWithCallback( AccessInfo accessInfo, String callback ) { |
| return wrapWithCallback( JsonUtils.mapToJsonString( accessInfo ), callback ); |
| } |
| |
| |
| public static String wrapWithCallback( String json, String callback ) { |
| if ( StringUtils.isNotBlank( callback ) ) { |
| json = callback + "(" + json + ")"; |
| } |
| return json; |
| } |
| |
| |
| public static MediaType jsonMediaType( String callback ) { |
| return StringUtils.isNotBlank( callback ) ? new MediaType( "application", "javascript" ) : APPLICATION_JSON_TYPE; |
| } |
| |
| |
| /** ************** the following is file attachment (Asset) support ********************* */ |
| |
| @CheckPermissionsForPath |
| @POST |
| @Consumes(MediaType.MULTIPART_FORM_DATA) |
| @JSONP |
| @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) |
| public ApiResponse executeMultiPartPost( @Context UriInfo ui, |
| @QueryParam("callback") @DefaultValue("callback") String callback, |
| FormDataMultiPart multiPart ) throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executeMultiPartPost" ); |
| } |
| return executeMultiPart( ui, callback, multiPart, ServiceAction.POST ); |
| } |
| |
| |
| @CheckPermissionsForPath |
| @PUT |
| @Consumes(MediaType.MULTIPART_FORM_DATA) |
| @JSONP |
| @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) |
| public ApiResponse executeMultiPartPut( @Context UriInfo ui, |
| @QueryParam("callback") @DefaultValue("callback") String callback, |
| FormDataMultiPart multiPart ) throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executeMultiPartPut" ); |
| } |
| return executeMultiPart( ui, callback, multiPart, ServiceAction.PUT ); |
| } |
| |
| |
| @JSONP |
| @Produces({MediaType.APPLICATION_JSON, "application/javascript"}) |
| private ApiResponse executeMultiPart( UriInfo ui, String callback, FormDataMultiPart multiPart, |
| ServiceAction serviceAction ) throws Exception { |
| // needed for testing |
| this.binaryStore = binaryStoreFactory.getBinaryStore( properties.getProperty(PROPERTIES_USERGRID_BINARY_UPLOADER) ); |
| |
| // collect form data values |
| List<BodyPart> bodyParts = multiPart.getBodyParts(); |
| HashMap<String, Object> data = new HashMap<>(); |
| for ( BodyPart bp : bodyParts ) { |
| FormDataBodyPart bodyPart = ( FormDataBodyPart ) bp; |
| if ( bodyPart.getMediaType().equals( MediaType.TEXT_PLAIN_TYPE ) ) { |
| data.put( bodyPart.getName(), bodyPart.getValue() ); |
| } |
| else { |
| if (logger.isTraceEnabled()) { |
| logger.trace("skipping bodyPart {} of media type {}", bodyPart.getName(), bodyPart.getMediaType()); |
| } |
| } |
| } |
| |
| FormDataBodyPart fileBodyPart = multiPart.getField( FILE_FIELD_NAME ); |
| |
| data.put( AssetUtils.FILE_METADATA, new HashMap() ); |
| |
| // process entity |
| ApiResponse response = createApiResponse(); |
| response.setAction( serviceAction.name().toLowerCase() ); |
| response.setApplication( services.getApplication() ); |
| response.setParams( ui.getQueryParameters() ); |
| |
| //Updates entity with fields that are in text/plain as per loop above |
| if(data.get( FILE_FIELD_NAME )==null){ |
| data.put( FILE_FIELD_NAME,null ); |
| } |
| ServicePayload payload = getPayload( data ); |
| ServiceResults serviceResults = executeServiceRequest( ui, response, serviceAction, payload ); |
| |
| // process file part |
| if ( fileBodyPart != null ) { |
| InputStream fileInput = ( (BodyPartEntity) fileBodyPart.getEntity() ).getInputStream(); |
| if ( fileInput != null ) { |
| Entity entity = serviceResults.getEntity(); |
| EntityManager em = emf.getEntityManager( getApplicationId() ); |
| try { |
| binaryStore.write( getApplicationId(), entity, fileInput ); |
| } |
| catch ( AwsPropertiesNotFoundException apnfe){ |
| logger.error( "Amazon Property needed for this operation not found",apnfe ); |
| response.setError( "500","Amazon Property needed for this operation not found",apnfe ); |
| } |
| catch ( RuntimeException re){ |
| logger.error(re.getMessage()); |
| response.setError( "500", re ); |
| } |
| //em.update( entity ); |
| entity = serviceResults.getEntity(); |
| serviceResults.setEntity( entity ); |
| } |
| } |
| |
| return response; |
| } |
| |
| |
| @CheckPermissionsForPath |
| @PUT |
| @Consumes(MediaType.APPLICATION_OCTET_STREAM) |
| public Response uploadDataStreamPut( @Context UriInfo ui, InputStream uploadedInputStream ) throws Exception { |
| return uploadDataStream( ui, uploadedInputStream ); |
| } |
| |
| |
| @CheckPermissionsForPath |
| @POST |
| @Consumes(MediaType.APPLICATION_OCTET_STREAM) |
| public Response uploadDataStream( @Context UriInfo ui, InputStream uploadedInputStream ) throws Exception { |
| |
| //needed for testing |
| this.binaryStore = binaryStoreFactory.getBinaryStore( properties.getProperty(PROPERTIES_USERGRID_BINARY_UPLOADER) ); |
| |
| |
| ApiResponse response = createApiResponse(); |
| response.setAction( "get" ); |
| response.setApplication( services.getApplication() ); |
| response.setParams( ui.getQueryParameters() ); |
| ServiceResults serviceResults = executeServiceRequest( ui, response, ServiceAction.GET, null ); |
| |
| Entity entity = serviceResults.getEntity(); |
| try { |
| binaryStore.write( getApplicationId(), entity, uploadedInputStream ); |
| }catch(AwsPropertiesNotFoundException apnfe){ |
| logger.error( "Amazon Property needed for this operation not found",apnfe ); |
| return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); |
| }catch ( RuntimeException re ){ |
| logger.error(re.getMessage()); |
| return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); |
| } |
| |
| EntityManager em = emf.getEntityManager( getApplicationId() ); |
| em.update( entity ); |
| return Response.status( 200 ).build(); |
| } |
| |
| @CheckPermissionsForPath |
| @GET |
| @Produces(MediaType.WILDCARD) |
| public Response executeStreamGet( @Context UriInfo ui, @PathParam("entityId") PathSegment entityId, |
| @HeaderParam("range") String rangeHeader, |
| @HeaderParam("if-modified-since") String modifiedSince ) throws Exception { |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "ServiceResource.executeStreamGet" ); |
| } |
| |
| // needed for testing |
| this.binaryStore = binaryStoreFactory.getBinaryStore( properties.getProperty(PROPERTIES_USERGRID_BINARY_UPLOADER) ); |
| |
| ApiResponse response = createApiResponse(); |
| response.setAction( "get" ); |
| response.setApplication( services.getApplication() ); |
| response.setParams( ui.getQueryParameters() ); |
| ServiceResults serviceResults = executeServiceRequest( ui, response, ServiceAction.GET, null ); |
| Entity entity = serviceResults.getEntity(); |
| |
| if(logger.isTraceEnabled()){ |
| logger.trace( "In ServiceResource.executeStreamGet with id: {}, range: {}, modifiedSince: {}", |
| entityId, rangeHeader, modifiedSince ); |
| } |
| |
| Map<String, Object> fileMetadata = AssetUtils.getFileMetadata( entity ); |
| |
| // return a 302 if not modified |
| Date modified = AssetUtils.fromIfModifiedSince( modifiedSince ); |
| if ( modified != null ) { |
| Long lastModified = ( Long ) fileMetadata.get( AssetUtils.LAST_MODIFIED ); |
| if ( lastModified - modified.getTime() < 0 ) { |
| return Response.status( Response.Status.NOT_MODIFIED ).build(); |
| } |
| } |
| |
| boolean range = StringUtils.isNotBlank( rangeHeader ); |
| long start = 0, end = 0, contentLength = 0; |
| InputStream inputStream; |
| |
| if ( range ) { // honor range request, calculate start & end |
| |
| String rangeValue = rangeHeader.trim().substring( "bytes=".length() ); |
| contentLength = ( Long ) fileMetadata.get( AssetUtils.CONTENT_LENGTH ); |
| end = contentLength - 1; |
| if ( rangeValue.startsWith( "-" ) ) { |
| start = contentLength - 1 - Long.parseLong( rangeValue.substring( "-".length() ) ); |
| } |
| else { |
| String[] startEnd = rangeValue.split( "-" ); |
| long parsedStart = Long.parseLong( startEnd[0] ); |
| if ( parsedStart > start && parsedStart < end ) { |
| start = parsedStart; |
| } |
| if ( startEnd.length > 1 ) { |
| long parsedEnd = Long.parseLong( startEnd[1] ); |
| if ( parsedEnd > start && parsedEnd < end ) { |
| end = parsedEnd; |
| } |
| } |
| } |
| try { |
| inputStream = binaryStore.read( getApplicationId(), entity, start, end - start ); |
| }catch(AwsPropertiesNotFoundException apnfe){ |
| logger.error( "Amazon Property needed for this operation not found",apnfe ); |
| return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); |
| }catch(RuntimeException re){ |
| logger.error(re.getMessage()); |
| return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); |
| } |
| } |
| else { // no range |
| try { |
| inputStream = binaryStore.read( getApplicationId(), entity ); |
| }catch(AwsPropertiesNotFoundException apnfe){ |
| logger.error( "Amazon Property needed for this operation not found",apnfe ); |
| return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); |
| } |
| catch(AmazonServiceException ase){ |
| if( ase.getStatusCode() > 499 ){ |
| logger.error(ase.getMessage()); |
| }else if(logger.isDebugEnabled()){ |
| logger.debug(ase.getMessage()); |
| } |
| return Response.status(ase.getStatusCode()).build(); |
| } |
| catch (StorageException se){ |
| if( se.getCode() > 499 ){ |
| logger.error(se.getMessage()); |
| }else if(logger.isDebugEnabled()){ |
| logger.debug(se.getMessage()); |
| } |
| return Response.status(se.getCode()).build(); |
| } |
| catch(RuntimeException re){ |
| logger.error(re.getMessage()); |
| return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); |
| } |
| } |
| |
| // return 404 if not found |
| if ( inputStream == null ) { |
| return Response.status( Response.Status.NOT_FOUND ).build(); |
| } |
| |
| Long lastModified = ( Long ) fileMetadata.get( AssetUtils.LAST_MODIFIED ); |
| Response.ResponseBuilder responseBuilder = |
| Response.ok( inputStream ).type( ( String ) fileMetadata.get( AssetUtils.CONTENT_TYPE ) ) |
| .lastModified( new Date( lastModified ) ); |
| |
| if ( fileMetadata.get( AssetUtils.E_TAG ) != null ) { |
| responseBuilder.tag( ( String ) fileMetadata.get( AssetUtils.E_TAG ) ); |
| } |
| |
| if ( range ) { |
| responseBuilder.header( "Content-Range", "bytes " + start + "-" + end + "/" + contentLength ); |
| } |
| |
| return responseBuilder.build(); |
| } |
| } |