001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     matic
016 */
017package org.nuxeo.runtime.tomcat.dev;
018
019import java.io.File;
020import java.lang.reflect.Method;
021
022/**
023 * Invokes the ReloadService by reflection as this module does not have access to the runtime context.
024 *
025 * @author matic
026 * @since 5.5
027 */
028public class ReloadServiceInvoker {
029
030    protected Object reloadService;
031
032    protected Method deployBundle;
033
034    protected Method undeployBundle;
035
036    /**
037     * Method to run the deployment preprocessor, previously handled by the deployBundle method
038     *
039     * @since 5.6
040     */
041    protected Method runDeploymentPreprocessor;
042
043    /**
044     * Method to install local web resources, as the deployment preprocessor won't see dev bundles as defined by Nuxeo
045     * IDE
046     *
047     * @since 5.6
048     */
049    protected Method installWebResources;
050
051    protected Method flush;
052
053    protected Method reload;
054
055    protected Method flushSeam;
056
057    protected Method reloadSeam;
058
059    public ReloadServiceInvoker(ClassLoader cl) throws ReflectiveOperationException {
060        Class<?> frameworkClass = cl.loadClass("org.nuxeo.runtime.api.Framework");
061        Class<?> reloadServiceClass = cl.loadClass("org.nuxeo.runtime.reload.ReloadService");
062        Method getLocalService = frameworkClass.getDeclaredMethod("getLocalService", new Class<?>[] { Class.class });
063        reloadService = getLocalService.invoke(null, new Object[] { reloadServiceClass });
064        deployBundle = reloadServiceClass.getDeclaredMethod("deployBundle", new Class<?>[] { File.class });
065        undeployBundle = reloadServiceClass.getDeclaredMethod("undeployBundle", new Class<?>[] { String.class });
066        runDeploymentPreprocessor = reloadServiceClass.getDeclaredMethod("runDeploymentPreprocessor", new Class<?>[0]);
067        installWebResources = reloadServiceClass.getDeclaredMethod("installWebResources", new Class<?>[] { File.class });
068        flush = reloadServiceClass.getDeclaredMethod("flush", new Class<?>[0]);
069        reload = reloadServiceClass.getDeclaredMethod("reload", new Class<?>[0]);
070        flushSeam = reloadServiceClass.getDeclaredMethod("flushSeamComponents", new Class<?>[0]);
071        reloadSeam = reloadServiceClass.getDeclaredMethod("reloadSeamComponents", new Class<?>[0]);
072    }
073
074    public void hotDeployBundles(DevBundle[] bundles) throws ReflectiveOperationException {
075        ClassLoader cl = Thread.currentThread().getContextClassLoader();
076        try {
077            Thread.currentThread().setContextClassLoader(reloadService.getClass().getClassLoader());
078            flush();
079            boolean hasSeam = false;
080            // rebuild existing war, this will remove previously copied web
081            // resources
082            // commented out for now, see NXP-9642
083            // runDeploymentPreprocessor();
084            for (DevBundle bundle : bundles) {
085                if (bundle.devBundleType == DevBundleType.Bundle) {
086                    bundle.name = (String) deployBundle.invoke(reloadService, new Object[] { bundle.file() });
087                    // install its web resources
088                    installWebResources.invoke(reloadService, new Object[] { bundle.file() });
089                } else if (bundle.devBundleType.equals(DevBundleType.Seam)) {
090                    hasSeam = true;
091                }
092            }
093            if (hasSeam) {
094                reloadSeam();
095            }
096            reload();
097        } finally {
098            Thread.currentThread().setContextClassLoader(cl);
099        }
100    }
101
102    public void hotUndeployBundles(DevBundle[] bundles) throws ReflectiveOperationException {
103        ClassLoader cl = Thread.currentThread().getContextClassLoader();
104        try {
105            Thread.currentThread().setContextClassLoader(reloadService.getClass().getClassLoader());
106            boolean hasSeam = false;
107            for (DevBundle bundle : bundles) {
108                if (bundle.devBundleType.equals(DevBundleType.Bundle) && bundle.name != null) {
109                    undeployBundle.invoke(reloadService, new Object[] { bundle.name });
110                } else if (bundle.devBundleType.equals(DevBundleType.Seam)) {
111                    hasSeam = true;
112                }
113            }
114            // run deployment preprocessor again: this will remove potential
115            // resources that were copied in the war at deploy
116            // commented out for now, see NXP-9642
117            // runDeploymentPreprocessor();
118            if (hasSeam) {
119                flushSeam.invoke(reloadService);
120            }
121        } finally {
122            Thread.currentThread().setContextClassLoader(cl);
123        }
124    }
125
126    protected void flush() throws ReflectiveOperationException {
127        flush.invoke(reloadService);
128    }
129
130    protected void reload() throws ReflectiveOperationException {
131        reload.invoke(reloadService);
132    }
133
134    protected void reloadSeam() throws ReflectiveOperationException {
135        reloadSeam.invoke(reloadService);
136    }
137
138    protected void runDeploymentPreprocessor() throws ReflectiveOperationException {
139        runDeploymentPreprocessor.invoke(reloadService);
140    }
141
142}