com.microsoft.webapp.debug.WebAppLaunchConfigurationDelegate.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.webapp.debug.WebAppLaunchConfigurationDelegate.java

Source

/**
 * Copyright (c) Microsoft Corporation
 * 
 * All rights reserved. 
 * 
 * MIT License
 * 
 * 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:
 * 
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 * 
 * 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.webapp.debug;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.model.ILaunchConfigurationDelegate;
import org.eclipse.jdt.internal.launching.JavaRemoteApplicationLaunchConfigurationDelegate;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Display;

import com.gigaspaces.azure.util.PreferenceWebAppUtil;
import com.microsoft.tooling.msservices.helpers.azure.AzureManager;
import com.microsoft.tooling.msservices.helpers.azure.AzureManagerImpl;
import com.microsoft.tooling.msservices.model.ws.WebSite;
import com.microsoft.tooling.msservices.model.ws.WebSiteConfiguration;
import com.microsoft.tooling.msservices.model.ws.WebSitePublishSettings;
import com.microsoft.tooling.msservices.model.ws.WebSitePublishSettings.FTPPublishProfile;
import com.microsoft.tooling.msservices.model.ws.WebSitePublishSettings.MSDeployPublishProfile;
import com.microsoft.tooling.msservices.model.ws.WebSitePublishSettings.PublishProfile;
import com.microsoft.webapp.activator.Activator;
import com.microsoft.webapp.config.Messages;
import com.microsoft.webapp.util.WebAppUtils;
import com.microsoftopentechnologies.azurecommons.util.WAEclipseHelperMethods;
import com.microsoftopentechnologies.azurecommons.wacommonutil.Utils;
import com.microsoftopentechnologies.azurecommons.xmlhandling.WebAppConfigOperations;
import com.microsoftopentechnologies.wacommon.utils.PluginUtil;

@SuppressWarnings("restriction")
public class WebAppLaunchConfigurationDelegate extends JavaRemoteApplicationLaunchConfigurationDelegate
        implements ILaunchConfigurationDelegate {

    @Override
    public void launch(ILaunchConfiguration config, String mode, ILaunch launch, IProgressMonitor monitor)
            throws CoreException {
        final ILaunchConfiguration configToUse = config;
        String port = "8000";
        Map<String, String> conMap = config.getAttribute(IJavaLaunchConfigurationConstants.ATTR_CONNECT_MAP,
                new HashMap<String, String>());
        for (java.util.Map.Entry<String, String> entry : conMap.entrySet()) {
            if (entry.getKey().equalsIgnoreCase("port")) {
                port = entry.getValue();
            }
        }
        final String portToDisplayError = port;
        try {
            // check port availability
            if (Utils.isPortAvailable(Integer.parseInt(port))) {
                // get web app name to which user want to debug his application
                String website = config.getAttribute(AzureLaunchConfigurationAttributes.WEBSITE_DISPLAY, "");
                if (!website.isEmpty()) {
                    website = website.substring(0, website.indexOf('(')).trim();
                    Map<WebSite, WebSiteConfiguration> webSiteConfigMap = PreferenceWebAppUtil.load();
                    // retrieve web apps configurations
                    for (Entry<WebSite, WebSiteConfiguration> entry : webSiteConfigMap.entrySet()) {
                        final WebSite websiteTemp = entry.getKey();
                        if (websiteTemp.getName().equals(website)) {
                            // check is there a need for preparation
                            AzureManager manager = AzureManagerImpl.getManager();
                            final WebSiteConfiguration webSiteConfiguration = entry.getValue();
                            final WebSitePublishSettings webSitePublishSettings = manager.getWebSitePublishSettings(
                                    webSiteConfiguration.getSubscriptionId(),
                                    webSiteConfiguration.getWebSpaceName(), website);
                            // case - if user uses shortcut without going to Azure Tab
                            Map<String, Boolean> mp = Activator.getDefault().getWebsiteDebugPrep();
                            if (!mp.containsKey(website)) {
                                mp.put(website, false);
                            }
                            Activator.getDefault().setWebsiteDebugPrep(mp);

                            if (Activator.getDefault().getWebsiteDebugPrep().get(website).booleanValue()) {
                                // already prepared. Just start debugSession.bat
                                // retrieve MSDeploy publish profile
                                WebSitePublishSettings.MSDeployPublishProfile msDeployProfile = null;
                                for (PublishProfile pp : webSitePublishSettings.getPublishProfileList()) {
                                    if (pp instanceof MSDeployPublishProfile) {
                                        msDeployProfile = (MSDeployPublishProfile) pp;
                                        break;
                                    }
                                }
                                if (msDeployProfile != null) {
                                    ProcessBuilder pb = null;
                                    String os = System.getProperty("os.name").toLowerCase();
                                    String webAppDirPath = String.format("%s%s%s", PluginUtil.pluginFolder,
                                            File.separator, com.microsoft.webapp.util.Messages.webAppPluginID);
                                    if (Activator.IS_WINDOWS) {
                                        String command = String.format(Messages.command, port, website,
                                                msDeployProfile.getUserName(), msDeployProfile.getPassword());
                                        pb = new ProcessBuilder("cmd", "/c", "start", "cmd", "/k", command);
                                    } else if (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0
                                            || os.indexOf("aix") > 0) {
                                        // escape $ for linux
                                        String userName = "\\" + msDeployProfile.getUserName();
                                        String command = String.format(Messages.commandSh, port, website, userName,
                                                msDeployProfile.getPassword());
                                        pb = new ProcessBuilder("/bin/bash", "-c", command);
                                    } else {
                                        // escape $ for mac
                                        String userName = "'" + msDeployProfile.getUserName() + "'";
                                        // On mac, you need to specify exact path of JAR
                                        String command = String.format(Messages.commandMac, webAppDirPath + "/",
                                                port, website, userName, msDeployProfile.getPassword());
                                        String commandNext = "tell application \"Terminal\" to do script \""
                                                + command + "\"";
                                        pb = new ProcessBuilder("osascript", "-e", commandNext);
                                    }
                                    pb.directory(new File(webAppDirPath));
                                    try {
                                        pb.start();
                                        Thread.sleep(10000);
                                    } catch (Exception e) {
                                        Activator.getDefault().log(Messages.errTtl, e);
                                    }
                                    super.launch(config, mode, launch, monitor);
                                }
                            } else {
                                // start the process of preparing the web app, in a blocking way
                                Display.getDefault().syncExec(new Runnable() {
                                    @Override
                                    public void run() {
                                        boolean choice = MessageDialog.openConfirm(PluginUtil.getParentShell(),
                                                Messages.title, Messages.remoteDebug);
                                        if (choice) {
                                            IRunnableWithProgress op = new PrepareForDebug(websiteTemp,
                                                    webSiteConfiguration, webSitePublishSettings);
                                            try {
                                                new ProgressMonitorDialog(PluginUtil.getParentShell()).run(true,
                                                        true, op);
                                                MessageDialog.openInformation(PluginUtil.getParentShell(),
                                                        Messages.title, Messages.debugReady);
                                            } catch (Exception e) {
                                                Activator.getDefault().log(e.getMessage(), e);
                                            }
                                        }
                                        WebAppUtils.openDebugLaunchDialog(configToUse);
                                    }
                                });
                            }
                            break;
                        }
                    }
                }

            } else {
                Display.getDefault().syncExec(new Runnable() {
                    @Override
                    public void run() {
                        PluginUtil.displayErrorDialog(PluginUtil.getParentShell(), Messages.errTtl,
                                String.format(Messages.portMsg, portToDisplayError));
                        WebAppUtils.openDebugLaunchDialog(configToUse);
                    }
                });
            }
        } catch (Exception ex) {
            Activator.getDefault().log(ex.getMessage(), ex);
        }
    }

    private class PrepareForDebug implements IRunnableWithProgress {
        private int workload = 100;
        WebSite webSite;
        WebSiteConfiguration webSiteConfiguration;
        WebSitePublishSettings webSitePublishSettings;

        PrepareForDebug(WebSite webSite, WebSiteConfiguration webSiteConfiguration,
                WebSitePublishSettings webSitePublishSettings) {
            this.webSite = webSite;
            this.webSiteConfiguration = webSiteConfiguration;
            this.webSitePublishSettings = webSitePublishSettings;
        }

        @Override
        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
            String webSiteName = webSite.getName();
            monitor.beginTask(String.format(Messages.prepareDebug, webSiteName), workload);
            try {
                // retrieve web apps configurations
                monitor.worked(10);

                AzureManager manager = AzureManagerImpl.getManager();
                String subId = webSiteConfiguration.getSubscriptionId();
                String webSpace = webSiteConfiguration.getWebSpaceName();

                monitor.worked(20);

                // retrieve ftp publish profile
                WebSitePublishSettings.FTPPublishProfile ftpProfile = null;
                for (PublishProfile pp : webSitePublishSettings.getPublishProfileList()) {
                    if (pp instanceof FTPPublishProfile) {
                        ftpProfile = (FTPPublishProfile) pp;
                        break;
                    }
                }

                monitor.worked(30);

                if (ftpProfile != null) {
                    final FTPClient ftp = new FTPClient();
                    FTPFile[] directories = null;
                    try {
                        URI uri = null;
                        uri = new URI(ftpProfile.getPublishUrl());
                        ftp.connect(uri.getHost());
                        final int replyCode = ftp.getReplyCode();
                        if (!FTPReply.isPositiveCompletion(replyCode)) {
                            ftp.disconnect();
                        }
                        if (!ftp.login(ftpProfile.getUserName(), ftpProfile.getPassword())) {
                            ftp.logout();
                        }
                        ftp.setFileType(FTP.BINARY_FILE_TYPE);
                        if (ftpProfile.isFtpPassiveMode()) {
                            ftp.enterLocalPassiveMode();
                        }
                        boolean webConfigPresent = WebAppUtils.isFilePresentOnFTPServer(ftp,
                                com.microsoft.webapp.util.Messages.configName);

                        directories = ftp.listDirectories("/site/wwwroot/webapps");

                        monitor.worked(40);

                        // delete temporary file
                        String tmpPath = String.format("%s%s%s", System.getProperty("java.io.tmpdir"),
                                File.separator, com.microsoft.webapp.util.Messages.configName);
                        String remoteFile = "/site/wwwroot/web.config";
                        File tmpFile = new File(tmpPath);
                        if (tmpFile.exists()) {
                            tmpFile.delete();
                        }

                        monitor.worked(50);

                        // prepare server directory path as per server configuration
                        String server = webSiteConfiguration.getJavaContainer();
                        String version = webSiteConfiguration.getJavaContainerVersion();
                        String serverFolder = WebAppUtils.generateServerFolderName(server, version);

                        boolean updateRequired = true;
                        if (webConfigPresent) {
                            // download from web app server
                            OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(tmpFile));
                            ftp.retrieveFile(remoteFile, outputStream);
                            outputStream.close();
                            updateRequired = WebAppConfigOperations.isWebConfigEditRequired(tmpPath, serverFolder);
                        } else {
                            // copy file from plugin repository
                            String pluginInstLoc = String.format("%s%s%s", PluginUtil.pluginFolder, File.separator,
                                    com.microsoft.webapp.util.Messages.webAppPluginID);
                            String configFile = String.format("%s%s%s", pluginInstLoc, File.separator,
                                    com.microsoft.webapp.util.Messages.configName);
                            WAEclipseHelperMethods.copyFile(configFile, tmpPath);
                        }
                        if (updateRequired) {
                            // web app restart gives problem some times. So stop and start service
                            manager.stopWebSite(subId, webSpace, webSiteName);
                            Thread.sleep(5000);
                            WebAppConfigOperations.prepareWebConfigForDebug(tmpPath, serverFolder);
                            // delete old file and copy new file
                            ftp.deleteFile(remoteFile);
                            Thread.sleep(5000);
                            InputStream input = new FileInputStream(tmpPath);
                            ftp.storeFile("/site/wwwroot/web.config", input);
                            input.close();
                        }
                        monitor.worked(60);
                        ftp.logout();
                    } catch (Exception e) {
                        Activator.getDefault().log(e.getMessage(), e);
                    } finally {
                        if (ftp.isConnected()) {
                            try {
                                ftp.disconnect();
                            } catch (IOException ignored) {
                            }
                        }
                    }

                    // Enable Web socket and start web app
                    manager.enableWebSockets(subId, webSpace, webSiteName, webSite.getLocation(), true);
                    // if web site is stopped we will require to start for debugging
                    manager.startWebSite(subId, webSpace, webSiteName);
                    Thread.sleep(10000);

                    monitor.worked(70);

                    for (FTPFile dir : directories) {
                        String sitePath = ftpProfile.getDestinationAppUrl();
                        if (!dir.getName().equalsIgnoreCase("ROOT")) {
                            sitePath = ftpProfile.getDestinationAppUrl() + "/" + dir.getName();
                        }
                        final String sitePathFinal = sitePath;
                        new Thread("Warm up the target site") {
                            public void run() {
                                try {
                                    WebAppUtils.sendGet(sitePathFinal);
                                } catch (Exception ex) {
                                    Activator.getDefault().log(ex.getMessage(), ex);
                                }
                            }
                        }.start();
                        Thread.sleep(5000);
                    }
                    Activator.getDefault().getWebsiteDebugPrep().put(webSiteName, true);
                    Thread.sleep(10000);
                    monitor.worked(100);
                }
            } catch (Exception e) {
                Activator.getDefault().log(e.getMessage(), e);
            } finally {
                monitor.done();
            }
            // Check if the user pressed "cancel"
            if (monitor.isCanceled()) {
                monitor.done();
                Activator.getDefault().getWebsiteDebugPrep().put(webSiteName, false);
                return;
            }
        }
    }
}