All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.osgihttp.Activator Maven / Gradle / Ivy

There is a newer version: 1.0.8
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2009-2012 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package org.glassfish.osgihttp;

import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.config.serverbeans.VirtualServer;
import com.sun.enterprise.web.WebContainer;
import com.sun.enterprise.web.WebModule;
import com.sun.enterprise.web.WebModuleConfig;
import org.apache.catalina.*;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.session.StandardManager;
import org.apache.catalina.startup.ContextConfig;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.embeddable.GlassFish;
import org.glassfish.embeddable.GlassFishException;
import org.glassfish.internal.api.ClassLoaderHierarchy;
import org.glassfish.osgijavaeebase.Extender;
import org.glassfish.web.valve.GlassFishValve;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.http.HttpService;
import org.osgi.util.tracker.ServiceTracker;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * This is the entry point to our implementation of OSGi/HTTP service.
 * For every virtual server in the configuration, it creates HTTPService.
 * Every service has same context path. The context path can be defined
 * by user using configuration property org.glassfish.web.osgihttp.ContextPath.
 * If it is absent, we use a default value of "/osgi." After initializing
 * the HttpService factory with necessary details, we register the factory
 * OSGi service registry.
 *
 * @author [email protected]
 */
public class Activator implements BundleActivator {

    // TODO(Sahoo): Use config admin to configure context path, virtual server, etc.

    private BundleContext bctx;
    private Map vss = new HashMap();
    private String contextPath;
    private List registrations = new ArrayList();

    // configuration property used to select context root under which
    // this service is deployed.
    private static final String CONTEXT_PATH_PROP =
            Activator.class.getPackage().getName() + ".ContextPath";

    private Logger logger = Logger.getLogger(getClass().getPackage().getName());
    private GlassFish gf;
    private ServiceRegistration extenderReg;

    public void start(BundleContext context) throws Exception {
        bctx = context;
        Extender extender = new OSGiHtttpExtender();
        extenderReg = context.registerService(Extender.class.getName(), extender, null);
    }

