From 0c2db486267828a80f5ab1b86d6482241ced7829 Mon Sep 17 00:00:00 2001 From: RobinFleige Date: Fri, 3 Aug 2018 14:25:02 +0200 Subject: [PATCH] Moving the backend call to the Sailing service and a few code style improvements --- .../ui/adminconsole/EventCreateDialog.java | 2 +- .../gwt/ui/adminconsole/EventDialog.java | 5 +- .../gwt/ui/adminconsole/EventEditDialog.java | 2 +- .../gwt/ui/adminconsole/ImageDialog.java | 11 +- .../ui/adminconsole/ImagesListComposite.java | 102 ++------- .../sailing/gwt/ui/client/SailingService.java | 3 + .../gwt/ui/client/SailingServiceAsync.java | 3 + .../gwt/ui/server/SailingServiceImpl.java | 180 +++++++++++++++ .../META-INF/MANIFEST.MF | 1 + .../WEB-INF/web.xml | 10 +- .../gateway/impl/ImageResizingServlet.java | 205 ------------------ .../sap/sse/common/media/ImageConverter.java | 32 ++- ...stInlineEditorWithCheckboxesComposite.java | 27 +-- 13 files changed, 247 insertions(+), 336 deletions(-) delete mode 100644 java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ImageResizingServlet.java diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java index ddd2f10cc6e..20cb4143671 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventCreateDialog.java @@ -19,7 +19,7 @@ public class EventCreateDialog extends EventDialog { public EventCreateDialog(Collection existingEvents, List availableLeaderboardGroups, SailingServiceAsync sailingService, StringMessages stringMessages, ErrorReporter errorReporter, DialogCallback callback) { - super(new EventParameterValidator(stringMessages, existingEvents), sailingService, stringMessages, errorReporter, + super(new EventParameterValidator(stringMessages, existingEvents), sailingService, stringMessages, availableLeaderboardGroups, /* leaderboardGroups */ Collections.emptyList(), callback); nameEntryField = createTextBox(null); nameEntryField.setVisibleLength(50); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java index 99d29273480..ed864feb130 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventDialog.java @@ -33,7 +33,6 @@ import com.sap.sailing.gwt.ui.shared.CourseAreaDTO; import com.sap.sailing.gwt.ui.shared.EventDTO; import com.sap.sailing.gwt.ui.shared.LeaderboardGroupDTO; import com.sap.sailing.gwt.ui.shared.VenueDTO; -import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.IconResources; import com.sap.sse.gwt.client.Notification; import com.sap.sse.gwt.client.Notification.NotificationType; @@ -147,7 +146,7 @@ public abstract class EventDialog extends DataEntryDialogWithDateTimeBox availableLeaderboardGroups, + StringMessages stringMessages, List availableLeaderboardGroups, Iterable leaderboardGroupsOfEvent, DialogCallback callback) { super(stringMessages.event(), null, stringMessages.ok(), stringMessages.cancel(), validator, callback); testFileStorageService(sailingService);//callback: the earlier the better to improve user experience @@ -181,7 +180,7 @@ public abstract class EventDialog extends DataEntryDialogWithDateTimeBox suggestedWindFinderSpotCollections = AvailableWindFinderSpotCollections diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java index e73dd23cdfc..cf081bbb106 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/EventEditDialog.java @@ -14,7 +14,7 @@ import com.sap.sse.gwt.client.controls.datetime.DateTimeInput.Accuracy; public class EventEditDialog extends EventDialog { public EventEditDialog(EventDTO event, Collection otherExistingEvents, List availableLeaderboardGroups, SailingServiceAsync sailingService, StringMessages stringMessages, ErrorReporter errorReporter, DialogCallback callback) { - super(new EventParameterValidator(stringMessages, otherExistingEvents), sailingService, stringMessages, errorReporter, availableLeaderboardGroups, event.getLeaderboardGroups(), callback); + super(new EventParameterValidator(stringMessages, otherExistingEvents), sailingService, stringMessages, availableLeaderboardGroups, event.getLeaderboardGroups(), callback); nameEntryField = createTextBox(event.getName()); nameEntryField.setVisibleLength(50); descriptionEntryField = createTextArea(event.getDescription()); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java index b00d71bce85..ed14de0243b 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImageDialog.java @@ -6,6 +6,8 @@ import java.util.Date; import java.util.HashMap; import java.util.List; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.user.client.rpc.AsyncCallback; @@ -245,10 +247,10 @@ public abstract class ImageDialog extends DataEntryDialog { doResizeLabel.setVisible(false); tagsListEditor = new StringListInlineEditorComposite(Collections. emptyList(), new GenericStringListInlineEditorWithCheckboxesComposite.ExpandedUi(stringMessages, IconResources.INSTANCE.removeIcon(), /* suggestValues */ - MediaConstants.imageTagSuggestions, stringMessages.enterTagsForTheImage(), 30, doResize,doResizeLabel,new ValueChangeHandler() { - + MediaConstants.imageTagSuggestions, stringMessages.enterTagsForTheImage(), 30, doResize,doResizeLabel,new ClickHandler() { + @Override - public void onValueChange(ValueChangeEvent event) { + public void onClick(ClickEvent event) { validateAndUpdate(); CheckBox checkBox = (CheckBox)event.getSource(); if(checkBox.getValue()) { @@ -256,6 +258,7 @@ public abstract class ImageDialog extends DataEntryDialog { }else { checkBox.getElement().getStyle().setBackgroundColor("red"); } + } })); tagsListEditor.addValueChangeHandler(new ValueChangeHandler>() { @@ -265,7 +268,7 @@ public abstract class ImageDialog extends DataEntryDialog { } }); } - + @Override protected ImageDTO getResult() { List tags = new ArrayList(); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java index e222aaa92f0..c45edb973b5 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/adminconsole/ImagesListComposite.java @@ -1,8 +1,6 @@ package com.sap.sailing.gwt.ui.adminconsole; -import java.util.ArrayList; import java.util.Comparator; -import java.util.Date; import java.util.List; import com.google.gwt.cell.client.AbstractCell; @@ -11,17 +9,6 @@ import com.google.gwt.cell.client.SafeHtmlCell; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.http.client.Request; -import com.google.gwt.http.client.RequestBuilder; -import com.google.gwt.http.client.RequestCallback; -import com.google.gwt.http.client.RequestException; -import com.google.gwt.http.client.Response; -import com.google.gwt.json.client.JSONArray; -import com.google.gwt.json.client.JSONBoolean; -import com.google.gwt.json.client.JSONNumber; -import com.google.gwt.json.client.JSONObject; -import com.google.gwt.json.client.JSONParser; -import com.google.gwt.json.client.JSONString; import com.google.gwt.safehtml.client.SafeHtmlTemplates; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.safehtml.shared.SafeHtmlBuilder; @@ -31,6 +18,7 @@ import com.google.gwt.user.cellview.client.CellTable; import com.google.gwt.user.cellview.client.Column; import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler; import com.google.gwt.user.cellview.client.TextColumn; +import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.HorizontalPanel; @@ -46,7 +34,6 @@ import com.sap.sailing.gwt.ui.client.StringMessages; import com.sap.sailing.gwt.ui.common.client.DateAndTimeFormatterUtil; import com.sap.sse.common.media.MediaTagConstants; import com.sap.sse.common.util.NaturalComparator; -import com.sap.sse.gwt.client.ErrorReporter; import com.sap.sse.gwt.client.Notification; import com.sap.sse.gwt.client.Notification.NotificationType; import com.sap.sse.gwt.client.celltable.BaseCelltable; @@ -62,7 +49,6 @@ import com.sap.sse.gwt.client.media.ToResizeImageDTO; public class ImagesListComposite extends Composite { private final StringMessages stringMessages; private final SailingServiceAsync sailingService; - private final ErrorReporter errorReporter; private CellTable imageTable; private SingleSelectionModel imageSelectionModel; @@ -89,10 +75,9 @@ public class ImagesListComposite extends Composite { private final AdminConsoleTableResources tableRes = GWT.create(AdminConsoleTableResources.class); - public ImagesListComposite(SailingServiceAsync sailingService, final StringMessages stringMessages, final ErrorReporter errorReporter, MutableBoolean storageServiceAvailable) { + public ImagesListComposite(SailingServiceAsync sailingService, final StringMessages stringMessages, MutableBoolean storageServiceAvailable) { this.sailingService = sailingService; this.stringMessages = stringMessages; - this.errorReporter = errorReporter; this.storageServiceAvailable = storageServiceAvailable; mainPanel = new SimplePanel(); @@ -299,7 +284,7 @@ public class ImagesListComposite extends Composite { @Override public void ok(ImageDTO newImage) { if(newImage.getClass().equals(ToResizeImageDTO.class)) { - callResizingServlet(null, (ToResizeImageDTO) newImage); + callResizingService(newImage, null); }else { imageListDataProvider.getList().add(newImage); updateTableVisisbilty(); @@ -322,7 +307,7 @@ public class ImagesListComposite extends Composite { @Override public void ok(ImageDTO updatedImage) { if(updatedImage.getClass().equals(ToResizeImageDTO.class)) { - callResizingServlet(selectedImage, (ToResizeImageDTO) updatedImage); + callResizingService(updatedImage,selectedImage); }else { imageListDataProvider.getList().remove(selectedImage); imageListDataProvider.getList().add(updatedImage); @@ -332,67 +317,26 @@ public class ImagesListComposite extends Composite { }); dialog.show(); } - - private String imageToJSON(ToResizeImageDTO image) { - JSONObject obj = new JSONObject(); - obj.put("URI", new JSONString(image.getSourceRef())); - obj.put("Title", new JSONString(image.getTitle())); - obj.put("Subtitle", new JSONString(image.getSubtitle())); - obj.put("Height", new JSONNumber(image.getHeightInPx())); - obj.put("Width", new JSONNumber(image.getWidthInPx())); - obj.put("Date", new JSONNumber(image.getCreatedAtDate().getTime())); - obj.put("Copyright", new JSONString(image.getCopyright())); - JSONObject doResizeMap = new JSONObject(); - for(String doResize : image.getMap().keySet()) { - doResizeMap.put(doResize, JSONBoolean.getInstance(image.resizeForTag(doResize))); - } - obj.put("ResizeMap", doResizeMap); - JSONArray tags = new JSONArray(); - for(int i = 0; i < image.getTags().size(); i++) { - tags.set(i, new JSONString(image.getTags().get(i))); - } - obj.put("Tags", tags); - return obj.toString(); - } - - private void callResizingServlet(ImageDTO originalImage, ToResizeImageDTO image) { + + protected void callResizingService(ImageDTO newImage, ImageDTO originalImage) { + sailingService.resizeImage((ToResizeImageDTO) newImage, new AsyncCallback(){ + + @Override + public void onFailure(Throwable caught) { + Notification.notify(stringMessages.resizeUnsuccessfull(), NotificationType.ERROR); + } + + @Override + public void onSuccess(ImageDTO[] result) { + for(int i = 0; i < result.length; i++) { + imageListDataProvider.getList().add(result[i]); + } + imageListDataProvider.getList().remove(originalImage); + updateTableVisisbilty(); + Notification.notify(stringMessages.resizeSuccessfull(), NotificationType.SUCCESS); + + }}); - RequestBuilder builder = new RequestBuilder(RequestBuilder.POST,"/sailingserver/imageResize"); - builder.setHeader("Content-Type", "application/json"); - try { - builder.sendRequest(imageToJSON(image), new RequestCallback() { - - @Override - public void onResponseReceived(Request request, Response response) { - String responseText = response.getText(); - JSONArray images = JSONParser.parseStrict(responseText).isArray(); - - for(int i = 0; i < images.size(); i++) { - ImageDTO image = new ImageDTO(images.get(i).isObject().get("URI").isString().stringValue(),new Date(Long.valueOf(images.get(i).isObject().get("Date").isNumber().toString()))); - List tags = new ArrayList<>(); - JSONArray jsonTags = images.get(i).isObject().get("Tags").isArray(); - for(int j = 0; j < jsonTags.size(); j++) { - tags.add(jsonTags.get(j).isString().stringValue()); - } - image.setTags(tags); - image.setTitle(images.get(i).isObject().get("Title").isString().stringValue()); - image.setSubtitle(images.get(i).isObject().get("Subtitle").isString().stringValue()); - image.setSizeInPx(Integer.valueOf(images.get(i).isObject().get("Width").isNumber().toString()), Integer.valueOf(images.get(i).isObject().get("Height").isNumber().toString())); - imageListDataProvider.getList().add(image); - } - imageListDataProvider.getList().remove(originalImage); - updateTableVisisbilty(); - errorReporter.reportError(stringMessages.resizeSuccessfull(), true); - } - - @Override - public void onError(Request request, Throwable exception) { - errorReporter.reportError(stringMessages.resizeUnsuccessfull(), false); - } - }); - } catch (RequestException e) { - e.printStackTrace(); - } } private void updateTableVisisbilty() { diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java index b45952f0b1e..b4c9980a275 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingService.java @@ -121,6 +121,7 @@ import com.sap.sse.common.mail.MailException; import com.sap.sse.gwt.client.ServerInfoDTO; import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtService; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ToResizeImageDTO; import com.sap.sse.gwt.client.media.VideoDTO; import com.sap.sse.gwt.client.replication.RemoteReplicationService; @@ -782,4 +783,6 @@ public interface SailingService extends RemoteService, FileStorageManagementGwtS * Checks if the given race is currently in state tracking or loading. */ Boolean checkIfRaceIsTracking(RegattaAndRaceIdentifier race); + + ImageDTO[] resizeImage(ToResizeImageDTO toResizeImage) throws Exception; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java index 2c5324fc800..a319ac05a3e 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/SailingServiceAsync.java @@ -108,6 +108,7 @@ import com.sap.sse.common.Util.Triple; import com.sap.sse.gwt.client.ServerInfoRetriever; import com.sap.sse.gwt.client.filestorage.FileStorageManagementGwtServiceAsync; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ToResizeImageDTO; import com.sap.sse.gwt.client.media.VideoDTO; import com.sap.sse.gwt.client.replication.RemoteReplicationServiceAsync; import com.sap.sse.pairinglist.PairingList; @@ -989,4 +990,6 @@ public interface SailingServiceAsync extends ServerInfoRetriever, FileStorageMan * @see SailingService#checkIfRaceIsTracking(RegattaAndRaceIdentifier) */ void checkIfRaceIsTracking(RegattaAndRaceIdentifier raceIdentifier, AsyncCallback asyncCallback); + + void resizeImage(ToResizeImageDTO updatedImage, AsyncCallback asyncCallback) ; } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java index 03a47b7418d..c2fa7ae6ab1 100755 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/server/SailingServiceImpl.java @@ -1,5 +1,10 @@ package com.sap.sailing.gwt.ui.server; +import static java.lang.Math.toIntExact; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FilterInputStream; @@ -52,6 +57,13 @@ import java.util.regex.Pattern; import java.util.stream.StreamSupport; import java.util.zip.GZIPInputStream; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -449,6 +461,7 @@ import com.sap.sailing.gwt.ui.shared.WaypointDTO; import com.sap.sailing.gwt.ui.shared.WindDTO; import com.sap.sailing.gwt.ui.shared.WindInfoForRaceDTO; import com.sap.sailing.gwt.ui.shared.WindTrackInfoDTO; +import com.sap.sailing.gwt.ui.shared.media.MediaConstants; import com.sap.sailing.manage2sail.EventResultDescriptor; import com.sap.sailing.manage2sail.Manage2SailEventResultsParserImpl; import com.sap.sailing.manage2sail.RaceResultDescriptor; @@ -544,12 +557,16 @@ import com.sap.sse.common.impl.DegreeBearingImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.impl.TimeRangeImpl; import com.sap.sse.common.mail.MailException; +import com.sap.sse.common.media.ImageConverter; +import com.sap.sse.common.media.MediaTagConstants; import com.sap.sse.common.media.MimeType; import com.sap.sse.filestorage.FileStorageManagementService; import com.sap.sse.filestorage.FileStorageService; import com.sap.sse.filestorage.InvalidPropertiesException; +import com.sap.sse.filestorage.OperationFailedException; import com.sap.sse.gwt.client.ServerInfoDTO; import com.sap.sse.gwt.client.media.ImageDTO; +import com.sap.sse.gwt.client.media.ToResizeImageDTO; import com.sap.sse.gwt.client.media.VideoDTO; import com.sap.sse.gwt.dispatch.servlets.ProxiedRemoteServiceServlet; import com.sap.sse.gwt.server.filestorage.FileStorageServiceDTOUtils; @@ -7877,4 +7894,167 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S } } } + + @Override + public ImageDTO[] resizeImage(ToResizeImageDTO toResizeImage) throws Exception { + //In following size tag will describe the tags, that have a defined size in MediaConstants, which is LOGO, TEASER and STAGE at the moment + + //create ArrayList that will contain all images that are to return + List resizedImages = new ArrayList(); + //calculating the fileType of the image by its uri + String fileType = toResizeImage.getSourceRef().substring(toResizeImage.getSourceRef().lastIndexOf(".")+1); + //splitting the size-tags in size-tags that need a resize and size-tags that do not need a resize + List resizeTags = new ArrayList<>(); + List notResizeSizeTags = new ArrayList<>(); + ImageConverter.splitSizeTags(toResizeImage.getMap(),resizeTags,notResizeSizeTags); + //deleting all size-tags from the tags list, because after resizing there should only be one size tag per image + toResizeImage.getTags().removeAll(toResizeImage.getMap().keySet()); + //trying to receive the EXIF data and loading the image. If this does not work only the image is loaded + IIOMetadata metadata = null; + BufferedImage img = null; + boolean loaded = false; + try(InputStream is = getService().getFileStorageManagementService().getActiveFileStorageService().loadFile(new URI(toResizeImage.getSourceRef()))){ + Iterator readerIterator = ImageIO.getImageReadersBySuffix(fileType); + while(readerIterator.hasNext()&&!loaded) { + ImageReader reader = readerIterator.next(); + reader.setInput(ImageIO.createImageInputStream(is)); + metadata = reader.getImageMetadata(0); + img = reader.read(0); + loaded = metadata != null; + } + if(!loaded) { + throw new Exception("Loading file via ImageReader did not work, not able to load metadata, retrying to load with ImageIO.read()"); + } + }catch(Exception e) { + e.printStackTrace(); + } + if(!loaded) { + try (InputStream is = getService().getFileStorageManagementService().getActiveFileStorageService().loadFile(new URI(toResizeImage.getSourceRef()))){ + img = ImageConverter.isToBi(is); + } catch (NoCorrespondingServiceRegisteredException | OperationFailedException | InvalidPropertiesException + | IOException | URISyntaxException e) { + throw e; + } + } + + //iterating over every size-tag that needs a resize + for(String resizeTag : resizeTags) { + //creating a new ImageDTO object with all values from the ToResizeImageDTO object + ImageDTO image = toImageDTO(toResizeImage); + //re-adding the size-tag for this iteration, so every ImageDTO object only has one size-tag + image.getTags().add(resizeTag); + //resizing the image + BufferedImage resizedBufferedImage = resizeImage(img, resizeTag, fileType); + //adding the new width and h eight to the ImageDTO object + image.setSizeInPx(resizedBufferedImage.getWidth(), resizedBufferedImage.getHeight()); + //storing the image on FileStorageService + String newUri = storeImage(resizedBufferedImage, fileType, metadata).toString(); + //saving the new image ref uri to the ImageDTO object + image.setSourceRef(newUri); + //adding the resized ImageDTO object to arraylist + resizedImages.add(image); + } + //if there is no size tag that does not need a resize we can delete the original source + if(notResizeSizeTags.isEmpty()) { + try { + getService().getFileStorageManagementService().getActiveFileStorageService().removeFile(new URI(toResizeImage.getSourceRef())); + } catch (NoCorrespondingServiceRegisteredException | OperationFailedException | InvalidPropertiesException + | IOException | URISyntaxException e) { + e.printStackTrace(); + //file deleting did not work -> no important error, because the "only" result of this is one more stored image + } + } + //otherwise we have to create an ImageDTO object for every non-resize-size-tag + else { + for(String resizeTag : notResizeSizeTags) { + ImageDTO image = toImageDTO(toResizeImage); + //re-add the deleted specific size tag + image.getTags().add(resizeTag); + resizedImages.add(image); + } + } + return resizedImages.toArray(new ImageDTO[resizedImages.size()]); + } + + private BufferedImage resizeImage(BufferedImage img, String resizeTag, String fileType) { + BufferedImage resizedImage = null; + switch(resizeTag) { + case MediaTagConstants.LOGO: + resizedImage = ImageConverter.resize(img, MediaConstants.MIN_LOGO_IMAGE_WIDTH, MediaConstants.MAX_LOGO_IMAGE_WIDTH, MediaConstants.MIN_LOGO_IMAGE_HEIGHT, MediaConstants.MAX_LOGO_IMAGE_HEIGHT, fileType, false); + break; + case MediaTagConstants.STAGE: + resizedImage = ImageConverter.resize(img, MediaConstants.MIN_STAGE_IMAGE_WIDTH, MediaConstants.MAX_STAGE_IMAGE_WIDTH, MediaConstants.MIN_STAGE_IMAGE_HEIGHT, MediaConstants.MAX_STAGE_IMAGE_HEIGHT, fileType, false); + break; + case MediaTagConstants.TEASER: + resizedImage = ImageConverter.resize(img, MediaConstants.MIN_EVENTTEASER_IMAGE_WIDTH, MediaConstants.MAX_EVENTTEASER_IMAGE_WIDTH, MediaConstants.MIN_EVENTTEASER_IMAGE_HEIGHT, MediaConstants.MAX_EVENTTEASER_IMAGE_HEIGHT, fileType, false); + break; + default://can not occur, because we only loop over the sizeTags, which are the same as in the switch case + break; + } + return resizedImage; + } + + private URI storeImage(BufferedImage resizedBufferedImage, String fileType, IIOMetadata metaData) throws Exception { + URI imgUri = null; + byte[] bytes = null; + //trying to obtain OutputStream of the image with EXIF data + try (ImageOutputStream ios = ImageIO.createImageOutputStream(new ByteArrayOutputStream())){ + //the following should write the exif data of the image to all copies of the image//it should already work, but due to a bug the data array stays empty + Iterator writers = ImageIO.getImageWritersBySuffix(fileType); + while(writers.hasNext() && bytes == null) { + ImageWriter writer = writers.next(); + if(writer != null) { + writer.setOutput(ios); + IIOImage iioImage = new IIOImage(resizedBufferedImage, null, metaData); + ImageWriteParam param = writer.getDefaultWriteParam(); + IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(param); + writer.write(streamMetadata, iioImage, param); + writer.dispose(); + bytes = new byte[toIntExact(ios.length())]; + ios.read(bytes); + if(isZeroByteArray(bytes)) + bytes = null; + } + } + if(bytes == null) + throw new Exception("Saving file via FileWriter did not work, not able to write file with metadata, retrying with ImageIO.write()"); + + } catch (Exception e) { + bytes = null; + e.printStackTrace(); + } + //if obtaining an OutputStream if the image with EXIF data did not work, then write it without + if(bytes == null) { + try(InputStream is = ImageConverter.biToIs(resizedBufferedImage, fileType)){ + imgUri = getService().getFileStorageManagementService().getActiveFileStorageService().storeFile(is, "."+fileType, new Long(is.available())); + } + }else {//if it did work, then write the OutputStream to the FileStorageService + try(ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes)){ + imgUri = getService().getFileStorageManagementService().getActiveFileStorageService().storeFile(byteStream, "."+fileType, new Long(byteStream.available())); + } + } + return imgUri; + } + + private boolean isZeroByteArray(byte[] bytes) { + for(int i= 0; i < bytes.length; i++){ + if(bytes[i] != 0) + return true; + } + return false; + } + + public ImageDTO toImageDTO(ToResizeImageDTO toResizeImage) { + ImageDTO toReturn = new ImageDTO(toResizeImage.getSourceRef(), toResizeImage.getCreatedAtDate()); + toReturn.setTitle(toResizeImage.getTitle()); + toReturn.setCopyright(toResizeImage.getCopyright()); + toReturn.setLocale(toResizeImage.getLocale()); + toReturn.setMimeType(MimeType.byName(toResizeImage.getMimeType().name()));//creating a new mimetype object so they do not use the same reference + toReturn.setSizeInPx(toResizeImage.getWidthInPx(), toResizeImage.getHeightInPx()); + toReturn.setSubtitle(toResizeImage.getSubtitle()); + List tags = new ArrayList<>();//Creating a new list, so they have the same tags, but not use the same reference to these tags, otherwise they could affect each other by editing this list + tags.addAll(toResizeImage.getTags()); + toReturn.setTags(tags); + return toReturn; + } } diff --git a/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF b/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF index 28a7d21dadf..85f46c934dc 100644 --- a/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF +++ b/java/com.sap.sailing.server.gateway/META-INF/MANIFEST.MF @@ -8,6 +8,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Import-Package: com.sap.sailing.gwt.ui.shared.media, com.sap.sailing.server, com.sap.sailing.server.operationaltransformation, + com.sap.sse.gwt.client.media, javax.ws.rs;version="1.1.1", javax.ws.rs.core;version="1.1.1", javax.ws.rs.ext;version="1.1.1", diff --git a/java/com.sap.sailing.server.gateway/WEB-INF/web.xml b/java/com.sap.sailing.server.gateway/WEB-INF/web.xml index bb9514e7a4d..51d75160911 100644 --- a/java/com.sap.sailing.server.gateway/WEB-INF/web.xml +++ b/java/com.sap.sailing.server.gateway/WEB-INF/web.xml @@ -213,15 +213,7 @@ FileUploadServlet /fileupload - - ImageResizingServlet - com.sap.sailing.server.gateway.impl.ImageResizingServlet - - - - ImageResizingServlet - /imageResize - + Jersey REST API com.sap.sailing.server.gateway.jaxrs.RestServletContainer diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ImageResizingServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ImageResizingServlet.java deleted file mode 100644 index eb63e1d2284..00000000000 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ImageResizingServlet.java +++ /dev/null @@ -1,205 +0,0 @@ -package com.sap.sailing.server.gateway.impl; - -import static java.lang.Math.toIntExact; - -import java.awt.image.BufferedImage; -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; - -import javax.imageio.IIOImage; -import javax.imageio.ImageIO; -import javax.imageio.ImageReader; -import javax.imageio.ImageWriteParam; -import javax.imageio.ImageWriter; -import javax.imageio.metadata.IIOMetadata; -import javax.imageio.stream.ImageOutputStream; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -import com.sap.sailing.gwt.ui.shared.media.MediaConstants; -import com.sap.sailing.server.gateway.AbstractJsonHttpServlet; -import com.sap.sse.common.NoCorrespondingServiceRegisteredException; -import com.sap.sse.common.media.ImageConverter; -import com.sap.sse.common.media.MediaTagConstants; -import com.sap.sse.filestorage.InvalidPropertiesException; -import com.sap.sse.filestorage.OperationFailedException; - -public class ImageResizingServlet extends AbstractJsonHttpServlet { - private static final long serialVersionUID = 4240540462729675752L; - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - //In following size tag will describe the tags, that have a defined size in MediaConstants, which is LOGO, TEASER and STAGE at the moment - String jsonString = new BufferedReader(new InputStreamReader(req.getInputStream())).readLine(); - JSONObject obj = getObjFromJSON(jsonString); - List resizeTags = new ArrayList<>(); - List notResizeSizeTags = new ArrayList<>(); - JSONArray toReturnArray = new JSONArray(); - if(obj != null) { - String fileType = ((String)obj.get("URI")).substring(((String)obj.get("URI")).lastIndexOf(".")+1); - JSONArray tags = (JSONArray) obj.get("Tags"); - JSONObject resizeMap = (JSONObject) obj.get("ResizeMap"); - IIOMetadata metadata = null; - BufferedImage img; - try(InputStream is = getInputStreamFromURIString(((String)obj.get("URI")))){ - ImageReader reader = ImageIO.getImageReadersBySuffix(fileType).next(); - reader.setInput(ImageIO.createImageInputStream(is)); - metadata = reader.getImageMetadata(0); - img = reader.read(0); - }catch(Exception e) { - InputStream is = getInputStreamFromURIString(((String)obj.get("URI"))); - img = ImageConverter.isToBi(is); - is.close(); - } - - for(Object tagKey : resizeMap.keySet()) { - if((boolean) resizeMap.get(tagKey)) { - resizeTags.add((String)tagKey);//size tags, that have the resize checkBox checked - }else{ - notResizeSizeTags.add((String)tagKey);//size tags, that not have the resize checkBox checked - } - } - - for(String resizeTag : resizeTags) { - for(String toDeleteTag : resizeTags) {//delete all size tags - tags.remove(toDeleteTag); - } - for(String toDeleteTag : notResizeSizeTags) {//delete all size tags - tags.remove(toDeleteTag); - } - tags.add(resizeTag);//read the deleted specific size tag - resizeAndAddToAr(img, toReturnArray, obj, resizeTag, fileType, metadata); - obj = getObjFromJSON(jsonString);//reset the object - tags = (JSONArray) obj.get("Tags");//and the tags - } - if(notResizeSizeTags.isEmpty()) {//if there is no size tag that does not need a resize we can delete the original source - try { - getService().getFileStorageManagementService().getActiveFileStorageService().removeFile(new URI((String)obj.get("URI"))); - } catch (NoCorrespondingServiceRegisteredException | OperationFailedException - | InvalidPropertiesException | URISyntaxException e) { - e.printStackTrace(); - } - }else { - for(String resizeTag : notResizeSizeTags) { - for(String toDeleteTag : resizeTags) {//delete all size tags - tags.remove(toDeleteTag); - } - for(String toDeleteTag : notResizeSizeTags) {//delete all size tags - tags.remove(toDeleteTag); - } - tags.add(resizeTag);//re-add the deleted specific size tag - toReturnArray.add(obj); - obj = getObjFromJSON(jsonString);//reset the object for next size-tag-iteration - tags = (JSONArray) obj.get("Tags");//and the tags - } - } - - } - resp.getWriter().write(toReturnArray.toJSONString()); - } - - private InputStream getInputStreamFromURIString(String uri) { - try { - return getService().getFileStorageManagementService().getActiveFileStorageService().loadFile(new URI(uri)); - } catch (NoCorrespondingServiceRegisteredException | OperationFailedException | InvalidPropertiesException - | IOException | URISyntaxException e) { - e.printStackTrace(); - } - return null; - } - - private JSONObject getObjFromJSON(String json) { - JSONParser parser = new JSONParser(); - try { - return (JSONObject) parser.parse(json); - } catch (ParseException e) { - e.printStackTrace(); - } - return null; - } - - private void resizeAndAddToAr(BufferedImage img, JSONArray array, JSONObject resizedImageObject, String tag, String fileType, IIOMetadata metaData) { - URI imgUri = null; - BufferedImage resizedImage = null; - switch(tag) { - case MediaTagConstants.LOGO: - resizedImage = ImageConverter.resize(img, MediaConstants.MIN_LOGO_IMAGE_WIDTH, MediaConstants.MAX_LOGO_IMAGE_WIDTH, MediaConstants.MIN_LOGO_IMAGE_HEIGHT, MediaConstants.MAX_LOGO_IMAGE_HEIGHT, fileType, false); - break; - case MediaTagConstants.STAGE: - resizedImage = ImageConverter.resize(img, MediaConstants.MIN_STAGE_IMAGE_WIDTH, MediaConstants.MAX_STAGE_IMAGE_WIDTH, MediaConstants.MIN_STAGE_IMAGE_HEIGHT, MediaConstants.MAX_STAGE_IMAGE_HEIGHT, fileType, false); - break; - case MediaTagConstants.TEASER: - resizedImage = ImageConverter.resize(img, MediaConstants.MIN_EVENTTEASER_IMAGE_WIDTH, MediaConstants.MAX_EVENTTEASER_IMAGE_WIDTH, MediaConstants.MIN_EVENTTEASER_IMAGE_HEIGHT, MediaConstants.MAX_EVENTTEASER_IMAGE_HEIGHT, fileType, false); - break; - default://can not occur, because we only loop over the sizeTags, which are the same as in the switch case - break; - } - try (ImageOutputStream ios = ImageIO.createImageOutputStream(new ByteArrayOutputStream())){ - //the following should write the exif data of the image to all copies of the image//it should already work, but due to a bug the data array stays empty - Iterator writers = ImageIO.getImageWritersBySuffix(fileType); - byte[] bytes = null; - while(writers.hasNext() && bytes == null) { - ImageWriter writer = writers.next(); - if(writer != null) { - writer.setOutput(ios); - IIOImage iioImage = new IIOImage(resizedImage, null, metaData); - ImageWriteParam param = writer.getDefaultWriteParam(); - IIOMetadata streamMetadata = writer.getDefaultStreamMetadata(param); - writer.write(streamMetadata, iioImage, param); - writer.dispose(); - bytes = new byte[toIntExact(ios.length())*2]; - ios.read(bytes); - bytes = trim(bytes); - if(bytes.length == 0) - bytes = null; - } - } - if(bytes == null) { - InputStream is = ImageConverter.biToIs(resizedImage, fileType); - imgUri = getService().getFileStorageManagementService().getActiveFileStorageService().storeFile(is, "."+fileType, new Long(is.available())); - is.close(); - }else { - - ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes); - imgUri = getService().getFileStorageManagementService().getActiveFileStorageService().storeFile(byteStream, "."+fileType, new Long(byteStream.available())); - byteStream.close(); - } - } catch (IOException | NoCorrespondingServiceRegisteredException | OperationFailedException | InvalidPropertiesException e1) { - e1.printStackTrace(); - } - - - - resizedImageObject.put("URI", imgUri.toString()); - resizedImageObject.put("Width", resizedImage.getWidth()); - resizedImageObject.put("Height", resizedImage.getHeight()); - array.add(resizedImageObject); - } - - static byte[] trim(byte[] bytes) - { - int i = bytes.length - 1; - while (i >= 0 && bytes[i] == 0) - { - --i; - } - - return Arrays.copyOf(bytes, i + 1); - } -} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageConverter.java b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageConverter.java index af3c9f2a227..524ed449c54 100644 --- a/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageConverter.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/media/ImageConverter.java @@ -6,27 +6,14 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.List; +import java.util.Map; + import javax.imageio.ImageIO; + import org.apache.commons.codec.binary.Base64; public class ImageConverter { - - public static String resizeAndConvertToBase64(InputStream is, int minWidth, int maxWidth, int minHeight, - int maxHeight, String imageFormat, boolean upsize) { - BufferedImage img = isToBi(is); - if(img.getWidth()>maxWidth || img.getHeight() > maxHeight || (upsize && (img.getWidth() < minWidth || img.getHeight() < minHeight))) { - int[] dimensions = calculateActualDimensions(img.getWidth(), img.getHeight(), minWidth, maxWidth, minHeight, - maxHeight, upsize); - if(dimensions != null) { - img = resize(img, dimensions[0], dimensions[1]); - return convertToBase64(biToBy(img, imageFormat)); - }else { - return null; - } - }else { - return null; - } - } private static int[] calculateActualDimensions(double width, double height, double minWidth, double maxWidth, double minHeight, double maxHeight, boolean upsize) { @@ -125,5 +112,14 @@ public class ImageConverter { g.dispose(); return resizedImage; } - + + public static void splitSizeTags(Map sizeTags, List resizeTags, List notResizeSizeTags) { + for(Object tagKey : sizeTags.keySet()) { + if(sizeTags.get(tagKey)) { + resizeTags.add((String)tagKey);//size tags, that have the resize checkBox checked + }else{ + notResizeSizeTags.add((String)tagKey);//size tags, that not have the resize checkBox checked + } + } + } } diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/GenericStringListInlineEditorWithCheckboxesComposite.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/GenericStringListInlineEditorWithCheckboxesComposite.java index dff87dc70c5..b513bb09f53 100644 --- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/GenericStringListInlineEditorWithCheckboxesComposite.java +++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/GenericStringListInlineEditorWithCheckboxesComposite.java @@ -1,7 +1,8 @@ package com.sap.sse.gwt.client.controls.listedit; import java.util.List; -import com.google.gwt.event.logical.shared.ValueChangeHandler; + +import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.resources.client.ImageResource; import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Grid; @@ -24,14 +25,14 @@ public abstract class GenericStringListInlineEditorWithCheckboxesComposite checkBoxes; private Label checkBoxTopLabel; - private ValueChangeHandler checkBoxValueChangeHandler; + private ClickHandler checkBoxClickHandler; public ExpandedUi(StringMessages stringMessages, ImageResource removeImage, List suggestValues, - String placeholderTextForAddTextbox, int textBoxSize, List checkBoxes, Label checkBoxTopLabel, ValueChangeHandler checkBoxValueChangeHandler) { + String placeholderTextForAddTextbox, int textBoxSize, List checkBoxes, Label checkBoxTopLabel, ClickHandler clickHandler) { super(stringMessages, removeImage, suggestValues, placeholderTextForAddTextbox, textBoxSize); this.checkBoxes = checkBoxes; this.checkBoxTopLabel = checkBoxTopLabel; - this.checkBoxValueChangeHandler = checkBoxValueChangeHandler; + this.checkBoxClickHandler = clickHandler; } @@ -43,18 +44,12 @@ public abstract class GenericStringListInlineEditorWithCheckboxesComposite