blob: c8b34c392f5fcbb4cd75751cf1356c051d74d098 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.eclipse.actions;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.hadoop.eclipse.ImageLibrary;
import org.apache.hadoop.eclipse.dfs.DFSActions;
import org.apache.hadoop.eclipse.dfs.DFSFile;
import org.apache.hadoop.eclipse.dfs.DFSFolder;
import org.apache.hadoop.eclipse.dfs.DFSLocation;
import org.apache.hadoop.eclipse.dfs.DFSLocationsRoot;
import org.apache.hadoop.eclipse.dfs.DFSPath;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IPersistableElement;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
/**
* Actual implementation of DFS actions
*/
public class DFSActionImpl implements IObjectActionDelegate {
private ISelection selection;
private IWorkbenchPart targetPart;
/* @inheritDoc */
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
this.targetPart = targetPart;
}
/* @inheritDoc */
public void run(IAction action) {
// Ignore non structured selections
if (!(this.selection instanceof IStructuredSelection))
return;
// operate on the DFS asynchronously to prevent blocking the main UI
final IStructuredSelection ss = (IStructuredSelection) selection;
final String actionId = action.getActionDefinitionId();
Display.getDefault().asyncExec(new Runnable() {
public void run() {
try {
switch (DFSActions.getById(actionId)) {
case DELETE: {
delete(ss);
break;
}
case OPEN: {
open(ss);
break;
}
case MKDIR: {
mkdir(ss);
break;
}
case UPLOAD_FILES: {
uploadFilesToDFS(ss);
break;
}
case UPLOAD_DIR: {
uploadDirectoryToDFS(ss);
break;
}
case REFRESH: {
refresh(ss);
break;
}
case DOWNLOAD: {
downloadFromDFS(ss);
break;
}
case RECONNECT: {
reconnect(ss);
break;
}
case DISCONNECT: {
disconnect(ss);
break;
}
default: {
System.err.printf("Unhandled DFS Action: " + actionId);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
MessageDialog.openError(Display.getDefault().getActiveShell(),
"DFS Action error",
"An error occurred while performing DFS operation: "
+ e.getMessage());
}
}
});
}
/**
* Create a new sub-folder into an existing directory
*
* @param selection
*/
private void mkdir(IStructuredSelection selection) {
List<DFSFolder> folders = filterSelection(DFSFolder.class, selection);
if (folders.size() >= 1) {
DFSFolder folder = folders.get(0);
InputDialog dialog =
new InputDialog(Display.getCurrent().getActiveShell(),
"Create subfolder", "Enter the name of the subfolder", "",
null);
if (dialog.open() == InputDialog.OK)
folder.mkdir(dialog.getValue());
}
}
/**
* Implement the import action (upload files from the current machine to
* HDFS)
*
* @param object
* @throws SftpException
* @throws JSchException
* @throws InvocationTargetException
* @throws InterruptedException
*/
private void uploadFilesToDFS(IStructuredSelection selection)
throws InvocationTargetException, InterruptedException {
// Ask the user which files to upload
FileDialog dialog =
new FileDialog(Display.getCurrent().getActiveShell(), SWT.OPEN
| SWT.MULTI);
dialog.setText("Select the local files to upload");
dialog.open();
List<File> files = new ArrayList<File>();
for (String fname : dialog.getFileNames())
files.add(new File(dialog.getFilterPath() + File.separator + fname));
// TODO enable upload command only when selection is exactly one folder
List<DFSFolder> folders = filterSelection(DFSFolder.class, selection);
if (folders.size() >= 1)
uploadToDFS(folders.get(0), files);
}
/**
* Implement the import action (upload directory from the current machine
* to HDFS)
*
* @param object
* @throws SftpException
* @throws JSchException
* @throws InvocationTargetException
* @throws InterruptedException
*/
private void uploadDirectoryToDFS(IStructuredSelection selection)
throws InvocationTargetException, InterruptedException {
// Ask the user which local directory to upload
DirectoryDialog dialog =
new DirectoryDialog(Display.getCurrent().getActiveShell(), SWT.OPEN
| SWT.MULTI);
dialog.setText("Select the local file or directory to upload");
String dirName = dialog.open();
final File dir = new File(dirName);
List<File> files = new ArrayList<File>();
files.add(dir);
// TODO enable upload command only when selection is exactly one folder
final List<DFSFolder> folders =
filterSelection(DFSFolder.class, selection);
if (folders.size() >= 1)
uploadToDFS(folders.get(0), files);
}
private void uploadToDFS(final DFSFolder folder, final List<File> files)
throws InvocationTargetException, InterruptedException {
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(
new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws InvocationTargetException {
int work = 0;
for (File file : files)
work += computeUploadWork(file);
monitor.beginTask("Uploading files to distributed file system",
work);
for (File file : files) {
try {
folder.upload(monitor, file);
} catch (IOException ioe) {
ioe.printStackTrace();
MessageDialog.openError(null,
"Upload files to distributed file system",
"Upload failed.\n" + ioe);
}
}
monitor.done();
// Update the UI
folder.doRefresh();
}
});
}
private void reconnect(IStructuredSelection selection) {
for (DFSLocation location : filterSelection(DFSLocation.class, selection))
location.reconnect();
}
private void disconnect(IStructuredSelection selection) {
if (selection.size() != 1)
return;
Object first = selection.getFirstElement();
if (!(first instanceof DFSLocationsRoot))
return;
DFSLocationsRoot root = (DFSLocationsRoot) first;
root.disconnect();
root.refresh();
}
/**
* Implements the Download action from HDFS to the current machine
*
* @param object
* @throws SftpException
* @throws JSchException
* @throws InterruptedException
* @throws InvocationTargetException
*/
private void downloadFromDFS(IStructuredSelection selection)
throws InvocationTargetException, InterruptedException {
// Ask the user where to put the downloaded files
DirectoryDialog dialog =
new DirectoryDialog(Display.getCurrent().getActiveShell());
dialog.setText("Copy to local directory");
dialog.setMessage("Copy the selected files and directories from the "
+ "distributed filesystem to a local directory");
String directory = dialog.open();
if (directory == null)
return;
final File dir = new File(directory);
if (!dir.exists())
dir.mkdirs();
if (!dir.isDirectory()) {
MessageDialog.openError(null, "Download to local file system",
"Invalid directory location: \"" + dir + "\"");
return;
}
final List<DFSPath> paths = filterSelection(DFSPath.class, selection);
PlatformUI.getWorkbench().getProgressService().busyCursorWhile(
new IRunnableWithProgress() {
public void run(IProgressMonitor monitor)
throws InvocationTargetException {
int work = 0;
for (DFSPath path : paths)
work += path.computeDownloadWork();
monitor
.beginTask("Downloading files to local file system", work);
for (DFSPath path : paths) {
if (monitor.isCanceled())
return;
try {
path.downloadToLocalDirectory(monitor, dir);
} catch (Exception e) {
// nothing we want to do here
e.printStackTrace();
}
}
monitor.done();
}
});
}
/**
* Open the selected DfsPath in the editor window
*
* @param selection
* @throws JSchException
* @throws IOException
* @throws PartInitException
* @throws InvocationTargetException
* @throws InterruptedException
*/
private void open(IStructuredSelection selection) throws IOException,
PartInitException, InvocationTargetException, InterruptedException {
for (DFSFile file : filterSelection(DFSFile.class, selection)) {
IStorageEditorInput editorInput = new DFSFileEditorInput(file);
targetPart.getSite().getWorkbenchWindow().getActivePage().openEditor(
editorInput, "org.eclipse.ui.DefaultTextEditor");
}
}
/**
* @param selection
* @throws JSchException
*/
private void refresh(IStructuredSelection selection) {
for (DFSPath path : filterSelection(DFSPath.class, selection))
path.refresh();
}
private void delete(IStructuredSelection selection) {
List<DFSPath> list = filterSelection(DFSPath.class, selection);
if (list.isEmpty())
return;
StringBuffer msg = new StringBuffer();
msg.append("Are you sure you want to delete "
+ "the following files from the distributed file system?\n");
for (DFSPath path : list)
msg.append(path.getPath()).append("\n");
if (MessageDialog.openConfirm(null, "Confirm Delete from DFS", msg
.toString())) {
Set<DFSPath> toRefresh = new HashSet<DFSPath>();
for (DFSPath path : list) {
path.delete();
toRefresh.add(path.getParent());
}
for (DFSPath path : toRefresh) {
path.refresh();
}
}
}
/* @inheritDoc */
public void selectionChanged(IAction action, ISelection selection) {
this.selection = selection;
}
/**
* Extract the list of <T> from the structured selection
*
* @param clazz the class T
* @param selection the structured selection
* @return the list of <T> it contains
*/
private static <T> List<T> filterSelection(Class<T> clazz,
IStructuredSelection selection) {
List<T> list = new ArrayList<T>();
for (Object obj : selection.toList()) {
if (clazz.isAssignableFrom(obj.getClass())) {
list.add((T) obj);
}
}
return list;
}
private static int computeUploadWork(File file) {
if (file.isDirectory()) {
int contentWork = 1;
for (File child : file.listFiles())
contentWork += computeUploadWork(child);
return contentWork;
} else if (file.isFile()) {
return 1 + (int) (file.length() / 1024);
} else {
return 0;
}
}
}
/**
* Adapter to allow the viewing of a DfsFile in the Editor window
*/
class DFSFileEditorInput extends PlatformObject implements
IStorageEditorInput {
private DFSFile file;
/**
* Constructor
*
* @param file
*/
DFSFileEditorInput(DFSFile file) {
this.file = file;
}
/* @inheritDoc */
public String getToolTipText() {
return file.toDetailedString();
}
/* @inheritDoc */
public IPersistableElement getPersistable() {
return null;
}
/* @inheritDoc */
public String getName() {
return file.toString();
}
/* @inheritDoc */
public ImageDescriptor getImageDescriptor() {
return ImageLibrary.get("dfs.file.editor");
}
/* @inheritDoc */
public boolean exists() {
return true;
}
/* @inheritDoc */
public IStorage getStorage() throws CoreException {
return file.getIStorage();
}
};