org.cloudfoundry.ide.eclipse.server.ui.internal.CloudRebelUIHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.ide.eclipse.server.ui.internal.CloudRebelUIHandler.java

Source

/*******************************************************************************
 * Copyright (c) 2015 Pivotal Software, Inc. 
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of 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.
 *  
 *  Contributors:
 *     Pivotal Software, Inc. - initial API and implementation
 ********************************************************************************/
package org.cloudfoundry.ide.eclipse.server.ui.internal;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.cloudfoundry.ide.eclipse.server.core.internal.CloudFoundryPlugin;
import org.cloudfoundry.ide.eclipse.server.core.internal.CloudFoundryProjectUtil;
import org.cloudfoundry.ide.eclipse.server.core.internal.CloudServerEvent;
import org.cloudfoundry.ide.eclipse.server.core.internal.ServerEventHandler;
import org.cloudfoundry.ide.eclipse.server.core.internal.jrebel.CloudRebelAppHandler;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.wst.server.core.IModule;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class CloudRebelUIHandler extends CloudRebelAppHandler {

    private static CloudRebelAppHandler handler;

    public CloudRebelUIHandler() {
    }

    public void register() {
        if (handler == null && CloudRebelAppHandler.isJRebelIDEInstalled()) {
            handler = this;
            ServerEventHandler.getDefault().addServerListener(handler);
        }
    }

    @Override
    protected void handleRebelProject(CloudServerEvent event, IModule module, IProgressMonitor monitor)
            throws CoreException {

        IProject project = module.getProject();
        // Only replace rebel xml file if a manual Remoting
        // update is performed on Spring boot applications
        if (event.getType() == CloudServerEvent.EVENT_JREBEL_REMOTING_UPDATE
                && CloudFoundryProjectUtil.isSpringBootCloudFoundryConfigured(project)) {
            updateRebelXML(project, monitor);
        }

        super.handleRebelProject(event, module, monitor);
    }

    protected void updateRebelXML(IProject project, IProgressMonitor monitor) {

        // rebel.xml is overwritten for Spring Boot Jar apps to skip the /lib
        // folder which
        // is only generated in the Spring Boot Jar but has no workspace
        // equivalent
        try {

            IFile file = getRebelXMLFile(project);
            if (file != null && file.isAccessible()) {
                String path = file.getRawLocation() != null ? file.getRawLocation().toString() : null;

                if (path != null) {
                    List<String> outputPaths = getClasspathSourceOutputPaths(project);

                    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

                    DocumentBuilder db = factory.newDocumentBuilder();
                    Document doc = db.parse(new File(path));

                    Element javaProjectOutputElement = null;
                    NodeList nodeList = doc.getElementsByTagName("*"); //$NON-NLS-1$
                    if (nodeList != null) {

                        String libFolderName = "lib/**"; //$NON-NLS-1$

                        String javaBuildpackFolderName = ".java-buildpack/**"; //$NON-NLS-1$

                        // Find the node element that corresponds to the
                        // project's source output. Check all the resolved
                        // output paths to find
                        // the one that matches the "dir" element in the
                        // rebel.xml
                        for (int i = 0; i < nodeList.getLength(); i++) {
                            Node node = nodeList.item(i);
                            if ((node instanceof Element) && node.getNodeName().equals("dir")) { //$NON-NLS-1$
                                Element element = (Element) node;
                                String att = element.getAttribute("name"); //$NON-NLS-1$
                                if (att != null) {

                                    for (String outpath : outputPaths) {
                                        if (att.contains(outpath)) {
                                            javaProjectOutputElement = element;
                                            break;
                                        }
                                    }

                                    if (javaProjectOutputElement != null) {
                                        break;
                                    }
                                }
                            }
                        }

                        if (javaProjectOutputElement != null) {
                            NodeList binChildren = javaProjectOutputElement.getChildNodes();
                            Element existingExcludeLib = null;
                            Element existingExcludeJavabuildpack = null;
                            if (binChildren != null) {

                                for (int i = 0; i < binChildren.getLength(); i++) {
                                    Node node = binChildren.item(i);
                                    if (node instanceof Element && node.getNodeName().equals("exclude")) { //$NON-NLS-1$
                                        Element excludeElement = (Element) node;
                                        Attr attr = excludeElement.getAttributeNode("name"); //$NON-NLS-1$
                                        if (attr != null && attr.getNodeValue() != null) {
                                            if (attr.getNodeValue().equals(libFolderName)) {
                                                existingExcludeLib = excludeElement;
                                            } else if (attr.getNodeValue().equals(javaBuildpackFolderName)) {
                                                existingExcludeJavabuildpack = excludeElement;
                                            }
                                        }
                                    }
                                }
                            }

                            Element updatedExcludeLib = null;
                            if (existingExcludeLib == null) {
                                updatedExcludeLib = doc.createElement("exclude"); //$NON-NLS-1$
                                updatedExcludeLib.setAttribute("name", libFolderName); //$NON-NLS-1$ 
                                javaProjectOutputElement.appendChild(updatedExcludeLib);
                            }
                            Element updatedExcludeJavabuildpack = null;
                            if (existingExcludeJavabuildpack == null) {
                                updatedExcludeJavabuildpack = doc.createElement("exclude"); //$NON-NLS-1$
                                updatedExcludeJavabuildpack.setAttribute("name", javaBuildpackFolderName); //$NON-NLS-1$ 
                                javaProjectOutputElement.appendChild(updatedExcludeJavabuildpack);
                            }
                            if (updatedExcludeLib != null || updatedExcludeJavabuildpack != null) {

                                final boolean[] proceed = { false };

                                final List<String> toexclude = new ArrayList<String>();
                                if (updatedExcludeLib != null) {
                                    toexclude.add(libFolderName);
                                }
                                if (updatedExcludeJavabuildpack != null) {
                                    toexclude.add(javaBuildpackFolderName);
                                }
                                Display.getDefault().syncExec(new Runnable() {

                                    public void run() {
                                        Shell shell = CloudUiUtil.getShell();

                                        proceed[0] = shell != null && !shell.isDisposed()
                                                && MessageDialog.openQuestion(shell,
                                                        Messages.CloudRebelUIHandler_TEXT_REPLACE_REBEL_XML_TITLE,
                                                        NLS.bind(
                                                                Messages.CloudRebelUIHandler_TEXT_REPLACE_REBEL_XML_BODY,
                                                                toexclude));
                                    }
                                });

                                if (proceed[0]) {
                                    // If replacing the exist rebel.xml file, be
                                    // sure to switch off automatic rebel.xml
                                    // generation
                                    project.setPersistentProperty(
                                            new QualifiedName("org.zeroturnaround.eclipse.jrebel", //$NON-NLS-1$
                                                    "autoGenerateRebelXml"), //$NON-NLS-1$
                                            "false"); //$NON-NLS-1$

                                    Transformer transformer = TransformerFactory.newInstance().newTransformer();
                                    transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
                                    DOMSource source = new DOMSource(doc);
                                    StreamResult console = new StreamResult(new File(path));
                                    transformer.transform(source, console);
                                    project.refreshLocal(IResource.DEPTH_INFINITE, monitor);
                                }
                            }
                        }
                    }
                }
            }
        } catch (ParserConfigurationException e) {
            CloudFoundryPlugin.logError(e);
        } catch (SAXException e) {
            CloudFoundryPlugin.logError(e);
        } catch (IOException e) {
            CloudFoundryPlugin.logError(e);
        } catch (TransformerException e) {
            CloudFoundryPlugin.logError(e);
        } catch (CoreException e) {
            CloudFoundryPlugin.logError(e);
        }
    }

    protected List<String> getClasspathSourceOutputPaths(IProject project) {

        IJavaProject javaProject = CloudFoundryProjectUtil.getJavaProject(project);
        List<String> outputPaths = new ArrayList<String>();
        if (javaProject != null) {
            try {
                IClasspathEntry[] classpath = javaProject.getResolvedClasspath(true);

                if (classpath != null) {
                    for (IClasspathEntry entry : classpath) {
                        if (entry != null && entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                            String outputPath = entry.getOutputLocation() != null
                                    ? entry.getOutputLocation().toString()
                                    : null;
                            if (outputPath != null && !outputPaths.contains(outputPath)
                                    && !outputPath.contains("target/test-classes")) {//$NON-NLS-1$
                                outputPaths.add(outputPath);
                            }
                        }
                    }
                }

                String outputPath = javaProject.getOutputLocation() != null
                        ? javaProject.getOutputLocation().toString()
                        : null;
                if (outputPath != null && !outputPaths.contains(outputPath)) {
                    outputPaths.add(outputPath);
                }
            } catch (JavaModelException e) {
                CloudFoundryPlugin.logError(e);
            }
        }

        return outputPaths;
    }

    protected IFile getRebelXMLFile(IProject project) {
        if (project != null && project.isAccessible()) {
            try {
                return getFile(project, "rebel.xml"); //$NON-NLS-1$
            } catch (CoreException e) {
                CloudFoundryPlugin.logError(e);
            }
        }

        return null;
    }

    protected IFile getFile(IResource resource, String fileName) throws CoreException {

        if (resource instanceof IFile && resource.getName().equals(fileName)) {
            return (IFile) resource;
        } else if (resource instanceof IContainer) {
            IContainer container = (IContainer) resource;
            IResource[] children = container.members();

            if (children != null) {
                for (IResource child : children) {

                    IFile file = getFile(child, fileName);
                    if (file != null) {
                        return file;
                    }
                }
            }
        }

        return null;
    }
}