com.microsoft.intellij.helpers.IDEHelperImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.intellij.helpers.IDEHelperImpl.java

Source

/**
 * Copyright (c) Microsoft Corporation
 * <p/>
 * All rights reserved.
 * <p/>
 * MIT License
 * <p/>
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 * <p/>
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
 * the Software.
 * <p/>
 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.microsoft.intellij.helpers;

import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.SettableFuture;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.compiler.CompileContext;
import com.intellij.openapi.compiler.CompileScope;
import com.intellij.openapi.compiler.CompileStatusNotification;
import com.intellij.openapi.compiler.CompilerManager;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.artifacts.Artifact;
import com.intellij.packaging.impl.artifacts.ArtifactUtil;
import com.intellij.packaging.impl.compiler.ArtifactCompileScope;
import com.intellij.packaging.impl.compiler.ArtifactsWorkspaceSettings;
import com.microsoft.intellij.AzureSettings;
import com.microsoft.intellij.helpers.tasks.CancellableTaskHandleImpl;
import com.microsoft.tooling.msservices.components.DefaultLoader;
import com.microsoft.tooling.msservices.helpers.IDEHelper;
import com.microsoft.tooling.msservices.helpers.NotNull;
import com.microsoft.tooling.msservices.helpers.Nullable;
import com.microsoft.tooling.msservices.helpers.ServiceCodeReferenceHelper;
import com.microsoft.tooling.msservices.helpers.azure.AzureCmdException;
import com.microsoft.tooling.msservices.helpers.tasks.CancellableTask;
import com.microsoft.tooling.msservices.helpers.tasks.CancellableTask.CancellableTaskHandle;
import com.microsoft.tooling.msservices.serviceexplorer.Node;
import com.microsoftopentechnologies.auth.browser.BrowserLauncher;
import org.apache.commons.lang3.tuple.Pair;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class IDEHelperImpl implements IDEHelper {
    private final Project project;

    public IDEHelperImpl(Project project) {
        this.project = project;
    }

    @Override
    public void openFile(@NotNull File file, @NotNull final Object n) {
        final Node node = (Node) n;
        final VirtualFile finalEditfile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
        ApplicationManager.getApplication().runReadAction(new Runnable() {
            @Override
            public void run() {
                try {
                    openFile(node.getProject(), finalEditfile);
                } finally {
                    node.setLoading(false);
                }
            }
        });
    }

    @Override
    public void saveFile(@NotNull final File file, @NotNull final ByteArrayOutputStream buff,
            @NotNull final Object n) {
        final Node node = (Node) n;
        ApplicationManager.getApplication().runWriteAction(new Runnable() {
            @Override
            public void run() {
                try {
                    final VirtualFile editfile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);

                    if (editfile != null) {
                        editfile.setWritable(true);
                        editfile.setBinaryContent(buff.toByteArray());

                        ApplicationManager.getApplication().invokeLater(new Runnable() {
                            @Override
                            public void run() {
                                FileEditorManager.getInstance((Project) node.getProject()).openFile(editfile, true);
                            }
                        });
                    }
                } catch (Throwable e) {
                    DefaultLoader.getUIHelper().showException(
                            "An error occurred while attempting to write temporal " + "editable file.", e,
                            "Azure Services Explorer - Error Writing Temp File", false, true);
                } finally {
                    node.setLoading(false);
                }
            }
        });
    }

    @Override
    public void replaceInFile(@NotNull Object moduleObject, @NotNull Pair<String, String>... replace) {
        Module module = (Module) moduleObject;

        if (module.getModuleFile() != null && module.getModuleFile().getParent() != null) {
            VirtualFile vf = module.getModuleFile().getParent()
                    .findFileByRelativePath(ServiceCodeReferenceHelper.STRINGS_XML);

            if (vf != null) {
                FileDocumentManager fdm = FileDocumentManager.getInstance();
                com.intellij.openapi.editor.Document document = fdm.getDocument(vf);

                if (document != null) {
                    String content = document.getText();

                    for (Pair<String, String> pair : replace) {
                        content = content.replace(pair.getLeft(), pair.getRight());
                    }

                    document.setText(content);
                    fdm.saveDocument(document);
                }
            }
        }
    }

    @Override
    public void copyJarFiles2Module(@NotNull Object moduleObject, @NotNull File zipFile, @NotNull String zipPath)
            throws IOException {
        Module module = (Module) moduleObject;
        final VirtualFile moduleFile = module.getModuleFile();

        if (moduleFile != null) {
            moduleFile.refresh(false, false);

            final VirtualFile moduleDir = module.getModuleFile().getParent();

            if (moduleDir != null) {
                moduleDir.refresh(false, false);

                copyJarFiles(module, moduleDir, zipFile, zipPath);
            }
        }
    }

    @Override
    public boolean isFileEditing(@NotNull Object projectObject, @NotNull File file) {
        VirtualFile scriptFile = LocalFileSystem.getInstance().findFileByIoFile(file);
        boolean fileIsEditing = false;

        if (scriptFile != null) {
            fileIsEditing = FileEditorManager.getInstance((Project) projectObject)
                    .getEditors(scriptFile).length != 0;
        }

        return fileIsEditing;
    }

    @Override
    public void closeFile(@NotNull final Object projectObject, @NotNull final Object openedFile) {
        ApplicationManager.getApplication().invokeLater(new Runnable() {
            @Override
            public void run() {
                FileEditorManager.getInstance((Project) projectObject).closeFile((VirtualFile) openedFile);
            }
        }, ModalityState.any());
    }

    @Override
    public void invokeLater(@NotNull Runnable runnable) {
        ApplicationManager.getApplication().invokeLater(runnable, ModalityState.any());
    }

    @Override
    public void invokeAndWait(@NotNull Runnable runnable) {
        ApplicationManager.getApplication().invokeAndWait(runnable, ModalityState.any());
    }

    @Override
    public void executeOnPooledThread(@NotNull Runnable runnable) {
        ApplicationManager.getApplication().executeOnPooledThread(runnable);
    }

    @Override
    public void runInBackground(@Nullable final Object project, @NotNull final String name,
            final boolean canBeCancelled, final boolean isIndeterminate, @Nullable final String indicatorText,
            final Runnable runnable) {
        // background tasks via ProgressManager can be scheduled only on the
        // dispatch thread
        ApplicationManager.getApplication().invokeLater(new Runnable() {
            @Override
            public void run() {
                ProgressManager.getInstance().run(new Task.Backgroundable((Project) project, name, canBeCancelled) {
                    @Override
                    public void run(@NotNull ProgressIndicator indicator) {
                        if (isIndeterminate) {
                            indicator.setIndeterminate(true);
                        }

                        if (indicatorText != null) {
                            indicator.setText(indicatorText);
                        }

                        runnable.run();
                    }
                });
            }
        }, ModalityState.any());
    }

    @NotNull
    @Override
    public CancellableTaskHandle runInBackground(@NotNull ProjectDescriptor projectDescriptor,
            @NotNull final String name, @Nullable final String indicatorText,
            @NotNull final CancellableTask cancellableTask) throws AzureCmdException {
        final CancellableTaskHandleImpl handle = new CancellableTaskHandleImpl();
        final Project project = findOpenProject(projectDescriptor);

        // background tasks via ProgressManager can be scheduled only on the
        // dispatch thread
        ApplicationManager.getApplication().invokeLater(new Runnable() {
            @Override
            public void run() {
                ProgressManager.getInstance()
                        .run(getCancellableBackgroundTask(project, name, indicatorText, handle, cancellableTask));
            }
        }, ModalityState.any());

        return handle;
    }

    @Nullable
    @Override
    public String getProperty(@NotNull String name) {
        return AzureSettings.getSafeInstance(project).getProperty(name);
        //        return PropertiesComponent.getInstance().getValue(name);
    }

    @NotNull
    @Override
    public String getProperty(@NotNull String name, @NotNull String defaultValue) {
        return PropertiesComponent.getInstance().getValue(name, defaultValue);
    }

    @Override
    public void setProperty(@NotNull String name, @NotNull String value) {
        AzureSettings.getSafeInstance(project).setProperty(name, value);
        //        PropertiesComponent.getInstance().setValue(name, value);
        //        ApplicationManager.getApplication().invokeLater(new Runnable() {
        //            @Override
        //            public void run() {
        //                ApplicationManager.getApplication().saveSettings();
        //            }
        //        }, ModalityState.any());
    }

    @Override
    public void unsetProperty(@NotNull String name) {
        AzureSettings.getSafeInstance(project).unsetProperty(name);
        //        PropertiesComponent.getInstance().unsetValue(name);
        //        ApplicationManager.getApplication().invokeLater(new Runnable() {
        //            @Override
        //            public void run() {
        //                ApplicationManager.getApplication().saveSettings();
        //            }
        //        }, ModalityState.any());
    }

    @Override
    public boolean isPropertySet(@NotNull String name) {
        return AzureSettings.getSafeInstance(project).isPropertySet(name);
        //        return PropertiesComponent.getInstance().isValueSet(name);
    }

    @Nullable
    @Override
    public String[] getProperties(@NotNull String name) { // todo!!!
        return AzureSettings.getSafeInstance(project).getProperties(name);
        //        return PropertiesComponent.getInstance().getValues(name);
    }

    @Override
    public void setProperties(@NotNull String name, @NotNull String[] value) {
        AzureSettings.getSafeInstance(project).setProperties(name, value);
        //        PropertiesComponent.getInstance().setValues(name, value);
        //        ApplicationManager.getApplication().saveSettings();
    }

    @NotNull
    @Override
    public List<ArtifactDescriptor> getArtifacts(@NotNull ProjectDescriptor projectDescriptor)
            throws AzureCmdException {
        Project project = findOpenProject(projectDescriptor);

        List<ArtifactDescriptor> artifactDescriptors = new ArrayList<ArtifactDescriptor>();

        for (Artifact artifact : ArtifactUtil.getArtifactWithOutputPaths(project)) {
            artifactDescriptors.add(new ArtifactDescriptor(artifact.getName(), artifact.getArtifactType().getId()));
        }

        return artifactDescriptors;
    }

    @NotNull
    @Override
    public ListenableFuture<String> buildArtifact(@NotNull ProjectDescriptor projectDescriptor,
            @NotNull ArtifactDescriptor artifactDescriptor) {
        try {
            Project project = findOpenProject(projectDescriptor);

            final Artifact artifact = findProjectArtifact(project, artifactDescriptor);

            final SettableFuture<String> future = SettableFuture.create();

            Futures.addCallback(buildArtifact(project, artifact, false), new FutureCallback<Boolean>() {
                @Override
                public void onSuccess(@Nullable Boolean succeded) {
                    if (succeded != null && succeded) {
                        future.set(artifact.getOutputFilePath());
                    } else {
                        future.setException(new AzureCmdException("An error occurred while building the artifact"));
                    }
                }

                @Override
                public void onFailure(Throwable throwable) {
                    if (throwable instanceof ExecutionException) {
                        future.setException(new AzureCmdException("An error occurred while building the artifact",
                                throwable.getCause()));
                    } else {
                        future.setException(
                                new AzureCmdException("An error occurred while building the artifact", throwable));
                    }
                }
            });

            return future;
        } catch (AzureCmdException e) {
            return Futures.immediateFailedFuture(e);
        }
    }

    @Override
    public BrowserLauncher getBrowserLauncher() {
        return null;
    }

    private static void openFile(@NotNull final Object projectObject, @Nullable final VirtualFile finalEditfile) {
        try {
            if (finalEditfile != null) {
                finalEditfile.setWritable(true);

                ApplicationManager.getApplication().invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        FileEditorManager.getInstance((Project) projectObject).openFile(finalEditfile, true);
                    }
                });
            }
        } catch (Throwable e) {
            DefaultLoader.getUIHelper().showException(
                    "An error occurred while attempting to write temporal editable " + "file.", e,
                    "Azure Services Explorer - Error Writing Temp File", false, true);
        }
    }

    private static void copyJarFiles(@NotNull final Module module, @NotNull VirtualFile baseDir,
            @NotNull File zipFile, @NotNull String zipPath) throws IOException {
        if (baseDir.isDirectory()) {
            final ZipFile zip = new ZipFile(zipFile);
            Enumeration<? extends ZipEntry> entries = zip.entries();

            while (entries.hasMoreElements()) {
                final ZipEntry zipEntry = entries.nextElement();

                if (!zipEntry.isDirectory() && zipEntry.getName().startsWith(zipPath)
                        && zipEntry.getName().endsWith(".jar") && !(zipEntry.getName().endsWith("-sources.jar")
                                || zipEntry.getName().endsWith("-javadoc.jar"))) {
                    VirtualFile libsVf = null;

                    for (VirtualFile vf : baseDir.getChildren()) {
                        if (vf.getName().equals("libs")) {
                            libsVf = vf;
                            break;
                        }
                    }

                    if (libsVf == null) {
                        libsVf = baseDir.createChildDirectory(module.getProject(), "libs");
                    }

                    final VirtualFile libs = libsVf;
                    final String fileName = zipEntry.getName().split("/")[1];

                    if (libs.findChild(fileName) == null) {
                        ApplicationManager.getApplication().invokeAndWait(new Runnable() {
                            @Override
                            public void run() {
                                ApplicationManager.getApplication().runWriteAction(new Runnable() {
                                    @Override
                                    public void run() {
                                        try {
                                            InputStream mobileserviceInputStream = zip.getInputStream(zipEntry);
                                            VirtualFile msVF = libs.createChildData(module.getProject(), fileName);
                                            msVF.setBinaryContent(getArray(mobileserviceInputStream));
                                        } catch (Throwable ex) {
                                            DefaultLoader.getUIHelper().showException(
                                                    "An error occurred while attempting "
                                                            + "to configure Azure Mobile Services.",
                                                    ex,
                                                    "Azure Services Explorer - Error Configuring Mobile Services",
                                                    false, true);
                                        }
                                    }
                                });
                            }
                        }, ModalityState.defaultModalityState());
                    }
                }
            }
        }
    }

    @NotNull
    private static byte[] getArray(@NotNull InputStream is) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();

        int nRead;
        byte[] data = new byte[16384];

        while ((nRead = is.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }

        buffer.flush();

        return buffer.toByteArray();
    }

    private static ListenableFuture<Boolean> buildArtifact(@NotNull Project project,
            final @NotNull Artifact artifact, boolean rebuild) {
        final SettableFuture<Boolean> future = SettableFuture.create();

        Set<Artifact> artifacts = new LinkedHashSet<Artifact>(1);
        artifacts.add(artifact);
        CompileScope scope = ArtifactCompileScope.createArtifactsScope(project, artifacts, rebuild);
        ArtifactsWorkspaceSettings.getInstance(project).setArtifactsToBuild(artifacts);

        CompilerManager.getInstance(project).make(scope, new CompileStatusNotification() {
            @Override
            public void finished(boolean aborted, int errors, int warnings, CompileContext compileContext) {
                future.set(!aborted && errors == 0);
            }
        });

        return future;
    }

    @NotNull
    private static Project findOpenProject(@NotNull ProjectDescriptor projectDescriptor) throws AzureCmdException {
        Project project = null;

        for (Project openProject : ProjectManager.getInstance().getOpenProjects()) {
            if (projectDescriptor.getName().equals(openProject.getName())
                    && projectDescriptor.getPath().equals(openProject.getBasePath())) {
                project = openProject;
                break;
            }
        }

        if (project == null) {
            throw new AzureCmdException("Unable to find an open project with the specified description.");
        }

        return project;
    }

    @NotNull
    private static Artifact findProjectArtifact(@NotNull Project project,
            @NotNull ArtifactDescriptor artifactDescriptor) throws AzureCmdException {
        Artifact artifact = null;

        for (Artifact projectArtifact : ArtifactUtil.getArtifactWithOutputPaths(project)) {
            if (artifactDescriptor.getName().equals(projectArtifact.getName())
                    && artifactDescriptor.getArtifactType().equals(projectArtifact.getArtifactType().getId())) {
                artifact = projectArtifact;
                break;
            }
        }

        if (artifact == null) {
            throw new AzureCmdException("Unable to find an artifact with the specified description.");
        }

        return artifact;
    }

    @org.jetbrains.annotations.NotNull
    private static Task.Backgroundable getCancellableBackgroundTask(final Project project,
            @NotNull final String name, @Nullable final String indicatorText,
            final CancellableTaskHandleImpl handle, @NotNull final CancellableTask cancellableTask) {
        return new Task.Backgroundable(project, name, true) {
            private final Semaphore lock = new Semaphore(0);

            @Override
            public void run(@org.jetbrains.annotations.NotNull ProgressIndicator indicator) {
                indicator.setIndeterminate(true);

                handle.setProgressIndicator(indicator);

                if (indicatorText != null) {
                    indicator.setText(indicatorText);
                }

                ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            cancellableTask.run(handle);
                        } catch (Throwable t) {
                            handle.setException(t);
                        } finally {
                            lock.release();
                        }
                    }
                });

                try {
                    while (!lock.tryAcquire(1, TimeUnit.SECONDS)) {
                        if (handle.isCancelled()) {
                            ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
                                @Override
                                public void run() {
                                    cancellableTask.onCancel();
                                }
                            });

                            return;
                        }
                    }

                    ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
                        @Override
                        public void run() {
                            if (handle.getException() == null) {
                                cancellableTask.onSuccess();
                            } else {
                                cancellableTask.onError(handle.getException());
                            }
                        }
                    });
                } catch (InterruptedException ignored) {
                }
            }
        };
    }
}