001/*
002 * (C) Copyright 2006-2010 Nuxeo SAS (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 *     bstefanescu
016 */
017package org.nuxeo.ecm.webengine.app;
018
019import java.io.File;
020import java.io.IOException;
021import java.util.Map;
022
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025import org.nuxeo.common.utils.FileUtils;
026import org.nuxeo.common.utils.Path;
027import org.nuxeo.common.utils.PathFilter;
028import org.nuxeo.common.utils.ZipUtils;
029import org.nuxeo.ecm.webengine.WebEngine;
030import org.nuxeo.osgi.BundleManifestReader;
031import org.nuxeo.runtime.api.Framework;
032import org.osgi.framework.Bundle;
033import org.osgi.framework.BundleContext;
034import org.osgi.framework.ServiceReference;
035import org.osgi.service.packageadmin.PackageAdmin;
036
037/**
038 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
039 */
040public class WebEngineModuleFactory {
041
042    public static Log log = LogFactory.getLog(WebEngineModuleFactory.class);
043
044    public static Bundle[] getFragments(Bundle bundle) {
045        BundleContext context = bundle.getBundleContext();
046        ServiceReference ref = context.getServiceReference(PackageAdmin.class.getName());
047        PackageAdmin admin = (PackageAdmin) context.getService(ref);
048        return admin.getFragments(bundle);
049    }
050
051    public static WebEngineModule getApplication(WebEngineModule app, Bundle bundle, Map<String, String> attrs)
052            throws ReflectiveOperationException, IOException {
053        WebEngine engine = Framework.getLocalService(WebEngine.class);
054
055        boolean explode = true;
056        if (attrs != null) {
057            if ("false".equals(attrs.get("explode"))) {
058                explode = false;
059            }
060        }
061        // register the web engine
062
063        File moduleDir = locateModuleDir(bundle, engine, explode);
064
065        app.init(engine, bundle, new File(moduleDir, "module.xml"), attrs);
066
067        app.cfg.directory = moduleDir;
068
069        Bundle[] fragments = getFragments(bundle);
070        for (Bundle fragment : fragments) {
071            File fragmentDir = locateModuleDir(fragment, engine, explode);
072            app.cfg.fragmentDirectories.add(fragmentDir);
073        }
074        app.cfg.allowHostOverride = Boolean.parseBoolean((String) bundle.getHeaders().get(
075                BundleManifestReader.ALLOW_HOST_OVERRIDE));
076        engine.addApplication(app);
077
078        log.info("Deployed web module found in bundle: " + bundle.getSymbolicName());
079
080        return app;
081    }
082
083    private static File locateModuleDir(Bundle bundle, WebEngine engine, boolean explode) throws IOException {
084        File moduleDir = null;
085        File bundleFile = Framework.getRuntime().getBundleFile(bundle);
086        if (explode) {
087            // this will also add the exploded directory to WebEngine class
088            // loader
089            moduleDir = explodeBundle(engine, bundle, bundleFile);
090        } else if (bundleFile.isDirectory()) {
091            moduleDir = bundleFile;
092        }
093        return moduleDir;
094    }
095
096    private static File explodeBundle(WebEngine engine, Bundle bundle, File bundleFile) throws IOException {
097        if (bundleFile.isDirectory()) { // exploded jar - deploy it as is.
098            return bundleFile;
099        } else { // should be a JAR - we copy the bundle module content
100            File moduleRoot = new File(engine.getRootDirectory(), "modules/" + bundle.getSymbolicName());
101            if (moduleRoot.exists()) {
102                if (bundleFile.lastModified() < moduleRoot.lastModified()) {
103                    // already deployed and JAR was not modified since.
104                    return moduleRoot;
105                }
106                // remove existing files
107                FileUtils.deleteTree(moduleRoot);
108            }
109            // create the module root
110            moduleRoot.mkdirs();
111            // avoid unziping classes
112            ZipUtils.unzip(bundleFile, moduleRoot, new PathFilter() {
113                @Override
114                public boolean isExclusive() {
115                    return false;
116                }
117
118                @Override
119                public boolean accept(Path arg0) {
120                    return !arg0.lastSegment().endsWith(".class");
121                }
122            });
123            return moduleRoot;
124        }
125    }
126
127}