Merge remote-tracking branch 'origin/jan-team-image' into ftes-file-storage

Conflicts:
	java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/jaxrs/api/TeamResource.java
	java/com.sap.sse.filestorage/src/com/sap/sse/filestorage/impl/AmazonS3FileStorageServiceImpl.java
This commit is contained in:
Fredrik Teschke
2015-01-23 15:13:02 +01:00
9 changed files with 224 additions and 123 deletions
@@ -27,14 +27,14 @@ import com.sap.sailing.domain.base.impl.NationalityImpl;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants;
import com.sap.sailing.server.gateway.jaxrs.api.TeamResource;
import com.sap.sailing.server.gateway.jaxrs.api.CompetitorsResource;
import com.sap.sse.filestorage.FileStorageService;
import com.sap.sse.filestorage.InvalidPropertiesException;
import com.sap.sse.filestorage.OperationFailedException;
import com.sap.sse.filestorage.testsupport.AmazonS3TestSupport;
import com.sun.jersey.core.header.FormDataContentDisposition;
public class TeamResourceTest extends AbstractJaxRsApiTest {
public class TeamImageTest extends AbstractJaxRsApiTest {
private static final String name = "Heiko KRÖGER";
private static final String id = "af855a56-9726-4a9c-a77e-da955bd289be";
private static final String boatClassName = "49er";
@@ -60,7 +60,7 @@ public class TeamResourceTest extends AbstractJaxRsApiTest {
public void storeAndRemoveTeamImage() throws URISyntaxException, ParseException, MalformedURLException,
IOException, OperationFailedException, InvalidPropertiesException {
//set team image
TeamResource r = spyResource(new TeamResource());
CompetitorsResource r = spyResource(new CompetitorsResource());
URL fileUrl = getClass().getResource("/" + teamImageFile);
URI fileUri = new URI(fileUrl.toString());
long length = new File(fileUri).length();
@@ -1,9 +1,18 @@
package com.sap.sailing.server.gateway.jaxrs.api;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.Consumes;
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.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@@ -11,12 +20,26 @@ import javax.ws.rs.core.Response.Status;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.Team;
import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
import com.sap.sailing.server.gateway.serialization.impl.NationalityJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.PersonJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.TeamJsonSerializer;
import com.sap.sse.filestorage.InvalidPropertiesException;
import com.sap.sse.filestorage.OperationFailedException;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;
@Path("/v1/competitors")
public class CompetitorsResource extends AbstractSailingServerResource {
private static final Logger logger = Logger.getLogger(CompetitorsResource.class.getName());
private static final int MAX_SIZE_IN_MB = 5;
public static JSONObject getCompetitorJSON(Competitor competitor) {
//see http://wiki.sapsailing.com/wiki/tracking-app-api-v1-draft#Competitor-Information
// see http://wiki.sapsailing.com/wiki/tracking-app-api-v1-draft#Competitor-Information
JSONObject json = new JSONObject();
json.put("id", competitor.getId().toString());
json.put("name", competitor.getName());
@@ -27,7 +50,7 @@ public class CompetitorsResource extends AbstractSailingServerResource {
return json;
}
@GET
@Produces("application/json;charset=UTF-8")
@Path("{competitorId}")
@@ -37,12 +60,83 @@ public class CompetitorsResource extends AbstractSailingServerResource {
competitorIdAsString);
if (competitor == null) {
response = Response.status(Status.NOT_FOUND)
.entity("Could not find a competitor with id '" + competitorIdAsString + "'.").type(MediaType.TEXT_PLAIN)
.build();
.entity("Could not find a competitor with id '" + competitorIdAsString + "'.")
.type(MediaType.TEXT_PLAIN).build();
} else {
String jsonString = getCompetitorJSON(competitor).toJSONString();
response = Response.ok(jsonString, MediaType.APPLICATION_JSON).build();
}
return response;
}
@GET
@Produces("application/json;charset=UTF-8")
@Path("{competitor-id}/team")
public Response getTeam(@PathParam("competitor-id") String competitorId) {
Competitor competitor = getService().getCompetitorStore().getExistingCompetitorByIdAsString(competitorId);
if (competitor == null) {
return Response.status(Status.NOT_FOUND)
.entity("Could not find a competitor with id '" + competitorId + "'.").type(MediaType.TEXT_PLAIN)
.build();
}
Team team = competitor.getTeam();
if (team == null) {
return Response.status(Status.NOT_FOUND)
.entity("Could not find a team associated with competitor '" + competitorId + "'.")
.type(MediaType.TEXT_PLAIN).build();
}
TeamJsonSerializer teamJsonSerializer = new TeamJsonSerializer(new PersonJsonSerializer(
new NationalityJsonSerializer()));
JSONObject teamJson = teamJsonSerializer.serialize(team);
String json = teamJson.toJSONString();
return Response.ok(json, MediaType.APPLICATION_JSON).build();
}
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces("application/json;charset=UTF-8")
@Path("{competitor-id}/image")
public String setTeamImage(@PathParam("competitor-id") String competitorId,
@FormDataParam("file") InputStream uploadedInputStream,
@FormDataParam("file") FormDataContentDisposition fileDetails) {
RacingEventService service = getService();
CompetitorStore store = service.getCompetitorStore();
Competitor competitor = store.getExistingCompetitorByIdAsString(competitorId);
if (competitor == null) {
logger.log(Level.INFO, "Could not find competitor to store image for: " + competitorId);
throw new WebApplicationException(Response.status(Status.BAD_REQUEST)
.entity("Could not find competitor with id " + competitorId).type(MediaType.TEXT_PLAIN).build());
}
URI imageUri;
try {
String fileName = fileDetails.getFileName();
long sizeInBytes = fileDetails.getSize();
if (sizeInBytes > 1024 * 1024 * MAX_SIZE_IN_MB) {
throw new WebApplicationException(Response.status(Status.BAD_REQUEST)
.entity("Image is larger than " + MAX_SIZE_IN_MB + "MB").build());
}
imageUri = getService().getFileStorageService().storeFile(uploadedInputStream, fileName, sizeInBytes);
} catch (IOException | OperationFailedException | InvalidPropertiesException e) {
logger.log(Level.WARNING, "Could not store competitor image", e);
throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR)
.entity("Could not store competitor image").type(MediaType.TEXT_PLAIN).build());
}
getService().getCompetitorStore().updateCompetitor(competitorId, competitor.getName(), competitor.getColor(),
competitor.getBoat().getSailID(), competitor.getTeam().getNationality(), imageUri);
logger.log(Level.INFO, "Set team image for competitor " + competitor.getName());
JSONObject result = new JSONObject();
result.put(DeviceMappingConstants.JSON_TEAM_IMAGE_URI, imageUri.toString());
return result.toString();
}
}
@@ -17,7 +17,6 @@ public class RestApiApplication extends Application {
classes.add(SearchResource.class);
classes.add(GPSFixesResource.class);
classes.add(CompetitorsResource.class);
classes.add(TeamResource.class);
return classes;
}
}
@@ -1,104 +0,0 @@
package com.sap.sailing.server.gateway.jaxrs.api;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ws.rs.Consumes;
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.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.json.simple.JSONObject;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CompetitorStore;
import com.sap.sailing.domain.base.Team;
import com.sap.sailing.domain.common.racelog.tracking.DeviceMappingConstants;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.gateway.jaxrs.AbstractSailingServerResource;
import com.sap.sailing.server.gateway.serialization.impl.NationalityJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.PersonJsonSerializer;
import com.sap.sailing.server.gateway.serialization.impl.TeamJsonSerializer;
import com.sap.sse.filestorage.InvalidPropertiesException;
import com.sap.sse.filestorage.OperationFailedException;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.sun.jersey.multipart.FormDataParam;
@Path("/v1/team")
public class TeamResource extends AbstractSailingServerResource {
private static final Logger logger = Logger.getLogger(TeamResource.class.getName());
@GET
@Produces("application/json;charset=UTF-8")
@Path("{competitor-id}")
public Response getTeam(@PathParam("competitor-id") String competitorId) {
Competitor competitor = getService().getCompetitorStore().getExistingCompetitorByIdAsString(competitorId);
if (competitor == null) {
return Response.status(Status.NOT_FOUND)
.entity("Could not find a competitor with id '" + competitorId + "'.").type(MediaType.TEXT_PLAIN)
.build();
}
Team team = competitor.getTeam();
if (team == null) {
return Response.status(Status.NOT_FOUND)
.entity("Could not find a team associated with competitor '" + competitorId + "'.")
.type(MediaType.TEXT_PLAIN).build();
}
TeamJsonSerializer teamJsonSerializer = new TeamJsonSerializer(new PersonJsonSerializer(
new NationalityJsonSerializer()));
JSONObject teamJson = teamJsonSerializer.serialize(team);
String json = teamJson.toJSONString();
return Response.ok(json, MediaType.APPLICATION_JSON).build();
}
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces("application/json;charset=UTF-8")
@Path("{competitor-id}/image")
public String setTeamImage(@PathParam("competitor-id") String competitorId,
@FormDataParam("file") InputStream uploadedInputStream,
@FormDataParam("file") FormDataContentDisposition fileDetails) {
RacingEventService service = getService();
CompetitorStore store = service.getCompetitorStore();
Competitor competitor = store.getExistingCompetitorByIdAsString(competitorId);
if (competitor == null) {
logger.log(Level.INFO, "Could not find competitor to store image for: " + competitorId);
throw new WebApplicationException(Response.status(Status.BAD_REQUEST)
.entity("Could not find competitor with id " + competitorId).type(MediaType.TEXT_PLAIN).build());
}
URI imageUri;
try {
String fileName = fileDetails.getFileName();
long sizeInBytes = fileDetails.getSize();
imageUri = getService().getFileStorageService().storeFile(uploadedInputStream, fileName, sizeInBytes);
} catch (IOException | OperationFailedException | InvalidPropertiesException e) {
logger.log(Level.WARNING, "Could not store competitor image", e);
throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR)
.entity("Could not store competitor image").type(MediaType.TEXT_PLAIN).build());
}
getService().getCompetitorStore().updateCompetitor(competitorId, competitor.getName(), competitor.getColor(),
competitor.getBoat().getSailID(), competitor.getTeam().getNationality(), imageUri);
logger.log(Level.INFO, "Set team image for competitor " + competitor.getName());
JSONObject result = new JSONObject();
result.put(DeviceMappingConstants.JSON_TEAM_IMAGE_URI, imageUri.toString());
return result.toString();
}
}
@@ -91,7 +91,8 @@ public class AmazonS3FileStorageServiceImpl implements FileStorageService {
private URI getUri(String key) {
try {
return new URI(retrievalProtocol, bucketName.getValue() + "." + baseUrl, "/" + key, null);
// FIXME: region is missing s3-... see: http://stackoverflow.com/questions/10975475/amazon-s3-upload-file-and-get-url
return new URI(retrievalProtocol, baseUrl, "/" + bucketName.getValue() + "/" + key, null);
} catch (URISyntaxException e) {
logger.log(Level.WARNING, "Could not create URI for uploaded file with key " + key, e);
return null;
@@ -128,7 +129,6 @@ public class AmazonS3FileStorageServiceImpl implements FileStorageService {
}
logger.info("Removed file " + uri);
}
@Override
public Property[] getProperties() {
return new Property[] { accessId, accessKey, bucketName };
@@ -0,0 +1,112 @@
package com.sap.sse.filestorage.impl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sap.sse.filestorage.FileStorageService;
import com.sap.sse.filestorage.InvalidPropertiesException;
import com.sap.sse.filestorage.Property;
public class LocalFileStorageServiceImpl implements FileStorageService {
private static final Logger logger = Logger.getLogger(LocalFileStorageServiceImpl.class.getName());
private static final String host = "media.sapsailing.com";
private static final String path = "images";
private static final String retrievalProtocol = "http";
@Override
public URI storeFile(InputStream is, String originalFileName, long lengthInBytes) throws IOException {
OutputStream outputStream = null;
String pathToFile = path + "/" + getKey(originalFileName);
outputStream = new FileOutputStream(new File(pathToFile));
try {
int read = 0;
byte[] bytes = new byte[1024];
while ((read = is.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
} finally {
if (is != null) {
is.close();
}
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
}
return getUri(pathToFile);
}
private static String getKey(String originalFileName) {
String key = UUID.randomUUID().toString();
if (originalFileName != null) {
String ending = originalFileName.substring(originalFileName.lastIndexOf("."));
key += ending;
// key += "/" + originalFileName;
}
return key;
}
private static URI getUri(String pathToFile) {
try {
return new URI(retrievalProtocol, host, pathToFile, null);
} catch (URISyntaxException e) {
logger.log(Level.WARNING, "Could not create URI for uploaded file with path " + pathToFile, e);
return null;
}
}
@Override
public void removeFile(URI uri) {
String filePath = uri.getPath();
File file = new File(filePath);
if(!file.delete()){
logger.warning("Could not delete file with path "+filePath);
}
}
@Override
public Property[] getProperties() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setProperty(String name, String value) throws IllegalArgumentException {
// TODO Auto-generated method stub
}
@Override
public String getName() {
// TODO Auto-generated method stub
return null;
}
@Override
public String getDescription() {
// TODO Auto-generated method stub
return null;
}
@Override
public void testProperties() throws InvalidPropertiesException {
// TODO Auto-generated method stub
}
}
@@ -1,12 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.compiler.source=1.6
@@ -1,12 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.compiler.source=1.6
@@ -1,12 +1,12 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.7
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.7
org.eclipse.jdt.core.compiler.source=1.6