package com.eucalyptus.context;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.log4j.Logger;
import org.mule.RequestContext;
import org.mule.api.MuleContext;
import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.context.MuleContextFactory;
import org.mule.api.registry.Registry;
import org.mule.config.ConfigResource;
import org.mule.config.spring.SpringXmlConfigurationBuilder;
import org.mule.context.DefaultMuleContextFactory;
import org.mule.module.client.MuleClient;
import com.eucalyptus.bootstrap.Bootstrap;
import com.eucalyptus.bootstrap.BootstrapException;
import com.eucalyptus.bootstrap.Bootstrapper;
import com.eucalyptus.bootstrap.Component;
import com.eucalyptus.bootstrap.Provides;
import com.eucalyptus.bootstrap.RunDuring;
import com.eucalyptus.bootstrap.Bootstrap.Stage;
import com.eucalyptus.component.Components;
import com.eucalyptus.component.Resource;
import com.eucalyptus.configurable.ConfigurableClass;
import com.eucalyptus.configurable.ConfigurableField;
import com.eucalyptus.configurable.ConfigurableProperty;
import com.eucalyptus.event.PassiveEventListener;
import com.eucalyptus.util.EucalyptusCloudException;
import com.eucalyptus.util.LogUtil;
import com.google.common.collect.Lists;
@ConfigurableClass( root = "system", description = "Parameters having to do with the system's state. Mostly read-only." )
public class ServiceContext {
private static Logger LOG = Logger.getLogger( ServiceContext.class );
private static SpringXmlConfigurationBuilder builder;
@ConfigurableField( initial = "16", description = "Max queue length allowed per service stage.", changeListener = HupListener.class )
public static Integer MAX_OUTSTANDING_MESSAGES = 16;
@ConfigurableField( initial = "0", description = "Do a soft reset.", changeListener = HupListener.class )
public static Integer HUP = 0;
public static class HupListener extends PassiveEventListener<ConfigurableProperty> {
@Override
public void firingEvent( ConfigurableProperty t ) {
if ( "123".equals( t.getValue( ) ) ) {
System.exit( 123 );
}
}
}
private static AtomicReference<MuleContext> context = new AtomicReference<MuleContext>( null );
private static AtomicReference<MuleClient> client = new AtomicReference<MuleClient>( null );
private static final BootstrapException failEx = new BootstrapException( "Attempt to use esb client before the service bus has been started." );
private static MuleClient getClient( ) throws MuleException {
if( context.get( ) == null ) {
LOG.fatal( failEx, failEx );
System.exit( 123 );
throw failEx;
} else if( client.get( ) == null && client.compareAndSet( null, new MuleClient( context.get( ) ) ) ) {
return client.get( );
} else {
return client.get( );
}
}
public static void dispatch( String dest, Object msg ) {
MuleEvent context = RequestContext.getEvent( );
try {
ServiceContext.getClient( ).sendDirect( dest, null, msg, null );
} catch ( MuleException e ) {
LOG.error( e );
} finally {
RequestContext.setEvent( context );
}
}
public static <T> T send( String dest, Object msg ) throws EucalyptusCloudException {
MuleEvent context = RequestContext.getEvent( );
try {
MuleMessage reply = ServiceContext.getClient( ).sendDirect( dest, null, msg, null );
if ( reply.getExceptionPayload( ) != null ) throw new EucalyptusCloudException( reply.getExceptionPayload( ).getRootException( ).getMessage( ), reply.getExceptionPayload( ).getRootException( ) );
else return (T) reply.getPayload( );
} catch ( MuleException e ) {
LOG.error( e, e );
throw new EucalyptusCloudException( e );
} finally {
RequestContext.setEvent( context );
}
}
public static void buildContext( List<ConfigResource> configs ) {
ServiceContext.builder = new SpringXmlConfigurationBuilder( configs.toArray( new ConfigResource[] {} ) );
}
public static void createContext( ) {
MuleContextFactory contextFactory = new DefaultMuleContextFactory( );
try {
MuleContext context = contextFactory.createMuleContext( builder );
if ( !ServiceContext.context.compareAndSet( null, context ) ) {
throw new ServiceInitializationException( "Service context initialized twice." );
}
} catch ( Exception e ) {
LOG.error( e, e );
throw new ServiceInitializationException( "Failed to build service context.", e );
}
}
public static void startContext( ) {
try {
if ( !ServiceContext.getContext( ).isInitialised( ) ) {
ServiceContext.getContext( ).initialise( );
}
} catch ( Throwable e ) {
LOG.error( e, e );
throw new ServiceInitializationException( "Failed to initialize service context.", e );
}
try {
ServiceContext.getContext( ).start( );
} catch ( Throwable e ) {
LOG.error( e, e );
throw new ServiceInitializationException( "Failed to start service context.", e );
}
}
public static MuleContext getContext( ) {
if ( ServiceContext.context.get( ) == null ) {
throw new ServiceInitializationException( "Attempt to reference service context before it is ready." );
} else {
return context.get( );
}
}
public static Registry getRegistry( ) {
return ServiceContext.getContext( ).getRegistry( );
}
public static void stopContext( ) {
try {
ServiceContext.getContext( ).stop( );
ServiceContext.getContext( ).dispose( );
} catch ( Throwable e ) {
LOG.debug( e, e );
}
}
@Provides( Component.bootstrap )
@RunDuring( Bootstrap.Stage.CloudServiceInit )
public static class ServiceBootstrapper extends Bootstrapper {
public ServiceBootstrapper( ) {}
@Override
public boolean load( Stage current ) throws Exception {
List<ConfigResource> configs = Lists.newArrayList( );
for ( com.eucalyptus.component.Component comp : Components.list( ) ) {
if ( comp.isEnabled( ) ) {
Resource rsc = comp.getConfiguration( ).getResource( );
if( rsc != null ) {
LOG.info( LogUtil.subheader( "Preparing configuration for: " + rsc ) );
configs.addAll( rsc.getConfigurations( ) );
}
}
}
for ( ConfigResource cfg : configs ) {
LOG.info( "-> Loaded cfg: " + cfg.getUrl( ) );
}
try {
ServiceContext.buildContext( configs );
} catch ( Exception e ) {
LOG.fatal( "Failed to bootstrap services.", e );
return false;
}
return true;
}
@Override
public boolean start( ) throws Exception {
try {
LOG.info( "Starting up system bus." );
ServiceContext.createContext( );
} catch ( Exception e ) {
LOG.fatal( "Failed to configure services.", e );
return false;
}
try {
ServiceContext.startContext( );
} catch ( Exception e ) {
LOG.fatal( "Failed to start services.", e );
return false;
}
return true;
}
@Override
public boolean stop( ) throws Exception {
ServiceContext.stopContext( );
return true;
}
}
}