Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UD-806 Allow to handle drag and drop local files to the Che instance #75

Merged
merged 1 commit into from
Oct 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import com.google.inject.servlet.ServletModule;

import org.eclipse.che.admin.upload.UploadServlet;
import org.eclipse.che.inject.DynaModule;
import org.everrest.guice.servlet.GuiceEverrestServlet;

Expand All @@ -23,6 +24,7 @@
public class ApiServletModule extends ServletModule {
@Override
protected void configureServlets() {
serve("/upload").with(UploadServlet.class);
serve("/*", new String[0]).with(GuiceEverrestServlet.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.admin.deploy;

/**
* Constants that might be defined in che.properties file.
* @author Florent Benoit
*/
public class Constants {

/**
* Constant used to describe the path to the servlet upload directory when uploading files.
*/
public static final String CHE_SERVLET_UPLOAD_DIRECTORY = "che.servlet.upload.directory";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.admin.upload;

import org.eclipse.che.admin.deploy.Constants;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Upload servlet allowing to upload files to the server. Request should contain a part named 'uploadedFile' for the file.
* @author Florent Benoit
*/
@MultipartConfig
@Singleton
public class UploadServlet extends HttpServlet {

/**
* Serializable class;
*/
private static final long serialVersionUID = -687991492884005033L;

/**
* Folder used to store uploaded files.
*/
private String uploadFolder;

/**
* Create a new upload folder.
* @param uploadFolder the path to store the uploaded files.
*/
@Inject
public UploadServlet(@Named(Constants.CHE_SERVLET_UPLOAD_DIRECTORY) String uploadFolder) {
this.uploadFolder = uploadFolder;
}

/**
* Handle the POST request only by allowing to upload files.
* @param request the request with a part named 'uploadedFile'
* @param response empty if file is uploaded
* @throws ServletException if there is a problem while uploading
* @throws IOException if there is a problem while uploading
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getParts().stream().forEach((filePart -> {
try {
String fileName = filePart.getSubmittedFileName();
InputStream inputStream = filePart.getInputStream();
Path path = Paths.get(uploadFolder).resolve(fileName);
Files.createDirectories(path.getParent());
Files.copy(inputStream, path);

} catch (IOException e) {
throw new RuntimeException("Unable to upload files", e);
}
}));
}


}
14 changes: 14 additions & 0 deletions che-admin-war/src/main/webapp/META-INF/context.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2012-2015 Codenvy, S.A.
All rights reserved. This program and the accompanying materials
are made available under the terms of the Eclipse Public License v1.0
which accompanies this distribution, and is available at
http://www.eclipse.org/legal/epl-v10.html

Contributors:
Codenvy, S.A. - initial API and implementation

-->
<Context allowCasualMultipartParsing="true" />
13 changes: 13 additions & 0 deletions che-admin-war/src/main/webapp/WEB-INF/classes/che/che.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#
# Copyright (c) 2012-2015 Codenvy, S.A.
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Eclipse Public License v1.0
# which accompanies this distribution, and is available at
# http://www.eclipse.org/legal/epl-v10.html
#
# Contributors:
# Codenvy, S.A. - initial API and implementation
#

# Directory used to upload files
che.servlet.upload.directory=${catalina.base}/temp/upload
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,41 @@ public class CustomExceptionMapper implements ExceptionMapper<PluginException> {
@Override
public Response toResponse(PluginException exception) {

// try to get the inner cause
Throwable innerException = getInnerCause(exception);
String message = exception.getMessage() + ": " + innerException.getClass().getSimpleName() + " " + innerException.getMessage();

if (exception instanceof PluginManagerNotFoundException || exception instanceof PluginInstallerNotFoundException || exception instanceof PluginResolverNotFoundException) {
return Response.status(Response.Status.NOT_FOUND)
.entity(DtoFactory.getInstance()
.toJson(DtoFactory.getInstance().createDto(ServiceError.class)
.withMessage(exception.getMessage())))
.withMessage(message)))
.type(MediaType.APPLICATION_JSON)
.build();
} else if (exception instanceof PluginManagerAlreadyExistsException) {
return Response.status(Response.Status.CONFLICT)
.entity(DtoFactory.getInstance()
.toJson(DtoFactory.getInstance().createDto(ServiceError.class)
.withMessage(exception.getMessage())))
.withMessage(message)))
.type(MediaType.APPLICATION_JSON)
.build();
}
return Response.serverError()
.entity(DtoFactory.getInstance().createDto(ServiceError.class).withMessage(exception.getMessage()))
.entity(DtoFactory.getInstance().createDto(ServiceError.class).withMessage(message))
.type(MediaType.APPLICATION_JSON)
.build();
}

/**
* Gets the inner cause or return current exception if there is no root cause
* @param throwable iterate over this throwable
* @return current or the deepest inner cause
*/
protected Throwable getInnerCause(Throwable throwable) {
if (throwable.getCause() == null) {
return throwable;
}
return getInnerCause(throwable.getCause());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.eclipse.che.plugin.internal.installer.PluginInstallerImpl;
import org.eclipse.che.plugin.internal.manager.PluginManagerImpl;
import org.eclipse.che.plugin.internal.repository.PluginRepositoryImpl;
import org.eclipse.che.plugin.internal.resolver.LocalUploadResolver;
import org.eclipse.che.plugin.internal.resolver.MavenResolver;

/**
Expand All @@ -44,6 +45,8 @@ protected void configure() {

Multibinder<PluginResolver> pluginDownloaderMultibinder = Multibinder.newSetBinder(binder(), PluginResolver.class);
pluginDownloaderMultibinder.addBinding().to(MavenResolver.class);
pluginDownloaderMultibinder.addBinding().to(LocalUploadResolver.class);


}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public interface PluginManager {
*/
List<IPlugin> listPlugins() throws PluginRepositoryException;

IPlugin addPlugin(String mavenPluginRef) throws PluginManagerException, PluginResolverNotFoundException;
IPlugin addPlugin(String mavenPluginRef) throws PluginManagerException, PluginResolverNotFoundException, PluginResolverNotFoundException;


IPlugin getPluginDetails(String pluginName) throws PluginManagerNotFoundException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,26 @@
package org.eclipse.che.plugin.internal.api;

/**
* Exception if plugin is not found during the resolution of the url
* @author Florent Benoit
*/
public class PluginResolverNotFoundException extends PluginException {

public PluginResolverNotFoundException(String s, Throwable e) {
super(s, e);
/**
* Create exception with a given message.
* @param message the error message
*/
public PluginResolverNotFoundException(String message) {
super(message);
}

/**
* Create exception with a given message and a root cause.
* @param message the error message
* @param e the root cause
*/
public PluginResolverNotFoundException(String message, Throwable e) {
super(message, e);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ public void onFailure(Throwable throwable) {
}


public IPlugin addPlugin(final String pluginRef) throws PluginResolverNotFoundException, PluginManagerException {
public IPlugin addPlugin(final String pluginRef) throws PluginResolverNotFoundException, PluginManagerException, PluginResolverNotFoundException {


// resolve plugin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ public Path add(Path localPlugin) throws PluginRepositoryException {
try {
Files.move(localPlugin, destPath);
} catch (IOException e) {
throw new PluginRepositoryException("Unable to move plugin to staged directory");
throw new PluginRepositoryException("Unable to move plugin to staged directory", e);
}

return destPath;
Expand All @@ -249,7 +249,7 @@ public Path stageInstall(Path availablePlugin) throws PluginRepositoryException
try {
Files.move(availablePlugin, newLocation);
} catch (IOException e) {
throw new PluginRepositoryException("Unable to move plugin to staged directory");
throw new PluginRepositoryException("Unable to move plugin to staged directory", e);
}


Expand All @@ -273,7 +273,7 @@ public Path undoStageInstall(Path stagedInstallPlugin) throws PluginRepositoryEx
try {
Files.move(stagedInstallPlugin, newLocation);
} catch (IOException e) {
throw new PluginRepositoryException("Unable to move plugin to staged directory");
throw new PluginRepositoryException("Unable to move plugin to staged directory", e);
}


Expand All @@ -296,7 +296,7 @@ public Path undoStageUninstall(Path stagedUninstallPlugin) throws PluginReposito
try {
Files.move(stagedUninstallPlugin, newLocation);
} catch (IOException e) {
throw new PluginRepositoryException("Unable to move plugin to staged directory");
throw new PluginRepositoryException("Unable to move plugin to staged directory", e);
}


Expand All @@ -320,7 +320,7 @@ public Path stageUninstall(Path installedPlugin) throws PluginRepositoryExceptio
try {
Files.move(installedPlugin, newLocation);
} catch (IOException e) {
throw new PluginRepositoryException("Unable to move plugin to available directory");
throw new PluginRepositoryException("Unable to move plugin to available directory", e);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*******************************************************************************
* Copyright (c) 2012-2015 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.internal.resolver;

import org.eclipse.che.plugin.internal.api.PluginResolver;
import org.eclipse.che.plugin.internal.api.PluginResolverException;
import org.eclipse.che.plugin.internal.api.PluginResolverNotFoundException;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.validation.constraints.NotNull;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
* LocalUpload Resolve will resolve jars that have been uploaded to the che instance.
* @author Florent Benoit
*/
@Singleton
public class LocalUploadResolver implements PluginResolver {

/**
* Constant used to describe the path to the servlet upload directory when uploading files.
*/
public static final String CHE_SERVLET_UPLOAD_DIRECTORY = "che.servlet.upload.directory";

/**
* Folder used to store uploaded files.
*/
private Path uploadFolder;

/**
* Create a new resolver using the local upload folder.
* @param uploadFolder the path to store the uploaded files.
*/
@Inject
public LocalUploadResolver(@Named(CHE_SERVLET_UPLOAD_DIRECTORY) String uploadFolder) {
this.uploadFolder = Paths.get(uploadFolder);
}

/**
* Resolve provided url
* @param pluginRef reference of the plugin
* @return
* @throws PluginResolverException
*/
public Path download(@NotNull final String pluginRef) throws PluginResolverException, PluginResolverNotFoundException {
String path = pluginRef;
if (path.startsWith(getProtocol())) {
path = path.substring(getProtocol().length());
}

// resolve the file from the upload folder
Path uploadedFile = this.uploadFolder.resolve(path);

if (Files.notExists(uploadedFile)) {
throw new PluginResolverNotFoundException(String.format("The provided file %s was not found as uploaded file",
uploadedFile.toString()));
}
return uploadedFile;

}

@Override
public String getProtocol() {
return "upload:";
}


}