    /**
     * This method is responsible for registering a HTTPService for every virtual server.
     * Each service is registered with a service property called "VirtualServer," which can be used by clients
     * to select a service. e.g., web console can use this to select __asadmin virtual server.
     * While registering the service for the default virtual server, it sets the service.ranking
     * to the maximum value so that any client just looking for an HTTPService gets to see the
     * HTTPService bound to default virtual server.
     *
     * @param webContainer
     */
    private void doActualWork(WebContainer webContainer) throws GlassFishException {
        String defaultVsId = getDefaultVirtualServer();
        final StringTokenizer vsIds = new StringTokenizer(getAllVirtualServers(), ",");
        while (vsIds.hasMoreTokens()) {
            String vsId = vsIds.nextToken().trim();
            try {
                WebModule standardContext = createRootWebModule(webContainer, vsId);
                if (standardContext == null) {
                    logger.logp(Level.WARNING, "Activator", "doActualWork",
                            "GlassFishHttpService will not be available for for virtual server = {0}, " +
                                    "because we are not able to create root web app.", new Object[]{vsId});
                    continue;
                }
                GlassFishHttpService httpService = new GlassFishHttpService(standardContext);
                Properties props = new Properties();
                props.put("VirtualServer", vsId);
                if (vsId.equals(defaultVsId)) {
                    props.put(Constants.SERVICE_RANKING, Integer.MAX_VALUE);
                }
                ServiceRegistration registration = bctx.registerService(HttpService.class.getName(),
                        new HttpServiceWrapper.HttpServiceFactory(httpService),
                        props);
                registrations.add(registration);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private WebModule createRootWebModule(WebContainer webContainer, String vsId) throws Exception {
        Engine engine = webContainer.getEngine();
        Host vs = (Host) engine.findChild(vsId);
        if (vs == null) return null; // this can happen if some one deleted a virtual server after we read domain.xml
        vss.put(vsId, vs);
        contextPath = bctx.getProperty(CONTEXT_PATH_PROP);
        if (contextPath == null) {
            contextPath = "/osgi"; // default value
        }
        // create a new context under which all OSGi HTTP wrappers
        // will be registered.
        final WebModule standardContext = new WebModule();
        standardContext.setWebContainer(webContainer);
        standardContext.setName(contextPath);
        standardContext.setPath(contextPath);
        // TODO(Sahoo): Need to set proper values for these directories
        standardContext.setDocBase(System.getProperty("java.io.tmpdir"));
        standardContext.setWorkDir(System.getProperty("java.io.tmpdir"));
        // standardContext.setJ2EEServer(System.getProperty("com.sun.aas.instanceName"));
        standardContext.setJ2EEServer(getInstanceName());
        standardContext.addLifecycleListener(new ContextConfig());
        Realm realm = gf.getService(Realm.class);
        standardContext.setRealm(realm);
        WebModuleConfig wmConfig = new WebModuleConfig();
        wmConfig.setWorkDirBase(System.getProperty("java.io.tmpdir"));
        wmConfig.setVirtualServers(vsId);

        // Setting it in WebModuleConfig does not work, Ceck with Jan.
//        wmConfig.setAppClassLoader(getCommonClassLoader());
        standardContext.setParentClassLoader(getCommonClassLoader(gf));
        standardContext.setWebModuleConfig(wmConfig);

        // See  See GLASSFISH-16764 for more details about this valve
        standardContext.addValve((GlassFishValve) new OSGiHttpContextValve());
        // Since there is issue about locating user classes that are part
        // of some OSGi bundle while deserializing, we switch off session
        // persistence.
        switchOffSessionPersistence(standardContext);
        vs.addChild(standardContext);
        logger.logp(Level.INFO, "Activator", "createRootWebModule", "standardContext = {0}",
                new Object[]{standardContext});
        return standardContext;
    }

    private ClassLoader getCommonClassLoader(GlassFish gf) throws GlassFishException {
        ClassLoaderHierarchy clh =
                gf.getService(ClassLoaderHierarchy.class);
        return clh.getAPIClassLoader();
    }

    public void stop(BundleContext context) throws Exception {
        extenderReg.unregister();
        // let everything else happen in Extender.stop which will get called by ExtenderManager.stop()
    }

    private void undoActualWork() {
        for (ServiceRegistration registration : registrations) registration.unregister();
        for (Host vs : vss.values()) {
            StandardContext standardContext =
                    StandardContext.class.cast(vs.findChild(contextPath));
            if (standardContext == null) {
                continue;
            }
            for (Container child : standardContext.findChildren()) {
                standardContext.removeChild(child);
            }
            vs.removeChild(standardContext);
        }
        // TODO(Sahoo): Need to call stop on all wrappers if they are not
        // automatically stopped when removed from context.
    }

    private void switchOffSessionPersistence(StandardContext ctx) {
        // See Jan's blog about how to switch off
        // Session persistence:
        // http://blogs.sun.com/jluehe/entry/how_to_disable_persisting_of
        Manager mgr = ctx.getManager();
        if (mgr == null) {
            mgr = new StandardManager();
            StandardManager.class.cast(mgr).setPathname(null);
            ctx.setManager(mgr);
        } else {
            try {
                StandardManager.class.cast(mgr).setPathname(null);
            } catch (ClassCastException cce) {
                logger.logp(Level.INFO, "Activator", "switchOffSessionPersistence",
                        "SessionManager {0} does not allow path name of session store to be configured.",
                        new Object[]{mgr});
            }
        }
    }

    /**
     * @return comma-separated list of all defined virtual servers (including __asadmin)
     */
    private String getAllVirtualServers() throws GlassFishException {
        StringBuilder sb = new StringBuilder();
        boolean first = true;
        Domain domain = gf.getService(Domain.class);
        String target = getInstanceName();
        Server server = domain.getServerNamed(target);
        if (server != null) {
            Config config = server.getConfig();
            if (config != null) {
                com.sun.enterprise.config.serverbeans.HttpService httpService = config.getHttpService();
                if (httpService != null) {
                    List hosts = httpService.getVirtualServer();
                    if (hosts != null) {
                        for (VirtualServer host : hosts) {
                            if (first) {
                                sb.append(host.getId());
                                first = false;
                            } else {
                                sb.append(",");
                                sb.append(host.getId());
                            }
                        }
                    }
                }
            }
        }
        return sb.toString();
    }

    private String getInstanceName() throws GlassFishException {
        ServerEnvironment se = gf.getService(ServerEnvironment.class);
        String target = se.getInstanceName();
        return target;
    }

    /**
     * @return the dafault virtual server
     */
    private String getDefaultVirtualServer() throws GlassFishException {
        // Grizzly renamed its package name from com.sun.grizzly to org.glassfish.grizzly in Grizzly 2.1. Since Grizzly 2.1 is only
        // integrated into GF3.2 only and we expect our module to work with GF 3.1.1 as well, we are not relying on Grizzly classes statically.
        // So, the code below does what the following line would have done.
        // return Globals.get(com.sun.grizzly.config.dom.NetworkListener.class).findHttpProtocol().getHttp().getDefaultVirtualServer();
        Class netWorkListenerClass;
        try {
            netWorkListenerClass = Class.forName("com.sun.grizzly.config.dom.NetworkListener");
        } catch (ClassNotFoundException cnfe) {
            try {
                netWorkListenerClass = Class.forName("org.glassfish.grizzly.config.dom.NetworkListener");
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        }
        Object networkListenerObj = gf.getService(netWorkListenerClass);
        try {
            Method findHttpProtocolMethod = netWorkListenerClass.getMethod("findHttpProtocol");
            Object httpProtocolObj = findHttpProtocolMethod.invoke(networkListenerObj);
            final Object httpObj = httpProtocolObj.getClass().getMethod("getHttp").invoke(httpProtocolObj);
            final String defaultVirtualServer = (String) httpObj.getClass().getMethod("getDefaultVirtualServer").invoke(httpObj);
            logger.logp(Level.INFO, "Activator", "getDefaultVirtualServer", "defaultVirtualServer = {0}",
                    new Object[]{defaultVirtualServer});
            return defaultVirtualServer;
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    private class OSGiHtttpExtender implements Extender {
        private GlassFish getGlassFish() {
            GlassFish gf = (GlassFish) bctx.getService(bctx.getServiceReference(GlassFish.class.getName()));
            try {
                assert(gf.getStatus() == GlassFish.Status.STARTED);
            } catch (GlassFishException e) {
                throw new RuntimeException(e); // TODO(Sahoo): Proper Exception Handling
            }
            return gf;
        }

        private WebContainer getWebContainer() throws GlassFishException {
            return gf.getService(WebContainer.class);
        }

        @Override
        public void start() {
            gf = getGlassFish();
            try {
                doActualWork(getWebContainer());
            } catch (GlassFishException e) {
                throw new RuntimeException(e); // TODO(Sahoo): Proper Exception Handling
            }
        }

        @Override
        public void stop() {
            undoActualWork();
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy