blob: 956e50678c78191677693db670f96633e95d9234 [file] [log] [blame]
/*******************************************************************************
* 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();
}
}