diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java index 97c89f3a5b7..3feb096fc2d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialog.java @@ -4,6 +4,7 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.dom.client.AnchorElement; @@ -14,11 +15,20 @@ 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.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.JSONException; +import com.google.gwt.json.client.JSONParser; +import com.google.gwt.json.client.JSONValue; import com.google.gwt.media.client.Audio; import com.google.gwt.media.client.MediaBase; import com.google.gwt.regexp.shared.MatchResult; import com.google.gwt.regexp.shared.RegExp; import com.google.gwt.typedarrays.shared.Int8Array; +import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.DialogBox; @@ -42,6 +52,7 @@ import com.sap.sailing.gwt.ui.client.media.JSDownloadUtils.JSDownloadCallback; import com.sap.sailing.gwt.ui.common.client.YoutubeApi; import com.sap.sse.common.Duration; import com.sap.sse.common.TimePoint; +import com.sap.sse.common.fileupload.FileUploadConstants; import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsTimePoint; import com.sap.sse.common.media.MediaSubType; @@ -58,10 +69,13 @@ import com.sap.sse.gwt.client.dialog.DataEntryDialog; import com.sap.sse.gwt.client.formfactor.DeviceDetector; public class NewMediaDialog extends DataEntryDialog implements FileStorageServiceConnectionTestObserver { + + private final Logger logger = Logger.getLogger(getClass().getName()); private static final boolean DONT_FIRE_EVENTS = false; private static final Duration DEFAULT_DURATION = new MillisecondsDurationImpl(0L); private static final NewMediaDialogResources RESOURCES = NewMediaDialogResources.INSTANCE; + private static final String PROGRESS_STATUS_URL = "/sailingserver/fileupload/progress"; protected static class MediaTrackValidator implements Validator { private final StringMessages stringMessages; @@ -402,23 +416,81 @@ public class NewMediaDialog extends DataEntryDialog implements FileS progressOverlay.addStyleName(NewMediaDialogResources.INSTANCE.css().progressOverlay()); FlowPanel progressSpinner = new FlowPanel(); progressSpinner.addStyleName(NewMediaDialogResources.INSTANCE.css().progressSpinner()); + final Label counter = new Label("0%"); + counter.addStyleName(NewMediaDialogResources.INSTANCE.css().progressCounter()); progressOverlay.add(progressSpinner); + progressOverlay.add(counter); progressOverlay.setVisible(false); + final Timer t = new Timer(){ + public void run() { + requestProgressPercentage(this, counter); + } + }; urlBox.setStartUploadEvent(new StartUploadEvent() { @Override public void startUpload() { progressOverlay.setVisible(true); + t.scheduleRepeating(1000); } }); urlBox.setEndUploadEvent(new EndUploadEvent() { @Override public void endUpload() { progressOverlay.setVisible(false); + t.cancel(); } }); mainPanel.add(progressOverlay); return mainPanel; } + + private void requestProgressPercentage(final Timer t, final Label counter) { + RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, PROGRESS_STATUS_URL); + try { + builder.sendRequest(null, new RequestCallback() { + @Override + public void onResponseReceived(Request request, Response response) { + try { + String result = response.getText().trim(); + JSONValue resultJsonValue = JSONParser.parseStrict(result); + if (resultJsonValue.isObject().get(FileUploadConstants.PROGRESS_PERCENTAGE) != null) { + int percentage = (int) resultJsonValue.isObject() + .get(FileUploadConstants.PROGRESS_PERCENTAGE).isNumber().doubleValue(); + long theBytesRead = (long) resultJsonValue.isObject() + .get(FileUploadConstants.PROGRESS_BYTE_DONE).isNumber().doubleValue(); + long theContentLength = (long) resultJsonValue.isObject() + .get(FileUploadConstants.PROGRESS_BYTE_TOTAL).isNumber().doubleValue(); + if (percentage > 99) { + logger.info("Upload complete."); + t.cancel(); + } + counter.setText(percentage + "%"); + if (theContentLength == -1) { + counter.setTitle(theBytesRead + " bytes"); + } else { + counter.setTitle(theBytesRead + " / " + theContentLength + " bytes."); + } + } else { + logger.severe("Cannot read result from progress request"); + t.cancel(); + } + } catch (JSONException e) { + logger.log(Level.SEVERE, "Cannot read result from progress request", e); + t.cancel(); + } + } + + @Override + public void onError(Request request, Throwable exception) { + logger.log(Level.SEVERE, "Error occured while requesting upload status. (1)", exception); + t.cancel(); + } + }); + } catch (RequestException e) { + logger.log(Level.SEVERE, "Error occured while requesting upload status. (2)", e); + t.cancel(); + } + } private String sliceBefore(String lastPathSegment, String slicer) { int paramSegment = lastPathSegment.indexOf(slicer); diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialogResources.gss b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialogResources.gss index 1f2465d08bb..b387210db8d 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialogResources.gss +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialogResources.gss @@ -104,6 +104,10 @@ -webkit-animation: pulse 4s infinite, spin 2s linear infinite; } +.progress-counter { + position: absolute; +} + @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } diff --git a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialogResources.java b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialogResources.java index 441a1ea27a3..20f7e421728 100644 --- a/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialogResources.java +++ b/java/com.sap.sailing.gwt.ui/src/main/java/com/sap/sailing/gwt/ui/client/media/NewMediaDialogResources.java @@ -39,6 +39,9 @@ public interface NewMediaDialogResources extends ClientBundle { @ClassName("progress-spinner") String progressSpinner(); + + @ClassName("progress-counter") + String progressCounter(); } @Source("NewMediaDialogResources.gss") 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 92266a300c0..fa7f474cb2a 100644 --- a/java/com.sap.sailing.server.gateway/WEB-INF/web.xml +++ b/java/com.sap.sailing.server.gateway/WEB-INF/web.xml @@ -221,6 +221,14 @@ FileUploadServlet /fileupload + + ProgressServlet + com.sap.sailing.server.gateway.impl.ProgressServlet + + + ProgressServlet + /fileupload/progress + ORCCertificateImportServlet com.sap.sailing.server.gateway.orc.ORCCertificateImportServlet diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/AbstractFileUploadServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/AbstractFileUploadServlet.java index 7c712f22d94..fe87204d44b 100755 --- a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/AbstractFileUploadServlet.java +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/AbstractFileUploadServlet.java @@ -6,6 +6,7 @@ import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; @@ -34,6 +35,12 @@ public abstract class AbstractFileUploadServlet extends AbstractJsonHttpServlet } FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); + HttpSession session = req.getSession(true); + if (session != null) { + ProgressListener progressListener = new ProgressListener(); + upload.setProgressListener(progressListener); + session.setAttribute("progressListener", progressListener); + } try { @SuppressWarnings("unchecked") List items = (List) upload.parseRequest(req); @@ -44,4 +51,5 @@ public abstract class AbstractFileUploadServlet extends AbstractJsonHttpServlet } abstract protected void process(List fileItems, HttpServletRequest req, HttpServletResponse resp) throws IOException; + } diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ProgressListener.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ProgressListener.java new file mode 100644 index 00000000000..70c429d253a --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ProgressListener.java @@ -0,0 +1,89 @@ +package com.sap.sailing.server.gateway.impl; + +public class ProgressListener implements org.apache.commons.fileupload.ProgressListener { + + private long num100Ks = 0; + + private long theBytesRead = 0; + private long theContentLength = -1; + private int whichItem = 0; + private int percentDone = 0; + private boolean contentLengthKnown = false; + + public void update(long bytesRead, long contentLength, int items) { + + if (contentLength > -1) { + contentLengthKnown = true; + } + theBytesRead = bytesRead; + theContentLength = contentLength; + whichItem = items; + + long nowNum100Ks = bytesRead / 100000; + // Only run this code once every 100K + if (nowNum100Ks > num100Ks || theBytesRead == theContentLength) { + num100Ks = nowNum100Ks; + if (contentLengthKnown) { + percentDone = (int) Math.round(100.00 * bytesRead / contentLength); + } + //System.out.println(getMessage()); + } + } + + public String getMessage() { + if (theContentLength == -1) { + return "" + theBytesRead + " of Unknown-Total bytes have been read."; + } else { + return "" + theBytesRead + " of " + theContentLength + " bytes have been read (" + percentDone + "% done)."; + } + + } + + public long getNum100Ks() { + return num100Ks; + } + + public void setNum100Ks(long num100Ks) { + this.num100Ks = num100Ks; + } + + public long getTheBytesRead() { + return theBytesRead; + } + + public void setTheBytesRead(long theBytesRead) { + this.theBytesRead = theBytesRead; + } + + public long getTheContentLength() { + return theContentLength; + } + + public void setTheContentLength(long theContentLength) { + this.theContentLength = theContentLength; + } + + public int getWhichItem() { + return whichItem; + } + + public void setWhichItem(int whichItem) { + this.whichItem = whichItem; + } + + public int getPercentDone() { + return percentDone; + } + + public void setPercentDone(int percentDone) { + this.percentDone = percentDone; + } + + public boolean isContentLengthKnown() { + return contentLengthKnown; + } + + public void setContentLengthKnown(boolean contentLengthKnown) { + this.contentLengthKnown = contentLengthKnown; + } +} diff --git a/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ProgressServlet.java b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ProgressServlet.java new file mode 100644 index 00000000000..9972c24083b --- /dev/null +++ b/java/com.sap.sailing.server.gateway/src/com/sap/sailing/server/gateway/impl/ProgressServlet.java @@ -0,0 +1,45 @@ +package com.sap.sailing.server.gateway.impl; + +import java.io.IOException; +import java.util.logging.Logger; + +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.json.simple.JSONObject; + +import com.sap.sse.common.fileupload.FileUploadConstants; + +public class ProgressServlet extends HttpServlet { + + private final Logger logger = Logger.getLogger(getClass().getName()); + + private static final long serialVersionUID = 6179739052238280324L; + + public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { + doPost(request, response); + } + + public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setContentType("text/html"); + + HttpSession session = request.getSession(true); + if (session == null) { + logger.warning("Sorry, session is null"); // just to be safe + return; + } + + ProgressListener progressListener = (ProgressListener) session.getAttribute("progressListener"); + if (progressListener == null) { + logger.warning("Progress listener is null"); + return; + } + JSONObject json = new JSONObject(); + json.put(FileUploadConstants.PROGRESS_PERCENTAGE, progressListener.getPercentDone()); + json.put(FileUploadConstants.PROGRESS_BYTE_DONE, progressListener.getTheBytesRead()); + json.put(FileUploadConstants.PROGRESS_BYTE_TOTAL, progressListener.getTheContentLength()); + json.writeJSONString(response.getWriter()); + } +} diff --git a/java/com.sap.sse.common/src/com/sap/sse/common/fileupload/FileUploadConstants.java b/java/com.sap.sse.common/src/com/sap/sse/common/fileupload/FileUploadConstants.java index 0d83d76a813..325c77bc944 100755 --- a/java/com.sap.sse.common/src/com/sap/sse/common/fileupload/FileUploadConstants.java +++ b/java/com.sap.sse.common/src/com/sap/sse/common/fileupload/FileUploadConstants.java @@ -5,4 +5,7 @@ public interface FileUploadConstants { String FILE_URI = "file_uri"; String MESSAGE = "message"; String STATUS = "status"; + String PROGRESS_PERCENTAGE = "progress_percentage"; + String PROGRESS_BYTE_DONE = "progress_byte_done"; + String PROGRESS_BYTE_TOTAL = "progress_byte_total"; } diff --git a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java index bf2a5ec0054..5386ff66af4 100755 --- a/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java +++ b/java/com.sap.sse.gwt.adminconsole/src/com/sap/sse/gwt/adminconsole/URLFieldWithFileUpload.java @@ -48,6 +48,7 @@ public class URLFieldWithFileUpload extends Composite implements HasValue