Implemented Feature #5028 with WebSockets
Workspace enhancements: avoid http timeout during folder compression git-svn-id: http://svn.d4science-ii.research-infrastructures.eu/gcube/trunk/portlets/user/workspace-tree-widget@131599 82a268e6-3cf1-43bd-a215-b396298e98cftask/19600
parent
fc95a2fad8
commit
10e426abd7
@ -0,0 +1,201 @@
|
||||
package org.gcube.portlets.user.workspace.client.util;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.gcube.portlets.user.gcubewidgets.client.popup.GCubeDialog;
|
||||
import org.gcube.portlets.user.workspace.client.ConstantsExplorer;
|
||||
import org.gcube.portlets.user.workspace.client.event.FileDownloadEvent;
|
||||
import org.gcube.portlets.user.workspace.client.rpc.GWTWorkspaceService;
|
||||
import org.gcube.portlets.user.workspace.client.rpc.GWTWorkspaceServiceAsync;
|
||||
import org.gcube.portlets.user.workspace.client.view.windows.MessageBoxAlert;
|
||||
import org.realityforge.gwt.websockets.client.WebSocket;
|
||||
import org.realityforge.gwt.websockets.client.WebSocketListener;
|
||||
|
||||
import com.github.gwtbootstrap.client.ui.Button;
|
||||
import com.github.gwtbootstrap.client.ui.Icon;
|
||||
import com.github.gwtbootstrap.client.ui.Paragraph;
|
||||
import com.github.gwtbootstrap.client.ui.constants.IconType;
|
||||
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.RequestBuilder;
|
||||
import com.google.gwt.typedarrays.shared.ArrayBuffer;
|
||||
import com.google.gwt.user.client.Timer;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.HasAlignment;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
|
||||
public class FolderDownloadDialog extends GCubeDialog implements WebSocketListener {
|
||||
private final GWTWorkspaceServiceAsync rpcWorkspaceService = (GWTWorkspaceServiceAsync) GWT.create(GWTWorkspaceService.class);
|
||||
|
||||
public static final int WIDTH = 300;
|
||||
public static final int HEIGHT = 50;
|
||||
|
||||
private final WebSocket webSocket = WebSocket.newWebSocketIfSupported();
|
||||
private final String username;
|
||||
private VerticalPanel topPanel = new VerticalPanel();
|
||||
private Icon loading = new Icon();
|
||||
Button close = new Button("Cancel Download");
|
||||
private Paragraph toShow = new Paragraph("Locating folder, please wait ...");
|
||||
private String webSocketURL;
|
||||
public FolderDownloadDialog(final FileDownloadEvent folder2Download, String username) {
|
||||
this.webSocket.setListener( this );
|
||||
this.username = username;
|
||||
setText("Preparing folder download");
|
||||
|
||||
|
||||
loading.setSpin(true);
|
||||
loading.setType(IconType.ROTATE_RIGHT);
|
||||
|
||||
topPanel.add(toShow);
|
||||
topPanel.add(loading);
|
||||
topPanel.setPixelSize(WIDTH, HEIGHT);
|
||||
|
||||
|
||||
VerticalPanel bPanel = new VerticalPanel();
|
||||
bPanel.setWidth(WIDTH+"px");
|
||||
bPanel.setHorizontalAlignment(HasAlignment.ALIGN_RIGHT);
|
||||
bPanel.add(close);
|
||||
close.addClickHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
topPanel.add(bPanel);
|
||||
add(topPanel);
|
||||
|
||||
rpcWorkspaceService.getServletContextPath(Window.Location.getProtocol(), new AsyncCallback<String>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(String servletContextPath) {
|
||||
webSocketURL = getWebSocketURL(servletContextPath);
|
||||
startZipping(webSocketURL, folder2Download.getItemIdentifier());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
loading.setIcon(IconType.EXCLAMATION_SIGN);
|
||||
loading.setSpin(false);
|
||||
toShow.setText("Error trying contact the server, please refresh this page and retry");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean startZipping(String webSocketURL, final String folderIdToZip) {
|
||||
if ( null == webSocket ) {
|
||||
Window.alert( "WebSocket not available!" );
|
||||
}
|
||||
|
||||
webSocket.connect( webSocketURL );
|
||||
//allow some timet to connect
|
||||
Timer t = new Timer() {
|
||||
@Override
|
||||
public void run() {
|
||||
webSocket.send(ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_PROTOCOL_DO_ZIP+":"+folderIdToZip+":"+username);
|
||||
}
|
||||
};
|
||||
t.schedule(2000);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
private String getWebSocketURL(String servletContextPath) {
|
||||
String moduleBaseURL = servletContextPath;
|
||||
return moduleBaseURL.replaceFirst( "http", "ws" ) + "/" + ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_SERVICE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen(WebSocket webSocket) { }
|
||||
|
||||
@Override
|
||||
public void onClose(WebSocket webSocket, boolean wasClean, int code, String reason) { }
|
||||
|
||||
@Override
|
||||
public void onMessage( @Nonnull final WebSocket webSocket, @Nonnull final String textData ) {
|
||||
switch (textData) {
|
||||
case ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_PROTOCOL_ZIPPING:
|
||||
toShow.setText("Compressing folder, this could take some time ...");
|
||||
break;
|
||||
case ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_PROTOCOL_ERROR_NOT_FOUND:
|
||||
toShow.setText("Could not locate the folder on server, please report this issue");
|
||||
loading.setIcon(IconType.EXCLAMATION_SIGN);
|
||||
loading.setSpin(false);
|
||||
webSocket.close();
|
||||
break;
|
||||
case ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_PROTOCOL_ERROR_DURING_COMPRESSION:
|
||||
toShow.setText("An error occurred while compressing this folder, please report this issue");
|
||||
loading.setIcon(IconType.EXCLAMATION_SIGN);
|
||||
loading.setSpin(false);
|
||||
webSocket.close();
|
||||
break;
|
||||
case ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_PROTOCOL_ERROR_NOT_A_FOLDER:
|
||||
toShow.setText("An error occurred, the folderId is not a valid folder, please report this issue");
|
||||
loading.setIcon(IconType.EXCLAMATION_SIGN);
|
||||
loading.setSpin(false);
|
||||
webSocket.close();
|
||||
break;
|
||||
case ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_PROTOCOL_ERROR_SESSION_EXPIRED:
|
||||
toShow.setText("It seems your session expired, please refresh the page and try again");
|
||||
loading.setIcon(IconType.EXCLAMATION_SIGN);
|
||||
loading.setSpin(false);
|
||||
webSocket.close();
|
||||
break;
|
||||
default:
|
||||
//the thread zipping has finished, is sending the zipped filepath on the server
|
||||
toShow.setText("Compressing folder success, starting download");
|
||||
triggerDownloadFile(textData);
|
||||
loading.setIcon(IconType.OK_SIGN);
|
||||
loading.setSpin(false);
|
||||
close.setText("Hide");
|
||||
this.setModal(false);
|
||||
webSocket.close();
|
||||
Timer t = new Timer() {
|
||||
@Override
|
||||
public void run() {
|
||||
hide();
|
||||
}
|
||||
};
|
||||
t.schedule(1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage( @Nonnull final WebSocket webSocket, @Nonnull final ArrayBuffer data ) {}
|
||||
|
||||
|
||||
@Override
|
||||
public void onError(WebSocket webSocket) {
|
||||
toShow.setText("Error contacting the server socket, please refresh this page and retry");
|
||||
}
|
||||
|
||||
private void triggerDownloadFile(String filePathOnServer) {
|
||||
try {
|
||||
new RequestBuilderWorkspaceValidateItem(RequestBuilder.GET,ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_SERVLET, "filepath="+filePathOnServer, "_self", downloadHandlerCallback);
|
||||
} catch (Exception e) {
|
||||
new MessageBoxAlert("Error", e.getMessage(), null);
|
||||
}
|
||||
}
|
||||
|
||||
public AsyncCallback<WindowOpenParameter> downloadHandlerCallback = new AsyncCallback<WindowOpenParameter>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
new MessageBoxAlert("Error", caught.getMessage(), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(WindowOpenParameter windowOpenParam) {
|
||||
String params = "?"+windowOpenParam.getParameters();
|
||||
|
||||
if(params.length()>1)
|
||||
params+="&";
|
||||
|
||||
params+=ConstantsExplorer.REDIRECTONERROR+"="+windowOpenParam.isRedirectOnError();
|
||||
|
||||
windowOpenParam.getBrowserWindow().setUrl(ConstantsExplorer.DOWNLOAD_WORKSPACE_FOLDER_SERVLET+params);
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,215 @@
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package org.gcube.portlets.user.workspace.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.gcube.common.homelibrary.home.workspace.Workspace;
|
||||
import org.gcube.portlets.user.workspace.client.ConstantsExplorer;
|
||||
import org.gcube.portlets.user.workspace.server.property.PortalUrlGroupGatewayProperty;
|
||||
import org.gcube.portlets.user.workspace.server.util.WsUtil;
|
||||
import org.gcube.portlets.user.workspace.shared.HandlerResultMessage;
|
||||
import org.gcube.portlets.user.workspace.shared.SessionExpiredException;
|
||||
|
||||
/**
|
||||
* @author M. Assante, CNR-ISTI
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class DownloadFolderServlet extends HttpServlet{
|
||||
|
||||
|
||||
protected static Logger logger = Logger.getLogger(DownloadFolderServlet.class);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void init() throws ServletException {
|
||||
super.init();
|
||||
logger.trace("Workspace DownloadFolderServlet ready.");
|
||||
}
|
||||
|
||||
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
|
||||
boolean urlRedirectOnError = req.getParameter(ConstantsExplorer.REDIRECTONERROR)==null?false:req.getParameter(ConstantsExplorer.REDIRECTONERROR).equals("true");
|
||||
|
||||
try {
|
||||
HttpSession session = req.getSession();
|
||||
if(WsUtil.isSessionExpired(session))
|
||||
throw new SessionExpiredException();
|
||||
} catch (Exception e) {
|
||||
|
||||
if (e instanceof SessionExpiredException){
|
||||
sendErrorForStatus(resp, HttpServletResponse.SC_UNAUTHORIZED +": Session expired", HttpServletResponse.SC_UNAUTHORIZED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
String fileAbsolutePath = req.getParameter("filepath");
|
||||
logger.debug("Trigger file download of " + fileAbsolutePath);
|
||||
try {
|
||||
File tmpZip = new File(fileAbsolutePath);
|
||||
logger.debug("File instanciated " + fileAbsolutePath);
|
||||
|
||||
resp.setHeader( "Content-Disposition", "attachment; filename=\"" + tmpZip.getName() + ".zip\"" );
|
||||
resp.setContentType("application/zip");
|
||||
resp = setContentLength(resp, tmpZip.length());
|
||||
OutputStream out = resp.getOutputStream();
|
||||
|
||||
FileInputStream fileTmpZip = new FileInputStream(tmpZip);
|
||||
IOUtils.copy(fileTmpZip, resp.getOutputStream());
|
||||
fileTmpZip.close();
|
||||
|
||||
out.close();
|
||||
tmpZip.deleteOnExit();
|
||||
return;
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error during folder compression "+fileAbsolutePath,e);
|
||||
handleError(urlRedirectOnError, req, resp, fileAbsolutePath, HttpServletResponse.SC_INTERNAL_SERVER_ERROR +": Error during folder compression: "+e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to manage HttpServletResponse content length also to big data
|
||||
* @param resp
|
||||
* @param length
|
||||
* @return
|
||||
*/
|
||||
protected HttpServletResponse setContentLength(HttpServletResponse resp, long length){
|
||||
try{
|
||||
if (length <= Integer.MAX_VALUE)
|
||||
resp.setContentLength((int)length);
|
||||
else
|
||||
resp.addHeader("Content-Length", Long.toString(length));
|
||||
}catch(Exception e){
|
||||
//silent
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
protected void handleError(boolean urlRedirectOnError, HttpServletRequest req, HttpServletResponse resp, String itemId, String message) throws IOException{
|
||||
|
||||
logger.warn("Handle error occurred: "+message);
|
||||
logger.trace("urlRedirectOnError is active: "+urlRedirectOnError);
|
||||
if(urlRedirectOnError){
|
||||
urlRedirect(req, resp, itemId);
|
||||
}else
|
||||
sendError(resp,message);
|
||||
|
||||
}
|
||||
|
||||
protected void sendError(HttpServletResponse response, String message) throws IOException
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||
HandlerResultMessage resultMessage = HandlerResultMessage.errorResult(message);
|
||||
logger.trace("error message: "+resultMessage);
|
||||
logger.trace("writing response...");
|
||||
StringReader sr = new StringReader(resultMessage.toString());
|
||||
IOUtils.copy(sr, response.getOutputStream());
|
||||
|
||||
logger.trace("response writed");
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
|
||||
protected void sendErrorForStatus(HttpServletResponse response, String message, int status) throws IOException
|
||||
{
|
||||
response.setStatus(status);
|
||||
HandlerResultMessage resultMessage = HandlerResultMessage.errorResult(message);
|
||||
logger.trace("error message: "+resultMessage);
|
||||
logger.trace("writing response...");
|
||||
StringReader sr = new StringReader(resultMessage.toString());
|
||||
IOUtils.copy(sr, response.getOutputStream());
|
||||
|
||||
logger.trace("response written");
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
protected void sendMessage(HttpServletResponse response, String message) throws IOException
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_ACCEPTED);
|
||||
HandlerResultMessage resultMessage = HandlerResultMessage.okResult(message);
|
||||
response.getWriter().write(resultMessage.toString());
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
protected void sendMessageResourceAvailable(HttpServletResponse response, String message) throws IOException
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_ACCEPTED);
|
||||
HandlerResultMessage resultMessage = HandlerResultMessage.okResult(message);
|
||||
response.getWriter().write(resultMessage.toString());
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
protected void sendWarnMessage(HttpServletResponse response, String message) throws IOException
|
||||
{
|
||||
response.setStatus(HttpServletResponse.SC_ACCEPTED);
|
||||
HandlerResultMessage resultMessage = HandlerResultMessage.warnResult(message);
|
||||
response.getWriter().write(resultMessage.toString());
|
||||
response.flushBuffer();
|
||||
}
|
||||
|
||||
protected void urlRedirect(HttpServletRequest req, HttpServletResponse response, String fakePath) throws IOException {
|
||||
|
||||
String requestUrl = getRequestURL(req) +fakePath;
|
||||
logger.trace("Url redirect on: "+requestUrl);
|
||||
// System.out.println("Url redirect on: "+requestUrl);
|
||||
response.sendRedirect(response.encodeRedirectURL(requestUrl));
|
||||
return;
|
||||
}
|
||||
|
||||
public static String getRequestURL(HttpServletRequest req) {
|
||||
|
||||
String scheme = req.getScheme(); // http
|
||||
String serverName = req.getServerName(); // hostname.com
|
||||
int serverPort = req.getServerPort(); // 80
|
||||
String contextPath = req.getContextPath(); // /mywebapp
|
||||
|
||||
|
||||
// Reconstruct original requesting URL
|
||||
StringBuffer url = new StringBuffer();
|
||||
url.append(scheme).append("://").append(serverName);
|
||||
|
||||
if (serverPort != 80 && serverPort != 443) {
|
||||
url.append(":").append(serverPort);
|
||||
}
|
||||
|
||||
logger.trace("server: "+url);
|
||||
logger.trace("omitted contextPath: "+contextPath);
|
||||
|
||||
|
||||
PortalUrlGroupGatewayProperty p = new PortalUrlGroupGatewayProperty();
|
||||
|
||||
int lenght = p.getPath().length();
|
||||
|
||||
String groupgatewaypath = "/";
|
||||
|
||||
if(lenght>1){
|
||||
|
||||
String lastChar = p.getPath().substring(lenght-1, lenght-1);
|
||||
|
||||
groupgatewaypath+= lastChar.compareTo("/")!=0?p.getPath()+"/":p.getPath();
|
||||
}
|
||||
|
||||
url.append(groupgatewaypath);
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue