/* license-start * * Copyright (C) 2008 - 2013 Crispico, <http://www.crispico.com/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details, at <http://www.gnu.org/licenses/>. * * Contributors: * Crispico - Initial API and implementation * * license-end */ package org.flowerplatform.communication; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.servlet.Servlet; import javax.servlet.http.HttpServletRequest; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.Platform; import org.flowerplatform.common.plugin.AbstractFlowerJavaPlugin; import org.flowerplatform.common.util.RunnableWithParam; import org.flowerplatform.communication.channel.CommunicationChannelManager; import org.flowerplatform.communication.service.ServiceRegistry; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkEvent; import org.osgi.framework.FrameworkListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Cristi */ public class CommunicationPlugin extends AbstractFlowerJavaPlugin { private Logger logger = LoggerFactory.getLogger(CommunicationPlugin.class); protected static CommunicationPlugin INSTANCE; public static CommunicationPlugin getInstance() { return INSTANCE; } public static final String SERVLET_EXTENSION_POINT = "org.flowerplatform.communication.servlet"; public static final String SERVICE_EXTENSION_POINT = "org.flowerplatform.communication.service"; /** * @author Mariana */ public static final String AUTHENTICATOR_EXTENSION_POINT = "org.flowerplatform.communication.authenticator"; private List<ServletMapping> servletMappings; private CommunicationChannelManager communicationChannelManager = new CommunicationChannelManager(); private ServiceRegistry serviceRegistry = new ServiceRegistry(); private List<Runnable> allServicesStartedListeners = new ArrayList<Runnable>(); /** * @author Mariana */ private IAuthenticator authenticator; private ScheduledExecutorServiceFactory scheduledExecutorServiceFactory = new ScheduledExecutorServiceFactory(); public List<ServletMapping> getServletMappings() { return servletMappings; } public CommunicationChannelManager getCommunicationChannelManager() { return communicationChannelManager; } public ServiceRegistry getServiceRegistry() { return serviceRegistry; } /** * @author Mariana */ public IAuthenticator getAuthenticator() { return authenticator; } public ScheduledExecutorServiceFactory getScheduledExecutorServiceFactory() { return scheduledExecutorServiceFactory; } public List<Runnable> getAllServicesStartedListeners() { return allServicesStartedListeners; } public static final ThreadLocal<IPrincipal> tlCurrentPrincipal = new ThreadLocal<IPrincipal>(); /** * @author Cristian Spiescu * @author Mariana Gheorghe */ @Override public void start(BundleContext bundleContext) throws Exception { super.start(bundleContext); INSTANCE = this; initExtensionPoint_servlet(); initExtensionPoint_authenticator(); if (bundleContext.getBundle(0).getState() == Bundle.ACTIVE) { // If Eclipse is already started before this plugin is activated // (happens during testing or // running the app from the IDE), it's safe to start the services. initializeServicesAndNotifyServicesStartedListeners(); } else { // Wait until Eclipse is started (see comment below). bundleContext.addFrameworkListener(new FrameworkListener() { @Override public void frameworkEvent(FrameworkEvent event) { if (event.getType() != FrameworkEvent.STARTLEVEL_CHANGED) { return; } CommunicationPlugin.this.initializeServicesAndNotifyServicesStartedListeners(); } }); } } protected void initializeServicesAndNotifyServicesStartedListeners() { try { // When STARTLEVEL_CHANGED event happens, Eclipse seems to have finished starting. // It is now that we start the services. If we didn't do this, e.g. of thing that // would go wrong: this plugin is activated because FlowerDispatcherServlet is referenced // (is superclass) of EclipseDispatcherServlet, which is referenced somewhere in the // initializer or constructor of WebPlugin. => the services would be instantiated, including // some services from .web, which would want to use the resourceBundle, which hasn't been // yet initialized because WebPlugin.start() hasn't been called yet. initExtensionPoint_service(); // notify the listeners that the services have been started for (Runnable listener : allServicesStartedListeners) { listener.run(); } } catch (CoreException e) { throw new RuntimeException(e); } } @SuppressWarnings("unchecked") protected void initExtensionPoint_servlet() throws CoreException { servletMappings = new ArrayList<ServletMapping>(); IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor(SERVLET_EXTENSION_POINT); for (IConfigurationElement configurationElement : configurationElements) { ServletMapping servletMapping = new ServletMapping(); servletMapping.priority = Integer.parseInt(configurationElement.getAttribute("priority")); servletMapping.mappingEvaluator = (RunnableWithParam<Boolean, HttpServletRequest>) configurationElement.createExecutableExtension("mappingEvaluator"); servletMapping.servlet = (Servlet) configurationElement.createExecutableExtension("servlet"); servletMappings.add(servletMapping); logger.debug("Added servlet mapping with priority = {} for servlet class = {}", servletMapping.priority, servletMapping.servlet.getClass()); } Collections.sort(servletMappings, new Comparator<ServletMapping>() { @Override public int compare(ServletMapping arg0, ServletMapping arg1) { return Integer.compare(arg0.priority, arg1.priority); } }); } protected void initExtensionPoint_service() throws CoreException { IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor(SERVICE_EXTENSION_POINT); for (IConfigurationElement configurationElement : configurationElements) { String id = configurationElement.getAttribute("id"); Object serviceInstance = configurationElement.createExecutableExtension("serviceClass"); getServiceRegistry().registerService(id, serviceInstance); logger.debug("Added service with id = {} with class = {}", id, serviceInstance.getClass()); } } /** * @author Mariana */ protected void initExtensionPoint_authenticator() throws CoreException { IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor(AUTHENTICATOR_EXTENSION_POINT); for (IConfigurationElement configurationElement : configurationElements) { String id = configurationElement.getAttribute("id"); Object authenticatorInstance = configurationElement.createExecutableExtension("authenticatorClass"); authenticator = (IAuthenticator) authenticatorInstance; logger.debug("Added authenticator with id = {} with class = {}", id, authenticatorInstance.getClass()); } } public void stop(BundleContext bundleContext) throws Exception { scheduledExecutorServiceFactory.dispose(); super.stop(bundleContext); INSTANCE = null; } @Override public void registerMessageBundle() throws Exception { // do nothing, because we don't have messages (yet) } }