]*>(.*)", "$1"));
}
+
+ public void setUploadEnabled(boolean uploadEnabled) {
+ if (uploadEnabled) {
+ uploadFormPanel.add(uploadPanel);
+ } else {
+ uploadFormPanel.remove(uploadPanel);
+ }
+ }
}
diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/CollapsedListEditorUi.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/CollapsedListEditorUi.java
index 97bee0018e1..2e24402c20b 100644
--- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/CollapsedListEditorUi.java
+++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/CollapsedListEditorUi.java
@@ -24,7 +24,7 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
* {@link ListEditorComposite} with the respective {@link ExpandedListEditorUi} strategy that will be passed through
* from this class's constructor to the {@link #createExpandedUi(List, ExpandedListEditorUi)} method.
*
- * Implementing subclasses may choose to override the {@link #onRowAdded()} and/or the {@link #onRowRemoved()} method(s)
+ * Implementing subclasses may choose to override the {@link #onRowAdded()} and/or the {@link #onRowRemoved(int)} method(s)
* to be notified of changes to the list.
*
* @author Lukas Niemeier
@@ -123,7 +123,7 @@ public abstract class CollapsedListEditorUi extends ListEditorUi
*
- * Implementing subclasses may choose to override the {@link #onRowAdded()} and/or the {@link #onRowRemoved()} method(s)
+ * Implementing subclasses may choose to override the {@link #onRowAdded()} and/or the {@link #onRowRemoved(int)} method(s)
* to be notified of changes to the list. Alternatively or in addition, clients can
* {@link ListEditorComposite#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) add a value
* change handler} to the enclosing {@link ListEditorComposite}.
@@ -37,7 +37,7 @@ import com.sap.sse.gwt.client.StringMessages;
public abstract class ExpandedListEditorUi extends ListEditorUi {
private final ImageResource removeImage;
- private Grid expandedValuesGrid;
+ protected Grid expandedValuesGrid;
private final boolean canRemoveItems;
/**
@@ -80,7 +80,7 @@ public abstract class ExpandedListEditorUi extends ListEditorUi extends ListEditorUi extends ListEditorUi
+ * The type of the items in the list
+ */
+public class ExpandedUiWithCheckboxes extends GenericStringListInlineEditorComposite.ExpandedUi {
+
+ private final List checkBoxes;
+ private final String checkBoxText;
+ private final List changeHandler = new ArrayList<>();
+ static final ListEditorResources ress = GWT.create(ListEditorResources.class);
+
+ /**
+ * Creates an editable list with checkboxes for every entry
+ *
+ * @param stringMessages
+ * the holder of the used strings
+ * @param removeImage
+ * the icon for removing an entry from the editor
+ * @param suggestValues
+ * values that will be suggested when entering something into the editor
+ * @param placeholderTextForAddTextbox
+ * @param textBoxSize
+ * the size if the textbox
+ * @param checkBoxText
+ * the text shown next to the checkboxes
+ */
+ public ExpandedUiWithCheckboxes(StringMessages stringMessages, ImageResource removeImage,
+ List suggestValues, String placeholderTextForAddTextbox, int textBoxSize, String checkBoxText) {
+ super(stringMessages, removeImage, suggestValues, placeholderTextForAddTextbox, textBoxSize);
+ this.checkBoxes = new ArrayList();
+ this.checkBoxText = checkBoxText;
+ ress.css().ensureInjected();
+ }
+
+ /**
+ * Used for the css styles
+ */
+ interface ListEditorResources extends ClientBundle {
+ @Source("ListEditor.gss")
+ ListEditorCSS css();
+ }
+
+ interface ListEditorCSS extends CssResource {
+ String checkBoxInvisible();
+
+ String checkBoxNormal();
+
+ String checkBoxError();
+ }
+
+ /**
+ * Returns the checkboxes,so they can be accessed from another class
+ *
+ * @returns the checkboxes
+ */
+ public List getCheckBoxes() {
+ return checkBoxes;
+ }
+
+ /**
+ * used to set the checkbox style from another class
+ *
+ * @returns String the StyleName of the style
+ */
+ public static String getInvisibleStyle() {
+ return ress.css().checkBoxInvisible();
+ }
+
+ public static String getErrorStyle() {
+ return ress.css().checkBoxError();
+ }
+
+ public static String getNormalStyle() {
+ return ress.css().checkBoxNormal();
+ }
+
+ /**
+ * See {@link ExpandedListEditorUi#addRow(Object)}
+ */
+ @Override
+ protected void addRow(ValueType newValue) {
+ super.addRow(newValue);
+ final CheckBox checkBox = new CheckBox(checkBoxText);
+ checkBox.setStylePrimaryName(getInvisibleStyle());
+ checkBox.addClickHandler(new ClickHandler() {
+ @Override
+ public void onClick(ClickEvent event) {
+ CheckBox source = (CheckBox) event.getSource();
+ if (source.getValue()) {
+ source.setStylePrimaryName(getNormalStyle());
+ } else {
+ source.setStylePrimaryName(getErrorStyle());
+ }
+ for (ChangeHandler changeHandler : ExpandedUiWithCheckboxes.this.changeHandler) {
+ changeHandler.onChange(null);
+ }
+ }
+ });
+ checkBoxes.add(checkBox);
+ expandedValuesGrid.setWidget(expandedValuesGrid.getRowCount() - 1, 2, checkBox);
+ }
+
+ /**
+ * See {@link ListEditorUiStrategy#initWidget()}
+ */
+ @Override
+ public Widget initWidget() {
+ expandedValuesGrid = new Grid(0, 3);
+ expandedValuesGrid.ensureDebugId("ExpandedValuesGrid");
+
+ VerticalPanel panel = new VerticalPanel();
+ panel.add(createAddWidget());
+ panel.add(expandedValuesGrid);
+ return panel;
+
+ }
+
+ /**
+ * See {@link ListEditorUiStrategy#onRowRemoved(int)}
+ */
+ @Override
+ public void onRowRemoved(int rowIndex) {
+ checkBoxes.remove(rowIndex);
+ }
+
+ public void addChangeHandler(ChangeHandler handler) {
+ changeHandler.add(handler);
+ }
+}
diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditor.gss b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditor.gss
new file mode 100644
index 00000000000..ca4a59596b0
--- /dev/null
+++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditor.gss
@@ -0,0 +1,23 @@
+.checkBoxInvisible {
+ visibility : hidden;
+ background-color : red;
+ padding: 3px;
+ padding-right: 5px;
+ padding-bottom: 4px;
+}
+
+.checkBoxNormal {
+ visibility : visible;
+ background-color : white;
+ padding: 3px;
+ padding-right: 5px;
+ padding-bottom: 4px;
+}
+
+.checkBoxError {
+ visibility : visible;
+ background-color : red;
+ padding: 3px;
+ padding-right: 5px;
+ padding-bottom: 4px;
+}
\ No newline at end of file
diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditorUiStrategy.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditorUiStrategy.java
index 1981cf9015f..314f9e56559 100644
--- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditorUiStrategy.java
+++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/controls/listedit/ListEditorUiStrategy.java
@@ -10,7 +10,7 @@ import com.google.gwt.user.client.ui.Widget;
* {@link ListEditorComposite#getValue() values} of the context editor that was passed to
* {@link #setContext(ListEditorComposite)} during editor initialization.
*
- * Objects will receive calls to {@link #onRowAdded()} when a value was added to the list, and {@link #onRowRemoved()} when
+ * Objects will receive calls to {@link #onRowAdded()} when a value was added to the list, and {@link #onRowRemoved(int)} when
* a value was removed from the list.
*
* There are two default implementations of this interface: {@link CollapsedListEditorUi} and {@link ExpandedListEditorUi}.
@@ -54,6 +54,7 @@ public interface ListEditorUiStrategy {
/**
* Called by the framework after a value was removed from the list. Note that this is not the place for this UI
* strategy to actually implement the UI changes. Those are expected to already have happened before.
+ * @param rowIndex The index of the removed row
*/
- void onRowRemoved();
+ void onRowRemoved(int rowIndex);
}
\ No newline at end of file
diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/filestorage/FileStorageManagementGwtService.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/filestorage/FileStorageManagementGwtService.java
index 0ad38080e53..d2e92c7fef5 100644
--- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/filestorage/FileStorageManagementGwtService.java
+++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/filestorage/FileStorageManagementGwtService.java
@@ -19,6 +19,8 @@ public interface FileStorageManagementGwtService extends RemoteService {
FileStorageServiceDTO[] getAvailableFileStorageServices(String localeInfoName);
/**
+ * If serviceName is null, calls {@link FileStorageManagementGwtService#getActiveFileStorageServiceName()} and uses the returned name
+ *
* @throws NoCorrespondingServiceRegisteredException service may have disappeared from registry in the meantime
*/
FileStorageServicePropertyErrorsDTO testFileStorageServiceProperties(String serviceName, String localeInfoName) throws NoCorrespondingServiceRegisteredException, IOException;
diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java
index 10edb3175c0..9468bbeb416 100644
--- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java
+++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/AbstractMediaDTO.java
@@ -25,6 +25,7 @@ public abstract class AbstractMediaDTO implements IsSerializable, Comparable resizingTask;
+
+ /** for GWT */
+ @Deprecated
+ protected ImageResizingTaskDTO() {
+ }
+
+ /**
+ * Creates an {@link ImageDTO} from the parameters
+ *
+ * @param imageRef
+ * needed for creating ImageDTO
+ * @param createdAtDate
+ * needed for creating ImageDTO
+ * @param resizingTask
+ * stored Information about resizing
+ */
+ public ImageResizingTaskDTO(String imageRef, Date createdAtDate, List resizingTask) {
+ this(new ImageDTO(imageRef, createdAtDate), resizingTask);
+ }
+
+ /**
+ *
+ * @param image
+ * the stored ImageDTO
+ * @param resizingTask
+ * stored Information about resizing
+ */
+ public ImageResizingTaskDTO(ImageDTO image, List resizingTask) {
+ this.image = image;
+ this.resizingTask = resizingTask;
+ }
+
+ /**
+ * @returns the ImageDTO
+ */
+ public ImageDTO getImage() {
+ return image;
+ }
+
+ /**
+ * @returns the List of MediaTagConstants
+ */
+ public List getResizingTask() {
+ return resizingTask;
+ }
+
+ /**
+ * Creates a clone of the ImageDTo with new references, so they do not interfere Used for resizing to edit
+ * afterwards, to easily copy all data from the original ImageDTO
+ *
+ * @returns a clone of the ImageDTO
+ */
+ public ImageDTO cloneImageDTO() {
+ final ImageDTO toReturn = new ImageDTO(image.getSourceRef(), image.getCreatedAtDate());
+ toReturn.setTitle(image.getTitle());
+ toReturn.setCopyright(image.getCopyright());
+ toReturn.setLocale(image.getLocale());
+ // creating a new mimetype object so they do not use the same reference
+ toReturn.setMimeType(MimeType.byName(image.getMimeType().name()));
+ toReturn.setSizeInPx(image.getWidthInPx(), image.getHeightInPx());
+ toReturn.setSubtitle(image.getSubtitle());
+ // 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
+ final List tags = new ArrayList<>();
+ tags.addAll(image.getTags());
+ toReturn.setTags(tags);
+ return toReturn;
+ }
+}
\ No newline at end of file
diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java
index 007b51faf10..4915d8c22df 100644
--- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java
+++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/client/media/VideoDTO.java
@@ -10,6 +10,7 @@ public class VideoDTO extends AbstractMediaDTO {
private String thumbnailRef;
/** for GWT */
+ @Deprecated
protected VideoDTO() {
}
@@ -34,7 +35,7 @@ public class VideoDTO extends AbstractMediaDTO {
}
public boolean isFeatured() {
- return hasTag(MediaTagConstants.FEATURED);
+ return hasTag(MediaTagConstants.FEATURED.getName());
}
@Override
diff --git a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/resources/css/CommonControls.css b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/resources/css/CommonControls.css
index ff51c8b8c97..7571aad5920 100644
--- a/java/com.sap.sse.gwt/src/com/sap/sse/gwt/resources/css/CommonControls.css
+++ b/java/com.sap.sse.gwt/src/com/sap/sse/gwt/resources/css/CommonControls.css
@@ -729,7 +729,7 @@ body ::-webkit-scrollbar-track {
}
.gwt-Button, .gwt-Button:visited {
- font-size: 0, 9rem;
+ font-size: 0.9rem;
display: inline-block;
color: #fff;
border: none;
diff --git a/java/com.sap.sse.security.ui/GWT Security DevMode.launch b/java/com.sap.sse.security.ui/GWT Security DevMode.launch
index 8154a68dd9d..18e9479fd03 100644
--- a/java/com.sap.sse.security.ui/GWT Security DevMode.launch
+++ b/java/com.sap.sse.security.ui/GWT Security DevMode.launch
@@ -1,111 +1,111 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/com.sap.sse.security.ui/GWT Security SDM.launch b/java/com.sap.sse.security.ui/GWT Security SDM.launch
index f7b277131fe..c8b77e31b45 100644
--- a/java/com.sap.sse.security.ui/GWT Security SDM.launch
+++ b/java/com.sap.sse.security.ui/GWT Security SDM.launch
@@ -1,112 +1,112 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/java/com.sap.sse.security.ui/build.properties b/java/com.sap.sse.security.ui/build.properties
old mode 100644
new mode 100755
diff --git a/java/com.sap.sse.test/src/com/sap/see/pairinglist/test/CommonPrefixStatsTest.java b/java/com.sap.sse.test/src/com/sap/see/pairinglist/test/CommonPrefixStatsTest.java
new file mode 100755
index 00000000000..79e6a871cc3
--- /dev/null
+++ b/java/com.sap.sse.test/src/com/sap/see/pairinglist/test/CommonPrefixStatsTest.java
@@ -0,0 +1,118 @@
+package com.sap.see.pairinglist.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.logging.Logger;
+
+import org.junit.Test;
+
+/**
+ * Constructs randomized number sequences of equal length, for each element in the sequence using a random number
+ * between 0 and a given limit, say {@code c}. The sequences are then ordered numerically, such that two sequences are
+ * equal if all their elements are equal, and with s1 being less than s2 if the first element where s1 and s2 differ is
+ * less for s1. Then, by enumerating the sorted list of sequences, the number of changed elements between the previous
+ * and the next element is counted. This number is then related to the total number of sequence elements produced in the
+ * process. In addition to the {@code c} parameter the process is parameterized by the number of sequences to generate
+ * ({@code i}) and the length of each sequence ({@code f}).
+ *
+ * @author Axel Uhl (d043530)
+ *
+ */
+public class CommonPrefixStatsTest {
+ private static final Logger logger = Logger.getLogger(CommonPrefixStatsTest.class.getName());
+
+ private final Random random = new Random();
+
+ private final Comparator sequenceComparator = (s1, s2)->{
+ for (int i=0; is2[i]) {
+ return 1;
+ } else if (s1[i] generateSeedSequences(int howMany, int maxNumberPlusOne, int sequenceLength) {
+ final List result = new ArrayList<>(howMany);
+ for (int i=0; i generateSortedSeedSequences(int howMany, int maxNumberPlusOne, int sequenceLength) {
+ final List result = generateSeedSequences(howMany, maxNumberPlusOne, sequenceLength);
+ Collections.sort(result, sequenceComparator);
+ return result;
+ }
+
+ private int countChanges(List sequences) {
+ int count;
+ if (sequences.isEmpty()) {
+ count = 0;
+ } else {
+ final Iterator iterator = sequences.iterator();
+ int[] previous = iterator.next();
+ count = previous.length; // the first sequence is all new
+ while (iterator.hasNext()) {
+ final int[] next = iterator.next();
+ count += countChanges(previous, next);
+ previous = next;
+ }
+ }
+ return count;
+ }
+
+ private int countChanges(int[] previous, int[] next) {
+ assert previous.length == next.length;
+ int changesCount = previous.length;
+ while (previous[previous.length-changesCount] == next[next.length-changesCount]) {
+ changesCount--;
+ }
+ return changesCount;
+ }
+
+ private int totalSeeds(List sequences) {
+ return sequences.isEmpty() ? 0 : sequences.size() * sequences.iterator().next().length;
+ }
+
+ public double computeSavingRatio(int howMany, int maxNumberPlusOne, int sequenceLength) {
+ final List sequences = generateSortedSeedSequences(howMany, maxNumberPlusOne, sequenceLength);
+ final int changesInSortedSequences = countChanges(sequences);
+ final int totalSeeds = totalSeeds(sequences);
+ final double savingRatio = 1.-((double) changesInSortedSequences) / (double) totalSeeds;
+ return savingRatio;
+ }
+
+ @Test
+ public void testOneMillionSequencesForFifteenFlightsWithEighteenCompetitors() {
+ final int runs = 3;
+ double savingRatioSum = 0.0;
+ for (int i=0; i0.2);
+ }
+}
diff --git a/java/com.sap.sse.test/src/com/sap/sse/test/ImageConverterTest.java b/java/com.sap.sse.test/src/com/sap/sse/test/ImageConverterTest.java
new file mode 100644
index 00000000000..48548f6dc80
--- /dev/null
+++ b/java/com.sap.sse.test/src/com/sap/sse/test/ImageConverterTest.java
@@ -0,0 +1,79 @@
+package com.sap.sse.test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.sap.sse.util.ImageConverter;
+import com.sap.sse.util.ImageConverter.ImageWithMetadata;
+
+/**
+ *
+ * @author Robin Fleige(D067799)
+ *
+ */
+public class ImageConverterTest {
+ private ImageConverter converter;
+ private ImageWithMetadata pngImage;
+ private ImageWithMetadata jpgImage;
+
+ private final byte[] onePixelPngExample = new byte[]{-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1, 8, 2, 0, 0, 0, -112, 119, 83, -34, 0, 0, 0, 12, 73, 68, 65, 84, 120, -38, 99, 96, 96, 96, 0, 0, 0, 4, 0, 1, -56, -22, -21, -7, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, 96, -126};
+ private final byte[] onePixelJpgExample = new byte[]{-1, -40, -1, -32, 0, 16, 74, 70, 73, 70, 0, 1, 2, 0, 0, 1, 0, 1, 0, 0, -1, -37, 0, 67, 0, 8, 6, 6, 7, 6, 5, 8, 7, 7, 7, 9, 9, 8, 10, 12, 20, 13, 12, 11, 11, 12, 25, 18, 19, 15, 20, 29, 26, 31, 30, 29, 26, 28, 28, 32, 36, 46, 39, 32, 34, 44, 35, 28, 28, 40, 55, 41, 44, 48, 49, 52, 52, 52, 31, 39, 57, 61, 56, 50, 60, 46, 51, 52, 50, -1, -37, 0, 67, 1, 9, 9, 9, 12, 11, 12, 24, 13, 13, 24, 50, 33, 28, 33, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, -1, -64, 0, 17, 8, 0, 1, 0, 1, 3, 1, 34, 0, 2, 17, 1, 3, 17, 1, -1, -60, 0, 31, 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -60, 0, -75, 16, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125, 1, 2, 3, 0, 4, 17, 5, 18, 33, 49, 65, 6, 19, 81, 97, 7, 34, 113, 20, 50, -127, -111, -95, 8, 35, 66, -79, -63, 21, 82, -47, -16, 36, 51, 98, 114, -126, 9, 10, 22, 23, 24, 25, 26, 37, 38, 39, 40, 41, 42, 52, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, -125, -124, -123, -122, -121, -120, -119, -118, -110, -109, -108, -107, -106, -105, -104, -103, -102, -94, -93, -92, -91, -90, -89, -88, -87, -86, -78, -77, -76, -75, -74, -73, -72, -71, -70, -62, -61, -60, -59, -58, -57, -56, -55, -54, -46, -45, -44, -43, -42, -41, -40, -39, -38, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -1, -60, 0, 31, 1, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, -1, -60, 0, -75, 17, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119, 0, 1, 2, 3, 17, 4, 5, 33, 49, 6, 18, 65, 81, 7, 97, 113, 19, 34, 50, -127, 8, 20, 66, -111, -95, -79, -63, 9, 35, 51, 82, -16, 21, 98, 114, -47, 10, 22, 36, 52, -31, 37, -15, 23, 24, 25, 26, 38, 39, 40, 41, 42, 53, 54, 55, 56, 57, 58, 67, 68, 69, 70, 71, 72, 73, 74, 83, 84, 85, 86, 87, 88, 89, 90, 99, 100, 101, 102, 103, 104, 105, 106, 115, 116, 117, 118, 119, 120, 121, 122, -126, -125, -124, -123, -122, -121, -120, -119, -118, -110, -109, -108, -107, -106, -105, -104, -103, -102, -94, -93, -92, -91, -90, -89, -88, -87, -86, -78, -77, -76, -75, -74, -73, -72, -71, -70, -62, -61, -60, -59, -58, -57, -56, -55, -54, -46, -45, -44, -43, -42, -41, -40, -39, -38, -30, -29, -28, -27, -26, -25, -24, -23, -22, -14, -13, -12, -11, -10, -9, -8, -7, -6, -1, -38, 0, 12, 3, 1, 0, 2, 17, 3, 17, 0, 63, 0, -9, -6, 40, -94, -128, 63, -1, -39};
+
+ private final int baseSize = 100;
+ private final int halfSize = baseSize / 2;
+ private final int doubleSize = baseSize * 2;
+ private final int minSize = 0;
+
+ /**
+ * Setting up the testing environment
+ */
+ @Before
+ public void setUp() {
+ converter = new ImageConverter();
+ pngImage = converter.loadImage(new ByteArrayInputStream(onePixelPngExample), "png");
+ jpgImage = converter.loadImage(new ByteArrayInputStream(onePixelJpgExample), "jpg");
+ }
+
+ /**
+ * Tests the calculation of the dimensions, which is used for resizing the image to a fitting size
+ */
+ @Test
+ public void testCalculateDimensions() {
+ int[] dimensions;
+ dimensions = converter.calculateDimensions(baseSize, baseSize, halfSize, doubleSize, halfSize, doubleSize);
+ assertEquals(dimensions[0], baseSize);
+ assertEquals(dimensions[1], baseSize);
+ dimensions = converter.calculateDimensions(baseSize, baseSize, minSize, halfSize, minSize, halfSize);
+ assertEquals(dimensions[0], halfSize);
+ assertEquals(dimensions[1], halfSize);
+ dimensions = converter.calculateDimensions(baseSize, doubleSize, minSize, halfSize, minSize, halfSize);
+ assertTrue(dimensions[0] < halfSize);
+ assertEquals(dimensions[1], halfSize);
+ dimensions = converter.calculateDimensions(minSize, minSize, halfSize, baseSize, halfSize, baseSize);
+ assertNull(dimensions);
+ }
+
+ /**
+ * Tests the conversions that are done while resizing an image
+ *
+ * @throws IOException
+ */
+ @Test
+ public void testConversions() throws IOException {
+ byte[] byteArray;
+ byteArray = converter.inputStreamToByteArray(
+ converter.imageWithMetadataToInputStream(jpgImage.getImage(), jpgImage.getMetadata(), "jpg"));
+ assertArrayEquals(onePixelJpgExample, byteArray);
+ byteArray = converter.inputStreamToByteArray(
+ converter.imageWithMetadataToInputStream(pngImage.getImage(), pngImage.getMetadata(), "png"));
+ assertArrayEquals(onePixelPngExample, byteArray);
+ }
+}
diff --git a/java/com.sap.sse/src/com/sap/sse/util/ImageConverter.java b/java/com.sap.sse/src/com/sap/sse/util/ImageConverter.java
new file mode 100644
index 00000000000..fe58f34d9d8
--- /dev/null
+++ b/java/com.sap.sse/src/com/sap/sse/util/ImageConverter.java
@@ -0,0 +1,432 @@
+package com.sap.sse.util;
+
+import static java.lang.Math.toIntExact;
+
+import java.awt.Graphics2D;
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+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 com.sap.sse.common.Base64Utils;
+import com.sap.sse.common.media.MediaTagConstants;
+
+/**
+ * /** An Utility Class to help resizing an image
+ *
+ * @author Robin Fleige (D067799)
+ */
+public class ImageConverter {
+ private static final Logger logger = Logger.getLogger(ImageConverter.class.getName());
+
+ /**
+ * Writes a BufferedImage to an InputStream. This should only be used as a backup, if
+ * {@link ImageConverter#imageWithMetadataToInputStream(BufferedImage, IIOMetadata, String)} fails
+ *
+ * @param image
+ * The BufferedImage that should be converted
+ * @param imageFormat
+ * the format of the image, for example "png", "jpeg" or "jpg"
+ * @returns an InputStream with the Information of the Image
+ * @throws IOException
+ */
+ private InputStream imageToInputStream(final BufferedImage image, final String imageFormat) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try {
+ ImageIO.write(image, imageFormat, bos);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, e.getMessage());
+ }
+ final byte[] arr = bos.toByteArray();
+ return new ByteArrayInputStream(arr);
+ }
+
+ /**
+ * Resizes an BufferedImage, so it fits into the defined bounds without changing the width-height-ratio. The image
+ * is kept as large as possible inside this bounds.
+ *
+ * @param image
+ * The BufferedImage that should be resized
+ * @param minWidth
+ * the minimum width the image should have after resizing
+ * @param maxWidth
+ * the maximum width the image should have after resizing
+ * @param minHeight
+ * the minimum height the image should have after resizing
+ * @param maxHeight
+ * the maximum height the image should have after resizing
+ * @returns the resized BufferedImage. Returns null, if BufferedImage is null, or if the defined bounds do not fit
+ * the image
+ */
+ public BufferedImage resize(final BufferedImage image, final int minWidth, final int maxWidth, final int minHeight,
+ final int maxHeight) {
+ final int[] dimensions = calculateDimensions(image.getWidth(), image.getHeight(), minWidth, maxWidth, minHeight,
+ maxHeight);
+ final BufferedImage resizedImage;
+ if (dimensions != null) {
+ resizedImage = resize(image, dimensions[0], dimensions[1]);
+ } else {
+ resizedImage = null;
+ }
+ return resizedImage;
+ }
+
+ /**
+ * Calculates the dimensions of an image, so it fits inside the defined bounds without changing the
+ * width-height-ratio. Keeps it as big as possible
+ *
+ * @param width
+ * the current width of the image that should be resized
+ * @param height
+ * the current height of the image that should be resized
+ * @param minWidth
+ * the minimum width the image should have after resizing
+ * @param maxWidth
+ * the maximum width the image should have after resizing
+ * @param minHeight
+ * the minimum height the image should have after resizing
+ * @param maxHeight
+ * the maximum height the image should have after resizing
+ * @returns an array of two integers, where the first entry is the fitting width and the second is the fitting
+ * height. returns null, if the defined bounds do not fit the current size
+ */
+ public int[] calculateDimensions(final double width, final double height, final double minWidth,
+ final double maxWidth, final double minHeight, final double maxHeight) {
+ int[] dimensions = new int[2];
+ if (maxWidth >= 0 && maxHeight >= 0 && maxHeight > minHeight && maxWidth > minWidth && width > minWidth
+ && height > minHeight) {
+ if (maxWidth <= width || maxHeight <= height) {
+ if (width / maxWidth > height / maxHeight) {
+ dimensions[1] = (int) maxWidth;
+ dimensions[1] = (int) (height / width * maxWidth);
+ if (dimensions[1] >= minHeight) {
+ dimensions[0] = (int) maxWidth;
+ } else {
+ dimensions = null;
+ }
+ } else {
+ dimensions[0] = (int) (width / height * maxHeight);
+ if (dimensions[0] >= minWidth) {
+ dimensions[1] = (int) maxHeight;
+ } else {
+ dimensions = null;
+ }
+ }
+ } else {
+ dimensions[0] = (int) width;
+ dimensions[1] = (int) height;
+ }
+ } else {
+ dimensions = null;
+ }
+ return dimensions;
+ }
+
+ /**
+ * Resizes an BufferedImage, to the width and height.
+ *
+ * @param image
+ * The BufferedImage that should be resized
+ * @param demandWidth
+ * the width the image should have after resizing
+ * @param demandHeight
+ * the height the image should have after resizing
+ * @returns the resized BufferedImage. Returns null, if BufferedImage is null
+ */
+ private BufferedImage resize(final BufferedImage image, final int demandedWidth, final int demandedHeight) {
+ final BufferedImage resizedImage = new BufferedImage((int) demandedWidth, (int) demandedHeight,
+ image.getType());
+ final Graphics2D g = resizedImage.createGraphics();
+ final AffineTransform transform = new AffineTransform();
+ transform.scale((double) demandedWidth / image.getWidth(), (double) demandedHeight / image.getHeight());
+ final BufferedImageOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
+ g.drawImage(image, op, 0, 0);
+ g.dispose();
+ return resizedImage;
+ }
+
+ /**
+ * Creates an InputStream from a BufferedImage, the IIOMetadata of the image and the imageFormat
+ *
+ * @param bufferdImage
+ * the image that has to be written to an InputStream
+ * @param metadata
+ * the IIOMetadata that should be stored in the InputStream with the BufferedImage
+ * @param imageFormat
+ * the format of the image, for example "png", "jpeg" or "jpg"
+ * @throws IOException
+ * @returns an InputStream with the data of the BufferedImage and if possible with the IIOMetadata. Returns null if
+ * the image is null or the imageFormat is incorrect
+ */
+ public InputStream imageWithMetadataToInputStream(final BufferedImage bufferdImage, final IIOMetadata metadata,
+ final String imageFormat) throws IOException {
+ byte[] bytes = null;
+ if (metadata != 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
+ final Iterator writers = ImageIO.getImageWritersBySuffix(imageFormat);
+ while (writers.hasNext() && bytes == null) {
+ final ImageWriter writer = writers.next();
+ if (writer != null) {
+ writer.setOutput(ios);
+ final IIOImage iioImage = new IIOImage(bufferdImage, null, metadata);
+ final ImageWriteParam param = writer.getDefaultWriteParam();
+ final 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;
+ logger.log(Level.INFO, e.getMessage());
+ } // if obtaining an OutputStream if the image with EXIF data did not work, then write it without
+ }
+ final InputStream toReturn;
+ if (bytes == null) {
+ toReturn = imageToInputStream(bufferdImage, imageFormat);
+ } else {// if it did work, then write the OutputStream to the FileStorageService
+ toReturn = new ByteArrayInputStream(bytes);
+ }
+ return toReturn;
+ }
+
+ /**
+ * Writes an inputstream into a ByteArray
+ *
+ * @param inputStream
+ * the inputstream that should be stored in the ByteArray
+ * @returns an Array of Bytes with the data of the inputstream
+ */
+ public byte[] inputStreamToByteArray(final InputStream inputStream) {
+ byte[] byteArray = null;
+ try {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ int nRead;
+ byte[] data = new byte[1024];
+ while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, nRead);
+ }
+ buffer.flush();
+ byteArray = buffer.toByteArray();
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, e.getMessage());
+ }
+ return byteArray;
+ }
+
+ /**
+ * Checks if a byte array only contains zeros
+ *
+ * @param bytes
+ * an byte array
+ * @returns true if the byte array is null, empty or only contains zeros, otherwise false
+ */
+ private boolean isZeroByteArray(final byte[] bytes) {
+ boolean toReturn = true;
+ if (bytes != null) {
+ for (int i = 0; i < bytes.length; i++) {
+ if (bytes[i] != 0) {
+ toReturn = false;
+ }
+ }
+ }
+ return toReturn;
+ }
+
+ /**
+ * Converts an InputStream that contains an image to a Base64 String
+ *
+ * @param inputStream
+ * the InputStream that should be converted
+ * @param imageFormat
+ * the format of the image, for example "png", "jpeg" or "jpg"
+ * @returns the Base64 representation of the InputStream
+ * @throws IOException
+ */
+ public String convertToBase64(final InputStream inputStream, final String imageFormat) throws IOException {
+ return convertToBase64(bufferedImageToByteArray(loadBufferedImageFromInputStream(inputStream), imageFormat));
+ }
+
+ /**
+ * Converts an BufferedImage to a Base64 String
+ *
+ * @param image
+ * the image that should be converted as a BufferedImage
+ * @param imageFormat
+ * the format of the image, for example "png", "jpeg" or "jpg"
+ * @returns the Base64 representation of the image
+ * @throws IOException
+ */
+ public String convertToBase64(final BufferedImage image, final String imageFormat) throws IOException {
+ return convertToBase64(bufferedImageToByteArray(image, imageFormat));
+ }
+
+ /**
+ * Converts an array of bytes to a Base64 String
+ *
+ * @param bytes
+ * an array of bytes
+ * @returns the Base64 representation of the byte array
+ */
+ private String convertToBase64(final byte[] bytes) {
+ return Base64Utils.toBase64(bytes);
+ }
+
+ /**
+ * Converts an InputStream to a BufferedImage. This should only be used as a backup, if
+ * {@link ImageConverter#loadImage(InputStream, String)} fails
+ *
+ * @param inputStream
+ * @return
+ */
+ private BufferedImage loadBufferedImageFromInputStream(final InputStream inputStream) {
+ BufferedImage image = null;
+ try {
+ image = ImageIO.read(inputStream);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, e.getMessage());
+ }
+ return image;
+ }
+
+ // looses metadata, so should not be used for storing an image, but only for showing an image
+ /**
+ * Converts an BufferedImage to a ByteArray that contains all of its information This Method does not use the
+ * IIOMetadata of the original image, so it should not be used to store images, but only for showing them. To also
+ * use the IIOMetadata of the image use the @link
+ * {@link ImageConverter#imageWithMetadataToInputStream(BufferedImage, IIOMetadata, String)} and then the @link
+ * {@link ImageConverter#inputStreamToByteArray(InputStream)} method
+ *
+ * @param image
+ * the image that should be converted to a ByteArray
+ * @param imageFormat
+ * the format of the image, for example "png", "jpeg" or "jpg"
+ * @returns an ByteArray with all the information of the image
+ */
+ public byte[] bufferedImageToByteArray(final BufferedImage image, final String imageFormat) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ ImageIO.write(image, imageFormat, baos);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, e.getMessage());
+ }
+ return baos.toByteArray();
+ }
+
+ /**
+ * Converts one BufferedImage to a list of at least one BufferedImage with different sizes as described in the given
+ * {@link MediaTagConstants}
+ *
+ * @param image
+ * the image that should be converted
+ * @param resizingTasks
+ * a List of {@link MediaTagConstants} that define to which size the image should be resized
+ * @returns a list of BufferedImages, that contains as many BufferedImages as resizingTask contains
+ * {@link MediaTagConstants}
+ */
+ public List convertImage(final BufferedImage image, final List resizingTasks) {
+ final List resizedImages = new ArrayList<>();
+ for (MediaTagConstants tag : resizingTasks) {
+ resizedImages
+ .add(resize(image, tag.getMinWidth(), tag.getMaxWidth(), tag.getMinHeight(), tag.getMaxHeight()));
+ }
+ return resizedImages;
+ }
+
+ /**
+ * Loads an BufferedImage and the IIOMetadata from an InputStream that contains an image.
+ *
+ * @param inputStream
+ * the InputStream that contains the image and the metadata
+ * @param imageFormat
+ * the format of the image, for example "png", "jpeg" or "jpg"
+ * @returns an {@link ImageWithMetadata} that contains the BufferedImage and the IIOMetadata of the image If the
+ * loading of the IIOMetadata does not work, returns an {@link ImageWithMetadata} where metadata is null
+ */
+ public ImageWithMetadata loadImage(final InputStream inputStream, final String imageFormat) {
+ // trying to receive the EXIF data and loading the image. If this does not work only the image is loaded
+ final ImageConverter converter = new ImageConverter();
+ BufferedImage image = null;
+ IIOMetadata metadata = null;
+ boolean loaded = false;
+ byte[] bytes = converter.inputStreamToByteArray(inputStream);
+ try {
+ final Iterator readerIterator = ImageIO.getImageReadersBySuffix(imageFormat);
+ while (readerIterator.hasNext() && !loaded) {
+ final ImageReader reader = readerIterator.next();
+ reader.setInput(ImageIO.createImageInputStream(new ByteArrayInputStream(bytes)));
+ metadata = reader.getImageMetadata(0);
+ image = 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) {
+ logger.log(Level.INFO, e.getMessage());
+ }
+ if (!loaded) {
+ image = converter.loadBufferedImageFromInputStream(new ByteArrayInputStream(bytes));
+ metadata = null;
+ }
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ logger.log(Level.WARNING, "Potential ressource leak");
+ }
+ return new ImageWithMetadata(image, metadata);
+ }
+
+ /**
+ * A Data Storage class to store an BufferedImage and IIOMetadata
+ *
+ * @author Robin Fleige (D067799)
+ *
+ */
+ public class ImageWithMetadata {
+ private final BufferedImage image;
+ private final IIOMetadata metadata;
+
+ public ImageWithMetadata(BufferedImage image, IIOMetadata metadata) {
+ this.image = image;
+ this.metadata = metadata;
+ }
+
+ public BufferedImage getImage() {
+ return image;
+ }
+
+ public IIOMetadata getMetadata() {
+ return metadata;
+ }
+ }
+}
diff --git a/wiki/info/landscape/typical-development-scenarios.md b/wiki/info/landscape/typical-development-scenarios.md
index 6abddf0d611..8ab41fb9a85 100644
--- a/wiki/info/landscape/typical-development-scenarios.md
+++ b/wiki/info/landscape/typical-development-scenarios.md
@@ -14,6 +14,7 @@ We distinguish two cases: adding a 3rd-party bundle to the target platform and a
* Go to directory 'java/com.sap.sailing.targetplatform/scripts'
* Rebuild the base target platform by running the script 'createLocalBaseP2repository.sh'
* Generate the target definition for this local repository by running the script 'createLocalTargetDef.sh'
+ * Currently this scripts work for the cygwin shell and the git bash, if the path to your files in the target definition is incorrect, this may be the reason.
* Test the new overall target platform
* by setting the race-analysis-p2-local.target as target platform in the IDE
* by running the local maven build via ''buildAndUpdateProduct.sh -v build'' (the ''-v'' switch builds and uses the local p2 repository)