org.sf.feeling.decompiler.actions.ExportSourceAction.java Source code

Java tutorial

Introduction

Here is the source code for org.sf.feeling.decompiler.actions.ExportSourceAction.java

Source

/*******************************************************************************
 * Copyright (c) 2016 Chen Chao(cnfree2000@hotmail.com).
 * 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:
 *  Chen Chao  - initial API and implementation
 *******************************************************************************/

package org.sf.feeling.decompiler.actions;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.Deflater;
import java.util.zip.ZipOutputStream;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.sf.feeling.decompiler.JavaDecompilerPlugin;
import org.sf.feeling.decompiler.i18n.Messages;
import org.sf.feeling.decompiler.util.DecompileUtil;
import org.sf.feeling.decompiler.util.FileUtil;
import org.sf.feeling.decompiler.util.UIUtil;

public class ExportSourceAction extends Action {

    private List selection = null;
    private boolean isFlat = false;

    public ExportSourceAction(List selection) {
        super(Messages.getString("ExportSourceAction.Action.Text")); //$NON-NLS-1$
        this.setImageDescriptor(JavaDecompilerPlugin.getImageDescriptor("icons/etool16/export_wiz.gif")); //$NON-NLS-1$
        this.setDisabledImageDescriptor(JavaDecompilerPlugin.getImageDescriptor("icons/dtool16/export_wiz.gif")); //$NON-NLS-1$
        this.selection = selection;
        this.isFlat = UIUtil.isPackageFlat();
    }

    public void run() {
        if (selection == null || selection.isEmpty())
            return;

        IPreferenceStore prefs = JavaDecompilerPlugin.getDefault().getPreferenceStore();
        final String decompilerType = prefs.getString(JavaDecompilerPlugin.DECOMPILER_TYPE);
        final boolean reuseBuf = prefs.getBoolean(JavaDecompilerPlugin.REUSE_BUFFER);
        final boolean always = prefs.getBoolean(JavaDecompilerPlugin.IGNORE_EXISTING);

        Object firstElement = selection.get(0);
        if (selection.size() == 1 && firstElement instanceof IClassFile) {
            IClassFile cf = (IClassFile) firstElement;
            exportClass(decompilerType, reuseBuf, always, cf);
        } else if (selection.size() == 1 && firstElement instanceof IPackageFragmentRoot) {
            IPackageFragmentRoot root = (IPackageFragmentRoot) firstElement;
            FileDialog dialog = new FileDialog(Display.getDefault().getActiveShell(), SWT.SAVE | SWT.SHEET);
            String fileName = root.getElementName();
            int index = fileName.lastIndexOf('.');
            if (index != -1) {
                fileName = fileName.substring(0, index);
            }
            dialog.setFileName(fileName + "-src"); //$NON-NLS-1$
            dialog.setFilterExtensions(new String[] { "*.zip" //$NON-NLS-1$
            });
            String file = dialog.open();
            if (file != null && file.trim().length() > 0) {
                final String projectFile = file.trim();
                try {
                    final IJavaElement[] children = root.getChildren();
                    exportPackagesSource(decompilerType, reuseBuf, always, projectFile, children);
                } catch (CoreException e) {
                    ExceptionHandler.handle(e, Messages.getString("ExportSourceAction.ErrorDialog.Title"), //$NON-NLS-1$
                            Messages.getString("ExportSourceAction.ErrorDialog.Message.CollectClassInfo")); //$NON-NLS-1$
                }
            } else {
                return;
            }
        } else {
            IPackageFragmentRoot root = null;
            if (firstElement instanceof IClassFile) {
                root = (IPackageFragmentRoot) ((IClassFile) firstElement).getParent().getParent();
            } else if (firstElement instanceof IPackageFragment) {
                root = (IPackageFragmentRoot) ((IPackageFragment) firstElement).getParent();
            }
            if (root == null)
                return;
            FileDialog dialog = new FileDialog(Display.getDefault().getActiveShell(), SWT.SAVE | SWT.SHEET);
            String fileName = root.getElementName();
            int index = fileName.lastIndexOf('.');
            if (index != -1) {
                fileName = fileName.substring(0, index);
            }
            dialog.setFileName(fileName + "-src"); //$NON-NLS-1$
            dialog.setFilterExtensions(new String[] { "*.zip" //$NON-NLS-1$
            });
            String file = dialog.open();
            if (file != null && file.trim().length() > 0) {
                final String projectFile = file.trim();

                exportPackagesSource(decompilerType, reuseBuf, always, projectFile,
                        (IJavaElement[]) selection.toArray(new IJavaElement[0]));
            } else {
                return;
            }
        }
    }

