diff --git a/ant/build.gant b/ant/build.gant
index eb96726b2..c3c91884a 100644
--- a/ant/build.gant
+++ b/ant/build.gant
@@ -1113,7 +1113,10 @@ junit = { pluginName ->
compile("${pluginName}/test/junit", "build/test/junit/classes/${pluginName}"){
ant.compilerarg(value: '-Xlint:-options')
ant.include(name: '**/*.java')
- ant.classpath{ant.pathelement(path: '${build.classes}/org.eclim')}
+ ant.classpath{
+ ant.pathelement(path: '${build.classes}/org.eclim')
+ ant.pathelement(path: '${build.classes}' + "/${pluginName}")
+ }
}
ant.path(id: 'junit'){
@@ -1130,6 +1133,7 @@ junit = { pluginName ->
ant.path(refid: 'junit')
ant.pathelement(path: "build/test/junit/classes/${pluginName}")
ant.pathelement(path: '${build.classes}/org.eclim')
+ ant.pathelement(path: '${build.classes}' + "/${pluginName}")
ant.fileset(dir: 'org.eclim/lib', includes: '*.jar', excludes: 'ant-*.jar')
}
ant.formatter(type: 'xml')
@@ -1141,6 +1145,8 @@ junit = { pluginName ->
ant.sysproperty(key: 'eclipse.home', value: '${eclipse}')
ant.sysproperty(key: 'eclim.version', value: '${eclim.version}')
ant.sysproperty(key: 'eclimd.port', value: '${nailgun.server.port}')
+ ant.sysproperty(key: 'http.server.port', value: '${http.server.port}')
+ ant.sysproperty(key: 'http.server.host', value: '${http.server.host}')
}
}
diff --git a/org.eclim.core/java/org/eclim/plugin/core/command/file/FileDeleteCommand.java b/org.eclim.core/java/org/eclim/plugin/core/command/file/FileDeleteCommand.java
new file mode 100644
index 000000000..945851e9e
--- /dev/null
+++ b/org.eclim.core/java/org/eclim/plugin/core/command/file/FileDeleteCommand.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.core.command.file;
+
+import java.io.File;
+
+import org.eclim.Services;
+import org.eclim.annotation.Command;
+import org.eclim.command.CommandException;
+import org.eclim.command.CommandException.ErrorType;
+import org.eclim.command.CommandLine;
+import org.eclim.command.Options;
+import org.eclim.logging.Logger;
+import org.eclim.plugin.core.command.AbstractCommand;
+import org.eclim.plugin.core.util.PathUtil;
+import org.eclim.plugin.core.util.PathUtilException;
+
+@Command(
+ name = "file_delete",
+ options =
+ "REQUIRED f relativeFilePath ARG," +
+ "REQUIRED p project ARG"
+)
+
+/**
+ * Command to delete a file.
+ *
+ * The relativeFilePath specifies the path relative to the
+ * project where the file/folder should be deleted.
+ *
+ * If the file is a directory, also all subdirectories will be deleted.
+ *
+ * Warning: you might have to update the project after calling this
+ * command.
+ *
+ *
+ * @author Lukas Roth
+ *
+ */
+public class FileDeleteCommand extends AbstractCommand
+{
+ private static final Logger logger = Logger.getLogger(FileDeleteCommand.class);
+
+ @Override
+ public Object execute(CommandLine commandLine)
+ throws Exception
+ {
+ String relativeFilePath = commandLine.getValue(Options.FILE_OPTION);
+ String projectName = commandLine.getValue(Options.PROJECT_OPTION);
+ return fileDelete(relativeFilePath, projectName);
+ }
+
+ public Object fileDelete(String relativeFilePath, String projectName)
+ {
+ try {
+ PathUtil.checkPathForEscaping(relativeFilePath);
+ } catch (PathUtilException e) {
+ return new CommandException(e, ErrorType.CLIENT_ERROR);
+ }
+ String absoluteFilePath;
+ try {
+ absoluteFilePath = PathUtil.getAbsolutePath(projectName, relativeFilePath);
+ } catch (PathUtilException e) {
+ return new CommandException(e, ErrorType.CLIENT_ERROR);
+ }
+ return deleteFileOnFileSystem(absoluteFilePath, relativeFilePath);
+ }
+
+ private Object deleteFileOnFileSystem(String absoluteFilePath, String filePath)
+ {
+ File file = new File(absoluteFilePath);
+ if (!file.exists()) {
+ String message = Services.getMessage("file.delete.not.found", filePath);
+ logger.error(message);
+ return new CommandException(message, ErrorType.CLIENT_ERROR);
+ }
+ if (file.isDirectory()) {
+ org.eclim.util.file.FileUtils.deleteDirectory(file);
+ return Services.getMessage("file.delete.directory.deleted", filePath);
+ } else {
+ if (file.delete()) {
+ return Services.getMessage("file.delete.success", filePath);
+ } else {
+ String message = Services.getMessage("file.delete.error", filePath);
+ logger.error(Services.getMessage("file.delete.error", filePath));
+ return new CommandException(message, ErrorType.SYSTEM_ERROR);
+ }
+ }
+ }
+}
diff --git a/org.eclim.core/java/org/eclim/plugin/core/command/file/FileListCommand.java b/org.eclim.core/java/org/eclim/plugin/core/command/file/FileListCommand.java
new file mode 100644
index 000000000..5eca6733b
--- /dev/null
+++ b/org.eclim.core/java/org/eclim/plugin/core/command/file/FileListCommand.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.core.command.file;
+
+import java.io.File;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclim.Services;
+import org.eclim.annotation.Command;
+import org.eclim.command.CommandException;
+import org.eclim.command.CommandLine;
+import org.eclim.command.Options;
+import org.eclim.logging.Logger;
+import org.eclim.plugin.core.command.AbstractCommand;
+import org.eclim.plugin.core.util.PathUtil;
+import org.eclim.plugin.core.util.PathUtilException;
+
+@Command(
+ name = "file_list",
+ options =
+ "REQUIRED f relativeFilePath ARG," +
+ "REQUIRED p project ARG," +
+ "OPTIONAL r recursiveFlag ARG"
+)
+
+/**
+ * Command to get a list of all files and folders in the folder
+ * {@code relativeFilePath} which is a relative path to the project
+ * {@code project}.
+ *
+ * Example response:
+ *
+ * myFolder/
+ * mySecFolder/
+ * myFile.txt
+ *
+ *
+ * If the {@code recursiveFlag} argument is set to true the command traverses
+ * all the folders inside the {@code relativeFilePath} recursively and returns
+ * all the folders inclusive all subfolders and subfiles.
+ *
+ * Example response with {@code recursiveFlag} set to true:
+ *
+ * myFolder/
+ * myFolder/mySubFolder/
+ * myFolder/mySubFolder/mySubFile.txt
+ * mySecFolder/
+ * myFile.txt
+ *
+ * @author Lukas Roth
+ *
+ */
+public class FileListCommand extends AbstractCommand
+{
+ private static final Logger logger = Logger.getLogger(FileListCommand.class);
+ private List result;
+
+ @Override
+ public Object execute(CommandLine commandLine)
+ throws Exception
+ {
+ String relativeFilePath = commandLine.getValue(Options.FILE_OPTION);
+ String projectName = commandLine.getValue(Options.PROJECT_OPTION);
+ String recursiveFlag = commandLine.getValue(Options.RECURSIVE_OPTION);
+ boolean recursive = Boolean.parseBoolean(recursiveFlag);
+ try {
+ return fileList(projectName, relativeFilePath, recursive);
+ } catch (FileListCommandException e) {
+ return new CommandException(e, CommandException.ErrorType.CLIENT_ERROR);
+ }
+ }
+
+ public List fileList(String projectName, String relativeFilePath,
+ boolean recursive)
+ throws FileListCommandException
+ {
+ validatePath(relativeFilePath);
+ File baseFile = getRootPath(projectName, relativeFilePath);
+ if (!baseFile.exists()) {
+ throw new FileListCommandException(
+ Services.getMessage("file.list.no.file", relativeFilePath, projectName));
+ }
+ result = new LinkedList();
+ traverseChildNodes(baseFile, null, recursive);
+ return result;
+ }
+
+ private void validatePath(String path)
+ throws FileListCommandException
+ {
+ try {
+ PathUtil.checkPathForEscaping(path);
+ } catch (PathUtilException e) {
+ throw new FileListCommandException(
+ Services.getMessage("file.path.error.illegal.path", path), e);
+ }
+ }
+
+ private void traverseChildNodes(File baseFile, String path, boolean recursive)
+ {
+ File[] childNodes = baseFile.listFiles();
+ for (File child : childNodes) {
+ String childPath = (path == null) ? child.getName() :
+ (path + "/" + child.getName());
+ if (child.isFile()) {
+ result.add(childPath);
+ } else if (child.isDirectory()) {
+ result.add(childPath + "/");
+ if (recursive) {
+ traverseChildNodes(child, childPath, recursive);
+ }
+ }
+ }
+ }
+
+ private File getRootPath(String projectName, String relativeFilePath)
+ throws FileListCommandException
+ {
+ try {
+ return new File(PathUtil.getAbsolutePath(projectName, relativeFilePath));
+ } catch (PathUtilException e) {
+ throw new FileListCommandException(
+ Services.getMessage("file.list.absolute.path.error", projectName), e);
+ }
+ }
+
+}
diff --git a/org.eclim.core/java/org/eclim/plugin/core/command/file/FileListCommandException.java b/org.eclim.core/java/org/eclim/plugin/core/command/file/FileListCommandException.java
new file mode 100644
index 000000000..7d20f5106
--- /dev/null
+++ b/org.eclim.core/java/org/eclim/plugin/core/command/file/FileListCommandException.java
@@ -0,0 +1,15 @@
+package org.eclim.plugin.core.command.file;
+
+public class FileListCommandException extends Exception
+{
+
+ public FileListCommandException(String message, Exception exception)
+ {
+ super(message, exception);
+ }
+
+ public FileListCommandException(String message)
+ {
+ super(message);
+ }
+}
diff --git a/org.eclim.core/java/org/eclim/plugin/core/command/file/FileSaveCommand.java b/org.eclim.core/java/org/eclim/plugin/core/command/file/FileSaveCommand.java
new file mode 100644
index 000000000..b818ea8b5
--- /dev/null
+++ b/org.eclim.core/java/org/eclim/plugin/core/command/file/FileSaveCommand.java
@@ -0,0 +1,134 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.core.command.file;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.eclim.Services;
+import org.eclim.annotation.Command;
+import org.eclim.command.CommandException;
+import org.eclim.command.CommandException.ErrorType;
+import org.eclim.command.CommandLine;
+import org.eclim.command.Options;
+import org.eclim.logging.Logger;
+import org.eclim.plugin.core.command.AbstractCommand;
+import org.eclim.plugin.core.util.PathUtil;
+import org.eclim.plugin.core.util.PathUtilException;
+import org.eclim.util.IOUtils;
+
+@Command(
+ name = "file_save",
+ options =
+ "REQUIRED f relativeFilePath ARG," +
+ "REQUIRED p project ARG," +
+ "REQUIRED c content ARG"
+)
+/**
+ * Command to save a file with content c.
+ *
+ * The content can either be a String or a InputStream.
+ *
+ * The relativeFilePath specifies the path relative to the
+ * project where the content should be saved.
+ *
+ * If there is no file at the specified location the file gets created
+ * (including parent directories). If there is already a file the content of the
+ * file will be overwritten.
+ *
+ * Warning: you might have to update the project after calling this
+ * command.
+ *
+ * @author Lukas Roth
+ *
+ */
+public class FileSaveCommand extends AbstractCommand
+{
+ private static final Logger logger = Logger.getLogger(FileSaveCommand.class);
+
+ @Override
+ public Object execute(CommandLine commandLine)
+ throws Exception
+ {
+ String relativeFilePath = commandLine.getValue(Options.FILE_OPTION);
+ String projectName = commandLine.getValue(Options.PROJECT_OPTION);
+ Object fileIn = commandLine.getRawValue(Options.CONTENT_OPTION);
+ InputStream fileStream;
+ if (fileIn == null) {
+ fileStream = new ByteArrayInputStream("".getBytes(StandardCharsets.UTF_8));
+ } else if (fileIn instanceof String) {
+ fileStream = new ByteArrayInputStream(
+ ((String) fileIn).getBytes(StandardCharsets.UTF_8));
+ } else if (fileIn instanceof InputStream) {
+ fileStream = (InputStream) fileIn;
+ } else {
+ String message = Services.getMessage("file.save.content.wrong.type");
+ logger.error(message);
+ return new CommandException(message, ErrorType.SYSTEM_ERROR);
+ }
+ return fileSave(relativeFilePath, projectName, fileStream);
+ }
+
+ public Object fileSave(String relativeFilePath, String projectName,
+ InputStream fileContent)
+ {
+ try {
+ PathUtil.checkPathForEscaping(relativeFilePath);
+ } catch (PathUtilException e) {
+ logger.error("File path is not valid", e);
+ return new CommandException(e, ErrorType.CLIENT_ERROR);
+ }
+ String absoluteFilePath;
+ try {
+ absoluteFilePath = PathUtil.getAbsolutePath(projectName, relativeFilePath);
+ } catch (PathUtilException e) {
+ logger.error("Could not get the absolute path", e);
+ return new CommandException(e, ErrorType.CLIENT_ERROR);
+ }
+ try {
+ writeToFileSystem(absoluteFilePath, fileContent);
+ return Services.getMessage("file.save.success", relativeFilePath);
+ } catch (IOException e) {
+ String message = Services.getMessage("file.save.error.io", relativeFilePath);
+ logger.error(message, e);
+ return new CommandException(message, ErrorType.SYSTEM_ERROR);
+ }
+ }
+
+ private void writeToFileSystem(String absoluteFilePath, InputStream fileContent)
+ throws IOException
+ {
+ File file = new File(absoluteFilePath);
+ if (file.exists()) {
+ logger.debug("Overwriting file at " + absoluteFilePath);
+ }
+ file.getParentFile().mkdirs();
+ copyInputStreamToFile(fileContent, file);
+ }
+
+ private void copyInputStreamToFile(InputStream in, File file)
+ throws IOException
+ {
+ OutputStream out = new FileOutputStream(file);
+ IOUtils.copy(in, out);
+ }
+}
diff --git a/org.eclim.core/java/org/eclim/plugin/core/messages.properties b/org.eclim.core/java/org/eclim/plugin/core/messages.properties
index 6658965f3..d93cf670c 100644
--- a/org.eclim.core/java/org/eclim/plugin/core/messages.properties
+++ b/org.eclim.core/java/org/eclim/plugin/core/messages.properties
@@ -18,6 +18,20 @@ nature.alias.not.found=No nature alias ''{0}'' found.
settings.updated=Settings updated.
setting.not.set=Required setting ''{0}'' has not been set.
+# file messages
+file.save.success=File saved at location ''{0}''.
+file.save.error.io=File could not be saved to the file system ''{0}''.
+file.save.content.wrong.type=The file content has a wrong type. The file content is not a String nor an InputStream.
+file.delete.not.found=No file at location ''{0}''.
+file.delete.directory.deleted=Folder ''{0}'' deleted.
+file.delete.success=File ''{0}'' deleted.
+file.delete.error=Could not delete the file at location ''{0}''.
+file.path.error.illegal.path=Illegal path ''{0}''.
+file.path.error.project.not.exist=Project ''{0}'' does not exist.
+file.project.update.error=Project ''{0}'' could not be updated.
+file.list.absolute.path.error=Could not get absolute path of the project ''{0}''.
+file.list.no.file=No file at ''{0}'' in project ''{1}''.
+
# project status messages.
project.created=Created project ''{0}''.
project.imported=Imported project ''{0}''.
diff --git a/org.eclim.core/java/org/eclim/plugin/core/util/PathUtil.java b/org.eclim.core/java/org/eclim/plugin/core/util/PathUtil.java
new file mode 100644
index 000000000..530637400
--- /dev/null
+++ b/org.eclim.core/java/org/eclim/plugin/core/util/PathUtil.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.core.util;
+
+import org.eclim.Services;
+import org.eclim.logging.Logger;
+import org.eclim.plugin.core.util.ProjectUtils;
+import org.eclipse.core.resources.IProject;
+
+/**
+ * Util class which helps to generate absolute paths and checks paths for not
+ * allowed content.
+ *
+ * @author Lukas Roth
+ *
+ */
+public class PathUtil
+{
+ private static final Logger logger = Logger.getLogger(PathUtil.class);
+
+ /**
+ * Checks if the path contains ".." as a substring. If so throw a
+ * PathUtilException.
+ *
+ * @param path
+ * @throws PathUtilException
+ */
+ public static void checkPathForEscaping(String path)
+ throws PathUtilException
+ {
+ if (path.contains("..")) {
+ String errMsg = Services.getMessage("file.path.error.illegal.path", path);
+ throw new PathUtilException(errMsg);
+ }
+ }
+
+ /**
+ * Returns the absolute file path generated form the projectName
+ * and the relative file path to the project filePath.
+ *
+ * Throws PathUtilException if the project can not be found.
+ *
+ * Example: If there is an exampleProject at location
+ * '/home/user/projects/exampleProject' then
+ * 'getAbsoluteFilePath(exampleProject, /path/to/my/file.txt)' returns
+ * '/home/user/projects/exampleProject/path/to/my/file.txt'
+ *
+ * @param projectName
+ * @param filePath
+ * @return absoluteFilePath Absolute file path.
+ * @throws PathUtilException
+ */
+ public static String getAbsolutePath(String projectName, String filePath)
+ throws PathUtilException
+ {
+ return getProjectPath(projectName) + "/" + filePath;
+ }
+
+ /**
+ * Returns the absolute path of the project projectName.
+ *
+ * @param projectName
+ * @return absoluteProjectPath Absolute path of the project.
+ * @throws PathUtilException
+ * Throws PathUtilException the project does not exist.
+ */
+ public static String getProjectPath(String projectName)
+ throws PathUtilException
+ {
+ IProject project;
+ try {
+ project = ProjectUtils.getProject(projectName);
+ } catch (Exception e) {
+ throw new PathUtilException(
+ Services.getMessage("file.path.error.project.not.exist", projectName), e);
+ }
+ if (project == null || project.getLocation() == null) {
+ throw new PathUtilException(
+ Services.getMessage("file.path.error.project.not.exist", projectName));
+ }
+ return project.getLocation().toOSString();
+ }
+}
diff --git a/org.eclim.core/java/org/eclim/plugin/core/util/PathUtilException.java b/org.eclim.core/java/org/eclim/plugin/core/util/PathUtilException.java
new file mode 100644
index 000000000..beb306568
--- /dev/null
+++ b/org.eclim.core/java/org/eclim/plugin/core/util/PathUtilException.java
@@ -0,0 +1,16 @@
+package org.eclim.plugin.core.util;
+
+public class PathUtilException extends Exception
+{
+ private static final long serialVersionUID = 1564613385435L;
+
+ public PathUtilException(String message)
+ {
+ super(message);
+ }
+
+ public PathUtilException(String message, Exception exception)
+ {
+ super(message, exception);
+ }
+}
diff --git a/org.eclim.core/test/eclimrc.test b/org.eclim.core/test/eclimrc.test
index 58a018c83..70cd4c87b 100644
--- a/org.eclim.core/test/eclimrc.test
+++ b/org.eclim.core/test/eclimrc.test
@@ -2,6 +2,9 @@
osgi.instance.area.default=@user.home/workspace.unittest
nailgun.server.port=9092
+http.server.enabled=true
+http.server.port=9997
+http.server.host=localhost
# increase heap space
-Xmx1g
diff --git a/org.eclim.core/test/junit/org/eclim/EclimHTTPClient.java b/org.eclim.core/test/junit/org/eclim/EclimHTTPClient.java
new file mode 100644
index 000000000..68d819a2e
--- /dev/null
+++ b/org.eclim.core/test/junit/org/eclim/EclimHTTPClient.java
@@ -0,0 +1,221 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+
+import org.eclim.http.EclimHTTPResponse;
+
+import com.google.gson.Gson;
+
+/**
+ * Client to call eclim over the HTTP Interface.
+ *
+ * @author Lukas Roth
+ *
+ */
+public class EclimHTTPClient
+{
+
+ private static final String APPLICATION_FORM = "application/x-www-form-urlencoded";
+ private static final String PORT = System.getProperty("http.server.port");
+ private static final String HOST = System.getProperty("http.server.host", "localhost");
+ private static String eclimAddress = "http://" + HOST + ":" + PORT + "/eclim/command/";
+
+ /**
+ * Calls eclim over a HTTP POST request with the parameters specified in the
+ * argument map parameters.
+ *
+ * Example parameters: parameters = {"command":"projects"}
+ *
+ * @param parameters
+ * The eclim parameters
+ * @return EcimHTTPResponse The response of eclim
+ * @throws IOException
+ */
+ public EclimHTTPResponse post(Map parameters)
+ throws IOException
+ {
+ byte[] postData = urlEncodeUTF8(parameters).getBytes(StandardCharsets.UTF_8);
+ String unparsedResponse = post(postData, getEclimAddress(), APPLICATION_FORM);
+ return (new Gson()).fromJson(unparsedResponse, EclimHTTPResponse.class);
+ }
+
+ /**
+ * Calls eclim over a HTTP POST request with the parameters specified in the
+ * argument map parameters. The file will be posted to the body
+ * while the parameters will passed as query parameters.
+ *
+ * Example parameters: InputStream file = new FileInputStream("my.jar");
+ * parameters = {"command":"jar_upload", "p":"exampleProject",
+ * "f","lib/my.jar"}
+ * post(parameters, file);
+ *
+ * @param parameters
+ * The eclim parameters.
+ * @param file
+ * The content of the inputstream inside the file
+ * parameter will be in the body of the request to eclim.
+ * @param conatentType
+ * The content type of your post request.
+ * @return EcimHTTPResponse The response of eclim
+ * @throws IOException
+ */
+ public EclimHTTPResponse post(Map parameters, InputStream file, String contentType)
+ throws IOException
+ {
+ byte[] postData = toByteArray(file);
+ String unparsedResponse = post(postData, getEclimAddress(parameters),
+ contentType);
+ return (new Gson()).fromJson(unparsedResponse, EclimHTTPResponse.class);
+ }
+
+ /**
+ * Calls eclim over a HTTP GET request with the parameters specified in the
+ * argument map parameters.
+ *
+ * Example parameters: parameters = {"command":"projects"}
+ *
+ * @param parameters
+ * @return EcimHTTPResponse The response of eclim
+ * @throws IOException
+ */
+ public EclimHTTPResponse get(Map parameters)
+ throws IOException
+ {
+ String unparsedResponse = get(getEclimAddress(parameters));
+ return (new Gson()).fromJson(unparsedResponse, EclimHTTPResponse.class);
+ }
+
+ protected String post(byte[] postData, String request, String contentType)
+ throws IOException
+ {
+ int postDataLength = postData.length;
+ URL url = new URL(request);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+ connection.setInstanceFollowRedirects(false);
+ connection.setRequestMethod("POST");
+ connection.setRequestProperty("Content-Type", contentType);
+ connection.setRequestProperty("Content-Length", Integer.toString(postDataLength));
+ connection.setUseCaches(false);
+
+ DataOutputStream wr = null;
+ try {
+ wr = new DataOutputStream(connection.getOutputStream());
+ wr.write(postData);
+ } finally {
+ wr.close();
+ }
+
+ InputStream result;
+ if (200 <= connection.getResponseCode() && connection.getResponseCode() <= 299) {
+ result = connection.getInputStream();
+ }else{
+ result = connection.getErrorStream();
+ }
+ return convertStreamToString(result);
+ }
+
+ private String get(String requestAddress)
+ throws IOException
+ {
+ URL url = new URL(requestAddress);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod("GET");
+ connection.connect();
+ InputStream result;
+ if (200 <= connection.getResponseCode() && connection.getResponseCode() <= 299) {
+ result = connection.getInputStream();
+ }else{
+ result = connection.getErrorStream();
+ }
+ return convertStreamToString(result); }
+
+ private String getEclimAddress(Map parameters)
+ {
+ return getEclimAddress() + "?" + urlEncodeUTF8(parameters);
+ }
+
+ public static String getEclimAddress()
+ {
+ return eclimAddress;
+ }
+
+ public static void setEclimAddress(String eclimAddress)
+ {
+ EclimHTTPClient.eclimAddress = eclimAddress;
+ }
+
+ // copied from
+ // http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string
+ private static String convertStreamToString(java.io.InputStream is)
+ {
+ java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
+ return s.hasNext() ? s.next() : "";
+ }
+
+ // copied from
+ // http://stackoverflow.com/questions/1264709/convert-inputstream-to-byte-array-in-java
+ private static byte[] toByteArray(InputStream inputStream)
+ throws IOException
+ {
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ int nRead;
+ byte[] data = new byte[16384];
+ while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, nRead);
+ }
+ buffer.flush();
+ return buffer.toByteArray();
+ }
+
+ // copied from
+ // http://stackoverflow.com/questions/2809877/how-to-convert-map-to-url-query-string
+ private static String urlEncodeUTF8(String s)
+ {
+ try {
+ return URLEncoder.encode(s, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ throw new UnsupportedOperationException(e);
+ }
+ }
+
+ // copied from
+ // http://stackoverflow.com/questions/2809877/how-to-convert-map-to-url-query-string
+ private static String urlEncodeUTF8(Map, ?> map)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Map.Entry, ?> entry : map.entrySet()) {
+ if (sb.length() > 0) {
+ sb.append("&");
+ }
+ sb.append(String.format("%s=%s", urlEncodeUTF8(entry.getKey().toString()),
+ urlEncodeUTF8(entry.getValue().toString())));
+ }
+ return sb.toString();
+ }
+}
diff --git a/org.eclim.core/test/junit/org/eclim/EclimTestCase.java b/org.eclim.core/test/junit/org/eclim/EclimTestCase.java
index 47c6210e0..81a4998fc 100644
--- a/org.eclim.core/test/junit/org/eclim/EclimTestCase.java
+++ b/org.eclim.core/test/junit/org/eclim/EclimTestCase.java
@@ -34,13 +34,13 @@
*/
public class EclimTestCase
{
- private HashMap modified = new HashMap();
+ private HashMap modified = new HashMap();
@After
public void resetModified()
- throws Exception
+ throws Exception
{
- for (Map.Entry entry : modified.entrySet()){
+ for (Map.Entry entry : modified.entrySet()) {
String[] parts = StringUtils.split(entry.getKey(), '|');
String project = parts[0];
String file = parts[1];
@@ -57,13 +57,15 @@ public void resetModified()
* supplied project. After the test runs, that file will be restored to it's
* original contents.
*
- * @param project The name of the project the file resides in.
- * @param file The project relative path of the file.
+ * @param project
+ * The name of the project the file resides in.
+ * @param file
+ * The project relative path of the file.
*/
protected void modifies(String project, String file)
{
String key = project + '|' + file;
- if (!modified.containsKey(key)){
+ if (!modified.containsKey(key)) {
String contents = Eclim.fileToString(project, file);
modified.put(key, contents);
}
diff --git a/org.eclim.core/test/junit/org/eclim/HTTPServerTest.java b/org.eclim.core/test/junit/org/eclim/HTTPServerTest.java
new file mode 100644
index 000000000..8afcc197d
--- /dev/null
+++ b/org.eclim.core/test/junit/org/eclim/HTTPServerTest.java
@@ -0,0 +1,197 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclim.http.EclimHTTPResponse;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests the HTTP Interface of eclim.
+ *
+ * @author Lukas Roth
+ *
+ */
+public class HTTPServerTest extends EclimHTTPClient
+{
+ private String eclimAddress = EclimHTTPClient.getEclimAddress();
+ private EclimHTTPClient eclimHTTPClient = new EclimHTTPClient();
+
+ @Test
+ public void getExpected()
+ throws IOException
+ {
+ Map projectsParams = new HashMap();
+ projectsParams.put("command", "projects");
+ EclimHTTPClient eclimHTTPClient = new EclimHTTPClient();
+ EclimHTTPResponse result = eclimHTTPClient.get(projectsParams);
+ assertProjectsExist(result);
+ }
+
+ @Test
+ public void postExpected()
+ throws IOException
+ {
+ Map projectsParams = new HashMap();
+ projectsParams.put("command", "projects");
+ EclimHTTPClient eclimHTTPClient = new EclimHTTPClient();
+ EclimHTTPResponse result = eclimHTTPClient.post(projectsParams);
+ assertProjectsExist(result);
+ }
+
+ private void assertProjectsExist(EclimHTTPResponse result)
+ {
+ Assert.assertTrue(
+ result.getResult().contains("\"name\":\"RemoteSystemsTempFiles\""));
+ Assert.assertTrue(result.getResult().contains("\"name\":\"eclim_unit_test\""));
+ Assert.assertTrue(
+ result.getResult().contains("\"name\":\"eclim_unit_test_java\""));
+ }
+
+ @Test
+ public void unsupportedMethod()
+ throws IOException
+ {
+ URL url = new URL(eclimAddress + "?command=projects");
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod("DELETE");
+ connection.connect();
+ Assert.assertEquals(405, connection.getResponseCode());
+ }
+
+ @Test
+ public void doubleArgumentKey()
+ throws IOException
+ {
+ String requestAddress = EclimHTTPClient.getEclimAddress()
+ + "?command=a&command=a";
+ URL url = new URL(requestAddress);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod("GET");
+ connection.connect();
+ InputStream result;
+ if (200 <= connection.getResponseCode()
+ && connection.getResponseCode() <= 299) {
+ result = connection.getInputStream();
+ } else {
+ result = connection.getErrorStream();
+ }
+
+ String stringResult = convertStreamToString(result);
+ Assert.assertTrue(stringResult.contains("Each argument needs an unique key."));
+ }
+
+ // copied from
+ // http://stackoverflow.com/questions/309424/read-convert-an-inputstream-to-a-string
+ private static String convertStreamToString(java.io.InputStream is)
+ {
+ java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
+ return s.hasNext() ? s.next() : "";
+ }
+
+ @Test
+ public void postFile()
+ throws IOException
+ {
+ String testFilePath = "testFile.txt";
+ File testFile = new File(
+ Eclim.getProjectPath(Eclim.TEST_PROJECT) + "/" + testFilePath);
+
+ Map saveStreamParams = new HashMap();
+ saveStreamParams.put("command", "file_save");
+ saveStreamParams.put("p", Eclim.TEST_PROJECT);
+ saveStreamParams.put("f", testFilePath);
+ InputStream file = new ByteArrayInputStream(
+ "Test Content".getBytes(StandardCharsets.UTF_8));
+ EclimHTTPClient eclimHTTPClient = new EclimHTTPClient();
+ eclimHTTPClient.post(saveStreamParams, file, "application/txt");
+
+ deleteFile(testFilePath, testFile);
+ }
+
+ private void deleteFile(String testFilePath, File testFile)
+ {
+ String deleteResult = (String) Eclim.execute(new String[] { "file_delete", "-p",
+ Eclim.TEST_PROJECT, "-f", testFilePath });
+ assertEquals("File '" + testFilePath + "' deleted.", deleteResult);
+ assertTrue("File deleted", !testFile.exists());
+ }
+
+ @Test
+ public void postFileNotAllowedParameterKey()
+ throws IOException
+ {
+ Map saveStreamParams = new HashMap();
+ saveStreamParams.put("command", "file_save");
+ saveStreamParams.put("s", "something");
+ InputStream file = new ByteArrayInputStream(
+ "Test Content".getBytes(StandardCharsets.UTF_8));
+ EclimHTTPClient eclimHTTPClient = new EclimHTTPClient();
+ EclimHTTPResponse result = eclimHTTPClient.post(saveStreamParams, file,
+ "application/txt");
+ assertCorrectStatusCode(result, 400);
+ Assert.assertTrue(
+ result.getResult().contains("Could not create a command line out of"));
+ }
+
+ @Test
+ public void postFileNotAllowedParameter()
+ throws IOException
+ {
+ Map saveStreamParams = new HashMap();
+ saveStreamParams.put("command", "file_save");
+ // The 'c' command key is not allowed in a file post
+ saveStreamParams.put("c", "something");
+ InputStream file = new ByteArrayInputStream(
+ "Test content".getBytes(StandardCharsets.UTF_8));
+ EclimHTTPClient eclimHTTPClient = new EclimHTTPClient();
+ EclimHTTPResponse result = eclimHTTPClient.post(saveStreamParams, file,
+ "application/txt");
+ assertCorrectStatusCode(result, 400);
+ Assert.assertTrue(result.getResult().contains(
+ "key is not allowed in a command which passes a file in the body of the request."));
+ }
+
+ @Test
+ public void commandException()
+ throws IOException
+ {
+ Map parameters = new HashMap();
+ parameters.put("asdfasdf", "");
+ EclimHTTPResponse response = eclimHTTPClient.get(parameters);
+ Assert.assertTrue(
+ response.getResult().contains("Could not create a command line out of"));
+ }
+
+ private void assertCorrectStatusCode(EclimHTTPResponse result, int expected)
+ {
+ Assert.assertEquals("Correct error code", expected, result.getStatusCode());
+ }
+}
diff --git a/org.eclim.core/test/junit/org/eclim/plugin/core/command/file/FileListCommandTest.java b/org.eclim.core/test/junit/org/eclim/plugin/core/command/file/FileListCommandTest.java
new file mode 100644
index 000000000..b7eb9cf36
--- /dev/null
+++ b/org.eclim.core/test/junit/org/eclim/plugin/core/command/file/FileListCommandTest.java
@@ -0,0 +1,135 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.core.command.file;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.eclim.Eclim;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * This test tests the file_list command.
+ *
+ * @author Lukas Roth
+ *
+ */
+@SuppressWarnings("unchecked")
+public class FileListCommandTest
+{
+ private static final String BASE_FOLDER = "fileListCommandTest_temp/";
+ private static final String TEST_FILE_1_PATH = BASE_FOLDER
+ + "my/example/folder/testFile1.txt";
+ private static final String TEST_FILE_2_PATH = BASE_FOLDER + "testFile2.txt";
+ private static final String TEST_CONTENT = "some content";
+ private static final String NOT_EXISTING_PROJECT = "someNotExistingProject";
+ private static final String ERROR_PROJECT_DOES_NOT_EXIST = "Could not get absolute path of the project '"
+ + NOT_EXISTING_PROJECT + "'.";
+ private static final String ILLEGAL_PATH = "asdf/../asdfw";
+ private static final String ERROR_ILLEGAL_PATH = "Illegal path '" + ILLEGAL_PATH
+ + "'.";
+ private static final String NOT_EXISTING_FILE_PATH = "egrgg97z2hg9s9gh9z20w0gu02/";
+
+ @Before
+ public void setup()
+ {
+ setupExampleFiles();
+ }
+
+ @After
+ public void cleanUp()
+ {
+ Eclim.execute(new String[] { "file_delete", "-p", Eclim.TEST_PROJECT, "-f",
+ BASE_FOLDER });
+ assertTrue("File deleted",
+ !(new File(Eclim.getProjectPath(Eclim.TEST_PROJECT) + "/" + BASE_FOLDER))
+ .exists());
+ }
+
+ private void setupExampleFiles()
+ {
+ saveExampleFile(TEST_FILE_1_PATH);
+ saveExampleFile(TEST_FILE_2_PATH);
+ }
+
+ private void saveExampleFile(String path)
+ {
+ String createResult = (String) Eclim.execute(new String[] { "file_save", "-p",
+ Eclim.TEST_PROJECT, "-f", path, "-c", TEST_CONTENT });
+ assertEquals("File saved at location '" + path + "'.", createResult);
+ }
+
+ @Test
+ public void testNormal()
+ {
+ List fileListResult = (List) Eclim.execute(
+ new String[] { "file_list", "-p", Eclim.TEST_PROJECT, "-f", BASE_FOLDER });
+ List expectedResult = new ArrayList();
+ expectedResult.add("my/");
+ expectedResult.add("testFile2.txt");
+ Assert.assertEquals(fileListResult, expectedResult);
+ }
+
+ @Test
+ public void testRecursive()
+ {
+ List fileListResult = (List) Eclim.execute(new String[] {
+ "file_list", "-p", Eclim.TEST_PROJECT, "-f", BASE_FOLDER, "-r", "true" });
+ List expectedResult = new ArrayList();
+ expectedResult.add("my/");
+ expectedResult.add("my/example/");
+ expectedResult.add("my/example/folder/");
+ expectedResult.add("my/example/folder/testFile1.txt");
+ expectedResult.add("testFile2.txt");
+ Assert.assertEquals(fileListResult, expectedResult);
+ }
+
+ @Test
+ public void notExistingProject()
+ {
+ Map createResult = (Map) Eclim
+ .execute(new String[] { "file_list", "-p", NOT_EXISTING_PROJECT, "-f",
+ NOT_EXISTING_FILE_PATH });
+ assertEquals(ERROR_PROJECT_DOES_NOT_EXIST, createResult.get("message"));
+ }
+
+ @Test
+ public void illegalPath()
+ {
+ Map createResult = (Map) Eclim.execute(
+ new String[] { "file_list", "-p", Eclim.TEST_PROJECT, "-f", ILLEGAL_PATH });
+ assertEquals(ERROR_ILLEGAL_PATH, createResult.get("message"));
+ }
+
+ @Test
+ public void nonExistingPath()
+ {
+ Map createResult = (Map) Eclim
+ .execute(new String[] { "file_list", "-p", Eclim.TEST_PROJECT, "-f",
+ NOT_EXISTING_FILE_PATH });
+ assertEquals("No file at '" + NOT_EXISTING_FILE_PATH + "' in project '"
+ + Eclim.TEST_PROJECT + "'.", createResult.get("message"));
+ }
+}
\ No newline at end of file
diff --git a/org.eclim.core/test/junit/org/eclim/plugin/core/command/file/FileSaveDeleteCommandTest.java b/org.eclim.core/test/junit/org/eclim/plugin/core/command/file/FileSaveDeleteCommandTest.java
new file mode 100644
index 000000000..ece68277f
--- /dev/null
+++ b/org.eclim.core/test/junit/org/eclim/plugin/core/command/file/FileSaveDeleteCommandTest.java
@@ -0,0 +1,168 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.core.command.file;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclim.Eclim;
+import org.eclim.EclimHTTPClient;
+import org.junit.Test;
+
+/**
+ * The class {@code FileSaveDeleteCommandTest} tests the file_save and
+ * file_delete commands of eclim.
+ *
+ * It uses the HTTP Interface of eclim to test the commands.
+ *
+ * For the file save it tests both, the stream parameter over the HTTP Interface
+ * and the string parameter.
+ *
+ * @author Lukas Roth
+ *
+ */
+public class FileSaveDeleteCommandTest
+{
+ private static final String TEST_FILE_PATH = "testFile.txt";
+ private static final File TEST_FILE = new File(
+ Eclim.getProjectPath(Eclim.TEST_PROJECT) + "/" + TEST_FILE_PATH);
+ private static final String TEST_FOLDER = "/testDir/";
+ private static final String TEST_CONTENT = "some content";
+ private static final String NOT_EXISTING_PROJECT = "someNotExistingProject";
+ private static final String WRONG_PATH = "some/path/containing/../bla/bli";
+ private static final String ERROR_PROJECT_DOES_NOT_EXIST = "Project '"
+ + NOT_EXISTING_PROJECT + "' does not exist.";
+ private static final String ERROR_ILLEGAL_PATH = "Illegal path '" + WRONG_PATH
+ + "'.";
+
+ @Test
+ public void saveString()
+ throws Exception
+ {
+ saveStringFile();
+ assertFileIsThere();
+ deleteFile();
+ }
+
+ private void saveStringFile()
+ {
+ String createResult = (String) Eclim.execute(new String[] { "file_save", "-p",
+ Eclim.TEST_PROJECT, "-f", TEST_FILE_PATH, "-c", TEST_CONTENT });
+ assertEquals("File saved at location '" + TEST_FILE_PATH + "'.", createResult);
+ }
+
+ @Test
+ public void saveStream()
+ throws IOException
+ {
+ saveStreamFile();
+ assertFileIsThere();
+ deleteFile();
+ }
+
+ private void saveStreamFile()
+ throws IOException
+ {
+ Map saveStreamParams = new HashMap();
+ saveStreamParams.put("command", "file_save");
+ saveStreamParams.put("p", Eclim.TEST_PROJECT);
+ saveStreamParams.put("f", TEST_FILE_PATH);
+ InputStream file = new ByteArrayInputStream(
+ TEST_CONTENT.getBytes(StandardCharsets.UTF_8));
+ EclimHTTPClient eclimHTTPClient = new EclimHTTPClient();
+ eclimHTTPClient.post(saveStreamParams, file, "application/txt");
+ }
+
+ private void assertFileIsThere()
+ throws IOException
+ {
+ assertTrue("File exists", TEST_FILE.exists());
+ assertEquals("Right content", readFile(TEST_FILE.getPath()), TEST_CONTENT);
+ }
+
+ private void deleteFile()
+ {
+ String deleteResult = (String) Eclim.execute(new String[] { "file_delete", "-p",
+ Eclim.TEST_PROJECT, "-f", TEST_FILE_PATH });
+ assertEquals("File '" + TEST_FILE_PATH + "' deleted.", deleteResult);
+ assertTrue("File deleted", !TEST_FILE.exists());
+ }
+
+ @Test
+ public void wrongPathSave()
+ {
+ Map createResult = (Map) Eclim
+ .execute(new String[] { "file_save", "-p", Eclim.TEST_PROJECT, "-f",
+ WRONG_PATH, "-c", TEST_CONTENT });
+ assertEquals(ERROR_ILLEGAL_PATH, createResult.get("message"));
+ }
+
+ @Test
+ public void wrongPathDelete()
+ {
+ Map createResult = (Map) Eclim.execute(
+ new String[] { "file_delete", "-p", Eclim.TEST_PROJECT, "-f", WRONG_PATH });
+ assertEquals(ERROR_ILLEGAL_PATH, createResult.get("message"));
+ }
+
+ @Test
+ public void notExistingProjectSave()
+ {
+ Map createResult = (Map) Eclim
+ .execute(new String[] { "file_save", "-p", NOT_EXISTING_PROJECT, "-f",
+ TEST_FILE_PATH, "-c", TEST_CONTENT });
+ assertEquals(ERROR_PROJECT_DOES_NOT_EXIST, createResult.get("message"));
+ }
+
+ @Test
+ public void notExistingProjectDelete()
+ {
+ Map createResult = (Map) Eclim
+ .execute(new String[] { "file_delete", "-p", NOT_EXISTING_PROJECT, "-f",
+ TEST_FILE_PATH });
+ assertEquals(ERROR_PROJECT_DOES_NOT_EXIST, createResult.get("message"));
+ }
+
+ @Test
+ public void deleteFolder()
+ {
+ File f = new File(Eclim.getProjectPath(Eclim.TEST_PROJECT) + "/" + TEST_FOLDER);
+ f.mkdirs();
+ String createResult = (String) Eclim.execute(new String[] { "file_delete", "-p",
+ Eclim.TEST_PROJECT, "-f", TEST_FOLDER });
+ assertEquals("Folder '" + TEST_FOLDER + "' deleted.", createResult);
+ assertTrue("Folder deleted", !f.exists());
+ }
+
+ private static String readFile(String path)
+ throws IOException
+ {
+ byte[] encoded = Files.readAllBytes(Paths.get(path));
+ return new String(encoded, Charset.defaultCharset());
+ }
+}
diff --git a/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathAddEntryCommand.java b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathAddEntryCommand.java
new file mode 100644
index 000000000..34e5dd5da
--- /dev/null
+++ b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathAddEntryCommand.java
@@ -0,0 +1,96 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.jdt.command.classpath;
+
+import org.eclim.Services;
+import org.eclim.annotation.Command;
+import org.eclim.command.CommandException;
+import org.eclim.command.CommandException.ErrorType;
+import org.eclim.command.CommandLine;
+import org.eclim.command.Options;
+import org.eclim.logging.Logger;
+import org.eclim.plugin.core.command.AbstractCommand;
+import org.eclim.plugin.core.util.PathUtil;
+import org.eclim.plugin.core.util.PathUtilException;
+
+@Command(
+ name = "java_classpath_add_entry",
+ options =
+ "REQUIRED p project ARG," +
+ "REQUIRED f relativeFilePath ARG"
+)
+
+/**
+ * Command to add a dependency entry to your eclipse '.classpath' file of the
+ * project.
+ *
+ * Example use case: You first upload a example.jar file to the file system over
+ * the {@code FileSaveCommand} and then add the file path to your .classpath
+ * file such that eclipse knows that there is a new dependency.
+ *
+ * Warning: you have to update the project after calling this
+ * command. You can do this over the 'project_update' command.
+ *
+ * @author Lukas Roth
+ *
+ */
+public class ClasspathAddEntryCommand extends AbstractCommand
+{
+ private static final Logger logger = Logger
+ .getLogger(ClasspathAddEntryCommand.class);
+
+ @Override
+ public Object execute(CommandLine commandLine)
+ throws Exception
+ {
+ String projectName = commandLine.getValue(Options.PROJECT_OPTION);
+ String relativeFilePath = commandLine.getValue(Options.FILE_OPTION);
+ return addDependency(projectName, relativeFilePath);
+ }
+
+ public Object addDependency(String projectName, String relativeFilePath)
+ {
+ String absoluteFilePath;
+ String projectPath;
+ try {
+ absoluteFilePath = PathUtil.getAbsolutePath(projectName, relativeFilePath);
+ projectPath = PathUtil.getProjectPath(projectName);
+ } catch (PathUtilException e) {
+ logger.error("Could not get the absolute project path", e);
+ return new CommandException(e, ErrorType.CLIENT_ERROR);
+ }
+ try {
+ callClasspathFileManipulator(absoluteFilePath,
+ projectPath + "/" + ".classpath");
+ } catch (ClasspathFileManipulatorException e) {
+ logger.error(Services.getMessage("dependency.classpath.error"), e);
+ return new CommandException(Services.getMessage("dependency.classpath.error"),
+ ErrorType.SYSTEM_ERROR);
+ }
+ return Services.getMessage("dependency.upload.jar.success", relativeFilePath);
+ }
+
+ private void callClasspathFileManipulator(String dependencyFilePath,
+ String classpathFilePath)
+ throws ClasspathFileManipulatorException
+ {
+ SimpleClasspathFileManipulator classpathFileManipulator =
+ new SimpleClasspathFileManipulator();
+ classpathFileManipulator.addJarDependency(dependencyFilePath,
+ classpathFilePath);
+ }
+}
diff --git a/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathFileManipulator.java b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathFileManipulator.java
new file mode 100644
index 000000000..2cc42bfb3
--- /dev/null
+++ b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathFileManipulator.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.jdt.command.classpath;
+
+/**
+ * The {@code ClasspathFileManipulator} Interface should be implemented by all
+ * the classes which can manipulate an eclipse classpath file such that one can
+ * add/remove a jar dependencies.
+ *
+ * @author Lukas Roth
+ *
+ */
+public interface ClasspathFileManipulator
+{
+ void addJarDependency(String dependencyFilePath, String classPathFilePath)
+ throws ClasspathFileManipulatorException;
+
+ void removeJarDependency(String dependencyFilePath, String classPathFilePath)
+ throws ClasspathFileManipulatorException;
+}
diff --git a/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathFileManipulatorException.java b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathFileManipulatorException.java
new file mode 100644
index 000000000..a768bffdb
--- /dev/null
+++ b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathFileManipulatorException.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.jdt.command.classpath;
+
+/**
+ * Exception thrown by the {@code ClasspathFileManipulator}.
+ *
+ * @author Lukas Roth
+ *
+ */
+public class ClasspathFileManipulatorException extends Exception
+{
+ private static final long serialVersionUID = -1988234200200654186L;
+
+ public ClasspathFileManipulatorException(String message)
+ {
+ super(message);
+ }
+
+ public ClasspathFileManipulatorException(String message, Exception exception)
+ {
+ super(message, exception);
+ }
+}
diff --git a/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathRemoveEntryCommand.java b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathRemoveEntryCommand.java
new file mode 100644
index 000000000..a42f1824c
--- /dev/null
+++ b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/ClasspathRemoveEntryCommand.java
@@ -0,0 +1,97 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.jdt.command.classpath;
+
+import org.eclim.Services;
+import org.eclim.annotation.Command;
+import org.eclim.command.CommandException;
+import org.eclim.command.CommandException.ErrorType;
+import org.eclim.command.CommandLine;
+import org.eclim.command.Options;
+import org.eclim.logging.Logger;
+import org.eclim.plugin.core.command.AbstractCommand;
+import org.eclim.plugin.core.util.PathUtil;
+import org.eclim.plugin.core.util.PathUtilException;
+
+@Command(
+ name = "java_classpath_remove_entry",
+ options =
+ "REQUIRED p project ARG," +
+ "REQUIRED f relativeFilePath ARG"
+)
+
+/**
+ * Command to remove a dependency entry from your eclipse '.classpath' file of
+ * the project.
+ *
+ * Example use case: You first delete a example.jar file from the file system
+ * over the {@code FileDeleteCommand} and then remove the file path from your
+ * .classpath file such that eclipse knows that the dependency is no more there.
+ *
+ * Warning: you have to update the project after calling this
+ * command. Do this over the 'project_update' command.
+ *
+ * @author Lukas Roth
+ *
+ */
+public class ClasspathRemoveEntryCommand extends AbstractCommand
+{
+ private static final Logger logger = Logger
+ .getLogger(ClasspathRemoveEntryCommand.class);
+
+ @Override
+ public Object execute(CommandLine commandLine)
+ throws Exception
+ {
+ String projectName = commandLine.getValue(Options.PROJECT_OPTION);
+ String relativeFilePath = commandLine.getValue(Options.FILE_OPTION);
+ return removeDependency(projectName, relativeFilePath);
+ }
+
+ public Object removeDependency(String projectName,
+ String relativeFilePath)
+ {
+ String absoluteFilePath;
+ String projectPath;
+ try {
+ absoluteFilePath = PathUtil.getAbsolutePath(projectName, relativeFilePath);
+ projectPath = PathUtil.getProjectPath(projectName);
+ } catch (PathUtilException e) {
+ return new CommandException(e, ErrorType.CLIENT_ERROR);
+ }
+ try {
+ callClasspathFileManipulator(absoluteFilePath,
+ projectPath + "/" + ".classpath");
+ } catch (ClasspathFileManipulatorException e) {
+ logger.error(Services.getMessage("dependency.classpath.error"), e);
+ return new CommandException(
+ Services.getMessage("dependency.classpath.error"),
+ ErrorType.SYSTEM_ERROR);
+ }
+ return Services.getMessage("dependency.remove.jar.success", relativeFilePath);
+ }
+
+ private void callClasspathFileManipulator(String dependencyFilePath,
+ String classpathFilePath)
+ throws ClasspathFileManipulatorException
+ {
+ SimpleClasspathFileManipulator classpathFileManipulator
+ = new SimpleClasspathFileManipulator();
+ classpathFileManipulator.removeJarDependency(dependencyFilePath,
+ classpathFilePath);
+ }
+}
diff --git a/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/SimpleClasspathFileManipulator.java b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/SimpleClasspathFileManipulator.java
new file mode 100644
index 000000000..ac5f68a29
--- /dev/null
+++ b/org.eclim.jdt/java/org/eclim/plugin/jdt/command/classpath/SimpleClasspathFileManipulator.java
@@ -0,0 +1,189 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.jdt.command.classpath;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.eclim.logging.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ *
+ * The {@code SimpleClasspathFileManipulator} manipulates the .classpath file of an
+ * eclipse project.
+ *
+ * It allows a user to
+ * - add a dependency file
+ * - remove a dependency file
+ *
+ * @author Lukas Roth
+ *
+ */
+public class SimpleClasspathFileManipulator implements ClasspathFileManipulator
+{
+ private final Logger logger = Logger
+ .getLogger(SimpleClasspathFileManipulator.class);
+ private static final String ERROR_LOG_ENTRY =
+ "Error while manipulating the eclipse classpath";
+ private static final String CLASS_PATH_NODE_NAME = "classpath";
+ private static final String KIND_ATTRIBUTE = "kind";
+ private static final String KIND_ATTRIBUTE_LIB = "lib";
+ private static final String PATH_ATTRIBUTE = "path";
+ private static final String ELEMENT_NAME_CLASS_PATH_ENTRY = "classpathentry";
+
+ /**
+ * Adds a jar dependency entry for the jar at position
+ * dependencyFilePath to the .classpath file (which is at path
+ * classPathFilePath). After this you need to ensure that eclipse
+ * refreshes the dependencies!
+ */
+ @Override
+ public void addJarDependency(String dependencyFilePath, String classPathFilePath)
+ throws ClasspathFileManipulatorException
+ {
+ Document doc = parseXML(classPathFilePath);
+ Node classPathNode = getClassPathNode(doc, CLASS_PATH_NODE_NAME);
+
+ List foundNodes = findChildNodes(dependencyFilePath, classPathNode);
+ if (!foundNodes.isEmpty()) {
+ logger.debug("There is already an entry '" + dependencyFilePath +
+ "' --> it will not be added a second time.");
+ return;
+ }
+ Element classPathEntry = doc.createElement(ELEMENT_NAME_CLASS_PATH_ENTRY);
+ classPathEntry.setAttribute(KIND_ATTRIBUTE, KIND_ATTRIBUTE_LIB);
+ classPathEntry.setAttribute(PATH_ATTRIBUTE, dependencyFilePath);
+ classPathNode.appendChild(classPathEntry);
+
+ writeXmlBackToFile(doc, classPathFilePath);
+ }
+
+ /**
+ * Removes all jar dependency entries for the jar at position
+ * dependencyFilePath from the .classpath file (which is at path
+ * classPathFilePath). After this you need to ensure that eclipse
+ * refreshes the dependencies!
+ */
+ @Override
+ public void removeJarDependency(String dependencyFilePath,
+ String classPathFilePath)
+ throws ClasspathFileManipulatorException
+ {
+ Document document = parseXML(classPathFilePath);
+ Node classPathNode = getClassPathNode(document, CLASS_PATH_NODE_NAME);
+ List childesToRemove = findChildNodes(dependencyFilePath, classPathNode);
+ if (childesToRemove.size() != 1) {
+ logger.debug("There were " + childesToRemove.size() +
+ " nodes which all fit to the dependency entry which gets removed now");
+ }
+ removeChildNodes(classPathNode, childesToRemove);
+ writeXmlBackToFile(document, classPathFilePath);
+ }
+
+ private Node getClassPathNode(Document doc, String tagName)
+ throws ClasspathFileManipulatorException
+ {
+ if (doc != null) {
+ NodeList temp = doc.getElementsByTagName(tagName);
+ if (temp != null) {
+ Node retNode = temp.item(0);
+ if (retNode != null) {
+ return retNode;
+ }
+ }
+ }
+ throw new ClasspathFileManipulatorException(
+ "Could not find the node: " + tagName);
+ }
+
+ private List findChildNodes(String dependencyFilePath, Node classPathNode)
+ {
+ NodeList childes = classPathNode.getChildNodes();
+ List childesToRemove = new ArrayList();
+ for (int i = 0; i < childes.getLength(); i++) {
+ Node child = childes.item(i);
+ if (child.getNodeName().equals(ELEMENT_NAME_CLASS_PATH_ENTRY) &&
+ child.hasAttributes())
+ {
+ NamedNodeMap attributeMap = child.getAttributes();
+ Node kind = attributeMap.getNamedItem(KIND_ATTRIBUTE);
+ Node path = attributeMap.getNamedItem(PATH_ATTRIBUTE);
+ if (kind != null && path != null &&
+ kind.getNodeValue().equals(KIND_ATTRIBUTE_LIB) &&
+ path.getNodeValue().equals(dependencyFilePath))
+ {
+ childesToRemove.add(child);
+ }
+ }
+ }
+ return childesToRemove;
+ }
+
+ private void removeChildNodes(Node classpath, List childesToRemove)
+ {
+ for (Node child : childesToRemove) {
+ classpath.removeChild(child);
+ }
+ }
+
+ private void writeXmlBackToFile(Document document, String filePath)
+ throws ClasspathFileManipulatorException
+ {
+ try {
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer;
+ transformer = transformerFactory.newTransformer();
+
+ DOMSource source = new DOMSource(document);
+ StreamResult result = new StreamResult(new File(filePath));
+ transformer.transform(source, result);
+ } catch (Exception e) {
+ throw new ClasspathFileManipulatorException(ERROR_LOG_ENTRY, e);
+ }
+ }
+
+ private Document parseXML(String document)
+ throws ClasspathFileManipulatorException
+ {
+ try {
+ logger.debug("Parsing XML file: " + document);
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(new File(document));
+ if (doc != null) {
+ return doc;
+ }
+ throw new ClasspathFileManipulatorException(
+ "Error parsing XML: doc is null after parsing");
+ } catch (Exception e) {
+ throw new ClasspathFileManipulatorException(ERROR_LOG_ENTRY, e);
+ }
+ }
+}
diff --git a/org.eclim.jdt/java/org/eclim/plugin/jdt/messages.properties b/org.eclim.jdt/java/org/eclim/plugin/jdt/messages.properties
index 5b45dac21..8cc10fe0b 100644
--- a/org.eclim.jdt/java/org/eclim/plugin/jdt/messages.properties
+++ b/org.eclim.jdt/java/org/eclim/plugin/jdt/messages.properties
@@ -154,3 +154,8 @@ org.eclipse.jdt.core.codeComplete.deprecationCheck=\
org.eclipse.jdt.core.codeComplete.visibilityCheck=\
Filter out inaccessible members (private, etc) during code completion\n\
(enabled or disabled).
+
+# Command dependency
+dependency.classpath.error=Could not manipulate the eclipse classpath file.
+dependency.upload.jar.success=Added the library ''{0}'' to the classpath file of eclipse.
+dependency.remove.jar.success=Removed the library ''{0}'' from the classpath file of eclipse.
\ No newline at end of file
diff --git a/org.eclim.jdt/test/junit/org/eclim/plugin/jdt/command/classpath/ClasspathAddRemoveEntryCommandTest.java b/org.eclim.jdt/test/junit/org/eclim/plugin/jdt/command/classpath/ClasspathAddRemoveEntryCommandTest.java
new file mode 100644
index 000000000..c1f6e485f
--- /dev/null
+++ b/org.eclim.jdt/test/junit/org/eclim/plugin/jdt/command/classpath/ClasspathAddRemoveEntryCommandTest.java
@@ -0,0 +1,212 @@
+/**
+ * Copyright (C) 2005 - 2016 Eric Van Dewoestine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package org.eclim.plugin.jdt.command.classpath;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclim.Eclim;
+import org.eclim.EclimHTTPClient;
+import org.eclim.http.EclimHTTPResponse;
+import org.eclim.plugin.jdt.Jdt;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.gson.JsonParser;
+
+import junit.framework.Assert;
+
+/**
+ * In this test we upload a dependency jar, manipulate the classpat file such that
+ * eclipse knows we uploaded a jar and then remove the dependency jar again.
+ *
+ * Test idea: Upload and remove a GSON Library and check that - before the
+ * upload Gson is not there - after the upload Gson is there - after the remove
+ * Gson is not there again
+ *
+ * We check if the Gson library is correctly uploaded with the help of the
+ * completion command. --> if we get a completion for GsonB (-> GsonBuilder) we
+ * know that the dependency was added correctly.
+ *
+ * @author Lukas Roth
+ */
+public class ClasspathAddRemoveEntryCommandTest
+{
+ private static final String TEST_FILE = "src/org/eclim/test/exampleClass.java";
+ private static final String TEST_FILE_CONTENT = "package org.eclim.test;\nclass A{\nvoid f(){\nGsonB}\n}";
+ private static final int TEST_FILE_OFFSET = 48;
+ private static final String PATH_TO_DEPENDENCY = "lib/gson-1.7.1.jar";
+ private static final String DEPENDENCY_LOCATION_ON_FILE_SYSTEM = "org.eclim/lib/gson-1.7.1.jar";
+ private EclimHTTPClient eclimHTTPClient = new EclimHTTPClient();
+
+ @Before
+ public void setupTestFile()
+ throws IOException
+ {
+ assertTrue("Java project doesn't exist.",
+ Eclim.projectExists(Jdt.TEST_PROJECT));
+ setupCompletionFile();
+ }
+
+ @After
+ public void deleteTestFile()
+ throws IOException
+ {
+ Map parameters = new HashMap();
+ parameters.put("command", "file_delete");
+ parameters.put("p", Jdt.TEST_PROJECT);
+ parameters.put("f", TEST_FILE);
+ eclimHTTPClient.get(parameters);
+
+ updateProject();
+ }
+
+ private void setupCompletionFile()
+ throws IOException
+ {
+ createTestFile();
+ updateProject();
+ }
+
+ private void updateProject()
+ throws IOException
+ {
+ Map parameters = new HashMap();
+ parameters.put("command", "project_update");
+ parameters.put("p", Jdt.TEST_PROJECT);
+ eclimHTTPClient.get(parameters);
+ }
+
+ private void createTestFile()
+ throws IOException
+ {
+ Map parameters = new HashMap();
+ parameters.put("command", "file_save");
+ parameters.put("p", Jdt.TEST_PROJECT);
+ parameters.put("f", TEST_FILE);
+ parameters.put("c", TEST_FILE_CONTENT);
+ eclimHTTPClient.get(parameters);
+ }
+
+ @Test
+ public void jarUploadRemoveTest()
+ throws IOException
+ {
+ assertLibraryNotAvailable();
+ uploadJar();
+ updateProject();
+ assertLibraryAvailable();
+ removeJar();
+ updateProject();
+ assertLibraryNotAvailable();
+ }
+
+ private void removeJar()
+ throws IOException
+ {
+ deleteJar();
+ removeFromClasspath();
+ }
+
+ private void removeFromClasspath()
+ throws IOException
+ {
+ Map uploadJarParams = new HashMap();
+ uploadJarParams.put("command", "remove_dependency");
+ uploadJarParams.put("p", Jdt.TEST_PROJECT);
+ uploadJarParams.put("f", PATH_TO_DEPENDENCY);
+ eclimHTTPClient.post(uploadJarParams);
+ }
+
+ private void deleteJar()
+ throws IOException
+ {
+ Map saveJarParams = new HashMap();
+ saveJarParams.put("command", "file_delete");
+ saveJarParams.put("p", Jdt.TEST_PROJECT);
+ saveJarParams.put("f", PATH_TO_DEPENDENCY);
+ eclimHTTPClient.post(saveJarParams);
+ }
+
+ private void uploadJar()
+ throws IOException
+ {
+ saveJar();
+ addToClasspath();
+ }
+
+ private void addToClasspath()
+ throws IOException
+ {
+ Map uploadJarParams = new HashMap();
+ uploadJarParams.put("command", "java_classpath_add_entry");
+ uploadJarParams.put("p", Jdt.TEST_PROJECT);
+ uploadJarParams.put("f", PATH_TO_DEPENDENCY);
+ eclimHTTPClient.post(uploadJarParams);
+ }
+
+ private void saveJar()
+ throws IOException
+ {
+ Map saveJarParams = new HashMap();
+ saveJarParams.put("command", "file_save");
+ saveJarParams.put("p", Jdt.TEST_PROJECT);
+ saveJarParams.put("f", PATH_TO_DEPENDENCY);
+ InputStream file = new FileInputStream(DEPENDENCY_LOCATION_ON_FILE_SYSTEM);
+ eclimHTTPClient.post(saveJarParams, file, "application/jar");
+ }
+
+ private void assertLibraryNotAvailable()
+ throws IOException
+ {
+ List