| /******************************************************************************* |
| * Copyright (c) 2011, 2012 Frank Appel and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Frank Appel - initial API and implementation |
| * EclipseSource - ongoing development |
| ******************************************************************************/ |
| package org.eclipse.rap.rwt.osgi.internal; |
| |
| import java.io.File; |
| |
| import org.eclipse.rap.rwt.osgi.ApplicationReference; |
| import org.eclipse.rap.rwt.osgi.ApplicationLauncher; |
| import org.eclipse.rap.rwt.osgi.internal.ServiceContainer.ServiceHolder; |
| import org.eclipse.rwt.application.ApplicationConfiguration; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.service.http.HttpContext; |
| import org.osgi.service.http.HttpService; |
| import org.osgi.service.log.LogService; |
| |
| |
| public class ApplicationLauncherImpl implements ApplicationLauncher { |
| |
| private final Object lock; |
| private final ServiceContainer<ApplicationConfiguration> configurations; |
| private final ServiceContainer<HttpService> httpServices; |
| private final ApplicationReferencesContainer applicationReferences; |
| private BundleContext bundleContext; |
| |
| public ApplicationLauncherImpl( BundleContext bundleContext ) { |
| lock = new Object(); |
| configurations = new ServiceContainer<ApplicationConfiguration>( bundleContext ); |
| httpServices = new ServiceContainer<HttpService>( bundleContext ); |
| applicationReferences = new ApplicationReferencesContainer(); |
| this.bundleContext = bundleContext; |
| } |
| |
| public HttpService addHttpService( ServiceReference<HttpService> reference ) { |
| ServiceHolder<HttpService> httpServiceHolder; |
| synchronized( lock ) { |
| httpServiceHolder = httpServices.add( reference ); |
| launchAtHttpService( httpServiceHolder ); |
| } |
| return httpServiceHolder.getService(); |
| } |
| |
| public void removeHttpService( HttpService httpService ) { |
| synchronized( lock ) { |
| httpServices.remove( httpService ); |
| stopApplicationReferences( httpService ); |
| } |
| } |
| |
| public ApplicationConfiguration addConfiguration( ServiceReference<ApplicationConfiguration> ref ) |
| { |
| ServiceHolder<ApplicationConfiguration> configurationHolder; |
| synchronized( lock ) { |
| configurationHolder = configurations.add( ref ); |
| launchWithConfiguration( configurationHolder ); |
| } |
| return configurationHolder.getService(); |
| } |
| |
| public void removeConfiguration( ApplicationConfiguration configuration ) { |
| synchronized( lock ) { |
| configurations.remove( configuration ); |
| stopApplicationReferences( configuration ); |
| } |
| } |
| |
| public ApplicationReference launch( ApplicationConfiguration configuration, |
| HttpService httpService, |
| HttpContext httpContext, |
| String contextName, |
| String contextDirectory ) |
| { |
| synchronized( lock ) { |
| ApplicationReference result = null; |
| if( isAlive() ) { |
| result = doLaunch( configuration, httpService, httpContext, contextName, contextDirectory ); |
| } |
| return result; |
| } |
| } |
| |
| private ApplicationReferenceImpl doLaunch( ApplicationConfiguration configuration, |
| HttpService httpService, |
| HttpContext httpContext, |
| String contextName, |
| String contextDirectory ) |
| { |
| ApplicationReferenceImpl result = new ApplicationReferenceImpl( configuration, |
| httpService, |
| httpContext, |
| contextName, |
| contextDirectory, |
| this ); |
| result.start(); |
| applicationReferences.add( result ); |
| httpServices.add( httpService ); |
| configurations.add( configuration ); |
| return result; |
| } |
| |
| |
| public void deactivate() { |
| synchronized( lock ) { |
| stopAllApplicationReferences(); |
| configurations.clear(); |
| applicationReferences.clear(); |
| httpServices.clear(); |
| bundleContext = null; |
| } |
| } |
| |
| boolean isAlive() { |
| return bundleContext != null; |
| } |
| |
| void notifyContextAboutToStop( ApplicationReferenceImpl applicationReference ) { |
| synchronized( lock ) { |
| applicationReferences.remove( applicationReference ); |
| } |
| } |
| |
| BundleContext getBundleContext() { |
| return bundleContext; |
| } |
| |
| private void launchAtHttpService( ServiceHolder<HttpService> httpServiceHolder ) { |
| ServiceHolder<ApplicationConfiguration>[] services = configurations.getServices(); |
| for( ServiceHolder<ApplicationConfiguration> configurationHolder : services ) { |
| if( matches( httpServiceHolder, configurationHolder ) ) { |
| launch( configurationHolder, httpServiceHolder ); |
| } |
| } |
| } |
| |
| private void launchWithConfiguration( ServiceHolder<ApplicationConfiguration> configurationHolder ) |
| { |
| ServiceHolder<HttpService>[] services = httpServices.getServices(); |
| for( ServiceHolder<HttpService> httpServiceHolder : services ) { |
| if( matches( httpServiceHolder, configurationHolder ) ) { |
| launch( configurationHolder, httpServiceHolder ); |
| } |
| } |
| } |
| |
| private void launch( ServiceHolder<ApplicationConfiguration> configurationHolder, |
| ServiceHolder<HttpService> httpServiceHolder ) |
| { |
| ApplicationConfiguration configuration = configurationHolder.getService(); |
| HttpService httpService = httpServiceHolder.getService(); |
| String contextName = getContextName( configurationHolder ); |
| String contextLocation = getLocation( contextName, configuration, httpService ); |
| try { |
| launch( configuration, httpService, null, contextName, contextLocation ); |
| } catch( RuntimeException rte ) { |
| logProblem( "Unable to start RWT application.", rte ); |
| } |
| } |
| |
| private String getContextName( ServiceHolder<ApplicationConfiguration> configurationHolder ) { |
| ServiceReference<ApplicationConfiguration> reference = configurationHolder.getReference(); |
| return ( String )reference.getProperty( PROPERTY_CONTEXT_NAME ); |
| } |
| |
| private void stopApplicationReferences( Object service ) { |
| ApplicationReferenceImpl[] iterator = applicationReferences.getAll(); |
| for( ApplicationReferenceImpl applicationReference : iterator ) { |
| if( applicationReference.belongsTo( service ) ) { |
| stopApplicationReference( applicationReference ); |
| } |
| } |
| } |
| |
| private void stopAllApplicationReferences() { |
| ApplicationReferenceImpl[] all = applicationReferences.getAll(); |
| for( ApplicationReferenceImpl applicationReference : all ) { |
| stopApplicationReference( applicationReference ); |
| } |
| } |
| |
| void stopApplicationReference( ApplicationReferenceImpl applicationReference ) { |
| try { |
| applicationReference.stopApplication(); |
| } catch( RuntimeException rte ) { |
| logProblem( "Unable to stop ApplicationReference properly.", rte ); |
| } |
| } |
| |
| private boolean matches( ServiceHolder<HttpService> httpServiceHolder, |
| ServiceHolder<ApplicationConfiguration> configurationHolder ) |
| { |
| ServiceReference<HttpService> httpServiceRef = httpServiceHolder.getReference(); |
| ServiceReference<ApplicationConfiguration> configurationRef = configurationHolder.getReference(); |
| return new Matcher( httpServiceRef, configurationRef ).matches(); |
| } |
| |
| private void logProblem( String failureMessage, Throwable failure ) { |
| ServiceReference logReference = bundleContext.getServiceReference( LogService.class.getName() ); |
| if( logReference != null ) { |
| @SuppressWarnings( "unchecked" ) |
| LogService log = ( LogService )bundleContext.getService( logReference ); |
| log.log( LogService.LOG_ERROR, failureMessage, failure ); |
| } else { |
| // TODO [fappel]: is there a better solution? |
| System.err.println( failureMessage ); |
| failure.printStackTrace(); |
| } |
| } |
| |
| String getLocation( String contextName, |
| ApplicationConfiguration configuration, |
| HttpService service ) |
| { |
| String pathToContext = getContextFileName( contextName, configuration, service ); |
| File dataFile = bundleContext.getDataFile( pathToContext ); |
| return dataFile.toString(); |
| } |
| |
| static String getContextFileName( String name, |
| ApplicationConfiguration configuration, |
| HttpService service ) |
| { |
| StringBuilder result = new StringBuilder(); |
| result.append( name == null ? "rwtcontext" : name ); |
| result.append( "_" ); |
| result.append( configuration.hashCode() ); |
| result.append( "_" ); |
| result.append( service.hashCode() ); |
| return result.toString(); |
| } |
| } |