    private void exportPackagesSource(final String decompilerType, final boolean reuseBuf, final boolean always,
            final String projectFile, final IJavaElement[] children) {
        try {
            final List exceptions = new ArrayList();
            ProgressMonitorDialog dialog = new ProgressMonitorDialog(Display.getDefault().getActiveShell());
            dialog.run(true, true, new IRunnableWithProgress() {

                public void run(final IProgressMonitor monitor)
                        throws InvocationTargetException, InterruptedException {
                    exportPackageSources(monitor, decompilerType, reuseBuf, always, projectFile, children,
                            exceptions);

                    final File workingDir = new File(JavaDecompilerPlugin.getDefault().getPreferenceStore()
                            .getString(JavaDecompilerPlugin.TEMP_DIR));// $NON-NLS-1$

                    if (workingDir != null && workingDir.exists()) {
                        try {
                            FileUtil.deleteDirectory(null, workingDir, 0);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            });

            if (dialog.getProgressMonitor().isCanceled()) {
                MessageDialog.openInformation(Display.getDefault().getActiveShell(),
                        Messages.getString("ExportSourceAction.InfoDialog.Title"), //$NON-NLS-1$
                        Messages.getString("ExportSourceAction.InfoDialog.Message.Canceled")); //$NON-NLS-1$
            } else if (!exceptions.isEmpty()) {
                final MultiStatus status = new MultiStatus(JavaDecompilerPlugin.PLUGIN_ID, IStatus.WARNING,
                        (exceptions.size() <= 1
                                ? Messages.getFormattedString("ExportSourceAction.WarningDialog.Message.Failed", //$NON-NLS-1$
                                        new String[] { "" + exceptions.size() //$NON-NLS-1$
                                        })
                                : Messages.getFormattedString(
                                        "ExportSourceAction.WarningDialog.Message.Failed.Multi", //$NON-NLS-1$
                                        new String[] { "" + exceptions.size() //$NON-NLS-1$
                                        })), null) {

                    public void add(IStatus status) {
                        super.add(status);
                        setSeverity(IStatus.WARNING);
                    }
                };
                for (int i = 0; i < exceptions.size(); i++) {
                    Status exception = (Status) exceptions.get(i);
                    status.add(exception);
                }

                JavaDecompilerPlugin.getDefault().getLog().log(status);
                ErrorDialog.openError(Display.getDefault().getActiveShell(),
                        Messages.getString("ExportSourceAction.WarningDialog.Title"), //$NON-NLS-1$
                        Messages.getString("ExportSourceAction.WarningDialog.Message.Success"), //$NON-NLS-1$
                        status);

            } else {
                MessageDialog.openInformation(Display.getDefault().getActiveShell(),
                        Messages.getString("ExportSourceAction.InfoDialog.Title"), //$NON-NLS-1$
                        Messages.getString("ExportSourceAction.InfoDialog.Message.Success")); //$NON-NLS-1$
            }
        } catch (Exception e) {
            IStatus status = new Status(IStatus.ERROR, JavaDecompilerPlugin.PLUGIN_ID,
                    Messages.getString("ExportSourceAction.Status.Error.DecompileAndExport"), //$NON-NLS-1$
                    e);
            ExceptionHandler.handle(status, Messages.getString("ExportSourceAction.ErrorDialog.Title"), //$NON-NLS-1$
                    status.getMessage());
        }
    }

    private void exportPackageSources(IProgressMonitor monitor, final String decompilerType, final boolean reuseBuf,
            final boolean always, final String projectFile, final IJavaElement[] children, List exceptions)
            throws InvocationTargetException, InterruptedException {
        monitor.beginTask(Messages.getString("ExportSourceAction.Task.Begin"), //$NON-NLS-1$
                1000000);

        final File workingDir = new File(
                JavaDecompilerPlugin.getDefault().getPreferenceStore().getString(JavaDecompilerPlugin.TEMP_DIR)
                        + "/export/" //$NON-NLS-1$
                        + System.currentTimeMillis());

        Map classes = new HashMap();
        for (int i = 0; i < children.length; i++) {
            if (monitor.isCanceled())
                return;
            IJavaElement child = children[i];
            try {
                collectClasses(child, classes, monitor);
            } catch (JavaModelException e) {
                IStatus status = new Status(IStatus.ERROR, JavaDecompilerPlugin.PLUGIN_ID,
                        Messages.getString("ExportSourceAction.Status.Error.CollectPackage"), //$NON-NLS-1$
                        e);
                exceptions.add(status);
            }
        }

        monitor.worked(20000);

        IPackageFragment[] pkgs = (IPackageFragment[]) classes.keySet().toArray(new IPackageFragment[0]);
        int step = 880000 / pkgs.length;
        for (int i = 0; i < pkgs.length; i++) {
            if (monitor.isCanceled())
                return;
            IPackageFragment pkg = pkgs[i];
            List clazzs = (List) classes.get(pkg);
            if (clazzs.size() == 0) {
                monitor.worked(step);
                continue;
            }
            int total = 0;
            int classStep = step / clazzs.size();
            for (int j = 0; j < clazzs.size(); j++) {
                if (monitor.isCanceled())
                    return;
                IJavaElement clazz = (IJavaElement) clazzs.get(j);
                if (clazz instanceof IClassFile && clazz.getParent() instanceof IPackageFragment) {
                    String className = pkg.getElementName();
                    if (pkg.getElementName().length() > 0) {
                        className += ("." + clazz.getElementName()); //$NON-NLS-1$
                    }
                    monitor.subTask(className);
                    try {
                        IClassFile cf = (IClassFile) clazz;
                        if (cf.getElementName().indexOf('$') != -1)
                            continue;
                        String result = DecompileUtil.decompile(cf, decompilerType, always, reuseBuf, true);
                        if (result != null) {
                            String packageName = pkg.getElementName().replace('.', '/');
                            if (packageName.length() > 0)
                                packageName += "/"; //$NON-NLS-1$
                            FileUtil.writeToFile(
                                    new File(workingDir, packageName + cf.getElementName().replaceAll("\\..+", "") //$NON-NLS-1$ //$NON-NLS-2$
                                            + ".java"), //$NON-NLS-1$
                                    result);
                        } else {
                            IStatus status = new Status(IStatus.ERROR, JavaDecompilerPlugin.PLUGIN_ID,
                                    Messages.getFormattedString("ExportSourceAction.Status.Error.DecompileFailed", //$NON-NLS-1$
                                            new String[] { className }));
                            throw new CoreException(status);
                        }
                    } catch (Exception e) {
                        IStatus status = new Status(IStatus.ERROR, JavaDecompilerPlugin.PLUGIN_ID,
                                Messages.getFormattedString("ExportSourceAction.Status.Error.DecompileFailed", //$NON-NLS-1$
                                        new String[] { className }));
                        exceptions.add(status);
                    }

                }
                total += classStep;
                monitor.worked(classStep);
            }
            if (total < step) {
                monitor.worked(step - total);
            }
        }
        try {
            int exportStep = 80000 / pkgs.length;
            monitor.setTaskName(Messages.getString("ExportSourceAction.Task.ExportSource")); //$NON-NLS-1$
            monitor.subTask(""); //$NON-NLS-1$
            ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(projectFile)));
            zos.setLevel(Deflater.BEST_SPEED);
            FileUtil.recursiveZip(monitor, zos, workingDir, "", //$NON-NLS-1$
                    null, exportStep);
            monitor.subTask(""); //$NON-NLS-1$
            zos.close();

            int total = exportStep * pkgs.length;
            if (total < 80000) {
                monitor.worked(80000 - total);
            }

            int deleteStep = 20000 / pkgs.length;
            monitor.setTaskName(Messages.getString("ExportSourceAction.Task.Clean")); //$NON-NLS-1$
            monitor.subTask(""); //$NON-NLS-1$
            FileUtil.deleteDirectory(monitor, workingDir.getParentFile(), deleteStep);
            total = deleteStep * pkgs.length;
            if (total < 20000) {
                monitor.worked(20000 - total);
            }
        } catch (Exception e) {
            final IStatus status = new Status(IStatus.ERROR, JavaDecompilerPlugin.PLUGIN_ID,
                    Messages.getString("ExportSourceAction.Status.Error.ExportFailed"), //$NON-NLS-1$
                    e);
            exceptions.add(status);
        }
    }

    private void collectClasses(IJavaElement element, Map classes, IProgressMonitor monitor)
            throws JavaModelException {
        if (element instanceof IPackageFragment) {
            IPackageFragment pkg = (IPackageFragment) element;
            if (!classes.containsKey(pkg)) {
                monitor.subTask(pkg.getElementName());
                List list = new ArrayList();
                IJavaElement[] children = pkg.getChildren();
                for (int i = 0; i < children.length; i++) {
                    list.add(children[i]);
                }
                classes.put(pkg, list);
            }
            if (!isFlat) {
                IPackageFragmentRoot root = (IPackageFragmentRoot) pkg.getParent();
                IJavaElement[] children = root.getChildren();
                for (int i = 0; i < root.getChildren().length; i++) {
                    IPackageFragment child = (IPackageFragment) children[i];
                    if (child.getElementName().startsWith(pkg.getElementName() + ".") //$NON-NLS-1$
                            && !classes.containsKey(child)) {
                        collectClasses(child, classes, monitor);
                    }
                }
            }
        } else if (element instanceof IClassFile) {
            IPackageFragment pkg = (IPackageFragment) ((IClassFile) element).getParent();
            if (!classes.containsKey(pkg)) {
                monitor.subTask(pkg.getElementName());
                List list = new ArrayList();
                list.add(element);
                classes.put(pkg, list);
            } else {
                ((List) classes.get(pkg)).add(element);
            }
        }
    }

    private void exportClass(String decompilerType, boolean reuseBuf, boolean always, IClassFile cf) {
        FileDialog dialog = new FileDialog(Display.getDefault().getActiveShell(), SWT.SAVE | SWT.SHEET);
        dialog.setFileName(cf.getElementName().replaceAll("\\..+", "")); //$NON-NLS-1$ //$NON-NLS-2$
        dialog.setFilterExtensions(new String[] { "*.java" //$NON-NLS-1$
        });
        String file = dialog.open();
        if (file != null && file.trim().length() > 0) {
            IPackageFragment pkg = (IPackageFragment) cf.getParent();
            String className = pkg.getElementName();
            if (pkg.getElementName().length() > 0) {
                className += ("." + cf.getElementName()); //$NON-NLS-1$
            }

            String projectFile = file.trim();
            try {
                String result = DecompileUtil.decompile(cf, decompilerType, always, reuseBuf, true);
                if (result != null)
                    FileUtil.writeToFile(new File(projectFile), result);
                else {
                    IStatus status = new Status(IStatus.ERROR, JavaDecompilerPlugin.PLUGIN_ID,
                            Messages.getFormattedString("ExportSourceAction.Status.Error.DecompileFailed", //$NON-NLS-1$
                                    new String[] { className }));
                    throw new CoreException(status);
                }
            } catch (CoreException e) {
                MessageDialog.openError(Display.getDefault().getActiveShell(),
                        Messages.getString("ExportSourceAction.ErrorDialog.Title"), //$NON-NLS-1$
                        Messages.getFormattedString("ExportSourceAction.Status.Error.DecompileFailed", //$NON-NLS-1$
                                new String[] { className }));
            }
        } else {
            return;
        }
    }

    public boolean isEnabled() {
        return selection != null;
    }

}