/*************************************************************************
* Copyright 2009-2015 Eucalyptus Systems, Inc.
*
* 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 of the License.
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*
* Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
* CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
* additional information or have any questions.
*
* This file may incorporate work covered under the following copyright
* and permission notice:
*
* Software License Agreement (BSD License)
*
* Copyright (c) 2008, Regents of the University of California
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms,
* with or without modification, are permitted provided that the
* following conditions are met:
*
* Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE
* THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL,
* COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE,
* AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING
* IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA,
* SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY,
* WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION,
* REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO
* IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT
* NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS.
************************************************************************/
package com.eucalyptus.component;
import java.net.InetAddress;
import java.util.List;
import java.util.NavigableSet;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import com.eucalyptus.system.Threads;
import org.apache.log4j.Logger;
import com.eucalyptus.bootstrap.Bootstrap;
import com.eucalyptus.bootstrap.Bootstrap.Stage;
import com.eucalyptus.bootstrap.Bootstrapper;
import com.eucalyptus.bootstrap.CanBootstrap;
import com.eucalyptus.records.EventRecord;
import com.eucalyptus.records.EventType;
import com.eucalyptus.records.Logs;
import com.eucalyptus.util.Exceptions;
import com.eucalyptus.auth.principal.FullName;
import com.eucalyptus.util.HasName;
import com.eucalyptus.util.Internets;
import com.eucalyptus.util.fsm.Automata;
import com.eucalyptus.util.fsm.OrderlyTransitionException;
import com.eucalyptus.util.fsm.StateMachine;
import com.eucalyptus.util.fsm.TransitionException;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
import javax.annotation.Nullable;
import static com.eucalyptus.util.Parameters.checkParam;
import static org.hamcrest.Matchers.notNullValue;
public class Component implements HasName<Component> {
private static Logger LOG = Logger.getLogger( Component.class );
public final ComponentId identity;
private final ServiceRegistry serviceRegistry;
private final ComponentBootstrapper bootstrapper;
public enum State implements Automata.State<State>, Predicate<ServiceConfiguration> {
BROKEN,
PRIMORDIAL,
INITIALIZED,
LOADED,
STOPPED,
NOTREADY,
DISABLED,
ENABLED;
@Override
public boolean apply( ServiceConfiguration input ) {
return this.equals( input.lookupState( ) );
}
}
public enum Transition implements Automata.Transition<Transition> {
INITIALIZING,
LOAD,
START,
READY_CHECK,
STOP,
STOPPING_NOTREADY,
STOPPING_BROKEN,
ENABLE,
ENABLED_CHECK,
DISABLE,
DISABLED_CHECK,
DESTROY,
FAILED_TO_PREPARE,
RELOAD,
REMOVING;
}
Component( ComponentId componentId ) throws ServiceRegistrationException {
this.identity = componentId;
this.serviceRegistry = new ServiceRegistry( );
this.bootstrapper = new ComponentBootstrapper( this );
}
/**
* @return the identity
*/
public ComponentId getComponentId( ) {
return this.identity;
}
public State getState( ) {
return this.hasLocalService( )
? this.getLocalServiceConfiguration( ).lookupState( )
: State.PRIMORDIAL;
}
/**
* Get the name of this component. This is the proper short name; e.g., 'eucalyptus', 'walrus',
* etc, as used in the META-INF descriptor file.
*
* @return Component name
*/
public String getName( ) {
return this.identity.name( );
}
public ServiceBuilder<? extends ServiceConfiguration> getBuilder( ) {
return ServiceBuilders.lookup( this.identity.getClass( ) );
}
public NavigableSet<ServiceConfiguration> services( ) {
return this.serviceRegistry.getServices( );
}
public Boolean hasLocalService( ) {
return this.serviceRegistry.hasLocalService( );
}
public Boolean isEnabledLocally( ) {
return this.serviceRegistry.hasLocalService( ) && State.ENABLED.equals( this.getLocalServiceConfiguration( ).lookupState( ) );
}
public Boolean isRunningLocally( ) {
return this.isEnabledLocally( );
}
/**
* @return the bootstrapper
*/
public CanBootstrap getBootstrapper( ) {
return this.bootstrapper;
}
public ServiceConfiguration lookup( String name ) {
return this.serviceRegistry.getService( name );
}
/**
* Builds a BasicService instance for this component using the local default
* values.
*
* @return BasicService instance of the service
* @throws ServiceRegistrationException
*/
public ServiceConfiguration initService( ) {
if ( !this.identity.isAvailableLocally( ) ) {
throw Exceptions.toUndeclared( "The component " + this.getName( ) + " is not being loaded automatically." );
} else {
return initRemoteService( Internets.localHostInetAddress( ) );
}
}
/**
* Builds a BasicService instance for this cloudLocal component when Eucalyptus is remote.
*
* @return BasicService instance of the service
* @throws ServiceRegistrationException
*/
public ServiceConfiguration initRemoteService( InetAddress addr ) {
ServiceConfiguration config = this.getBuilder( ).newInstance( this.getComponentId( ).getPartition( ), addr.getHostAddress( ), addr.getHostAddress( ),
this.getComponentId( ).getPort( ) );
BasicService ret = this.serviceRegistry.register( config );
Logs.extreme( ).debug( "Initializing remote service for host " + addr
+ " with configuration: "
+ config );
return config;
}
void destroy( final ServiceConfiguration configuration ) throws ServiceRegistrationException {
try {
BasicService service = null;
if ( this.serviceRegistry.hasService( configuration ) ) {
service = this.serviceRegistry.lookup( configuration );
}
try {
EventRecord.caller( Component.class, EventType.COMPONENT_SERVICE_DESTROY, this.getName( ), configuration.getFullName( ),
ServiceUris.remote( configuration ).toASCIIString( ) ).info( );
this.serviceRegistry.deregister( configuration );
} catch ( Exception ex ) {
throw new ServiceRegistrationException( "Failed to destroy service: " + configuration
+ " because of: "
+ ex.getMessage( ), ex );
}
} catch ( NoSuchElementException ex ) {
throw new ServiceRegistrationException( "Failed to find service corresponding to: " + configuration, ex );
}
}
/**
* Builds a BasicService instance for this component using the provided service
* configuration.
*
* @throws ServiceRegistrationException
*/
public void setup( final ServiceConfiguration config ) throws IllegalStateException {
if ( ( config.isVmLocal( ) || config.isHostLocal( ) ) && !this.serviceRegistry.hasLocalService( ) ) {
this.serviceRegistry.register( config );
} else if ( this.serviceRegistry.hasService( config ) ) {
this.serviceRegistry.lookup( config );
} else {
this.serviceRegistry.register( config );
}
}
public boolean hasService( ServiceConfiguration config ) {
return this.serviceRegistry.hasService( config );
}
public boolean updateService( ServiceConfiguration config ) {
if ( this.serviceRegistry.hasService( config ) ) {
final ServiceConfiguration registeredConfig = this.serviceRegistry.lookup( config ).getServiceConfiguration( );
ServiceConfigurations.update( registeredConfig, config );
return true;
}
return false;
}
/**
* @see java.lang.Object#toString()
*/
@Override
public String toString( ) {
return String.format( "Component %s=%s service=%s\n",
this.identity.name( ),
( this.identity.isAvailableLocally( )
? ""
: "not" ) + "available",
( this.serviceRegistry.hasLocalService( )
? this.serviceRegistry.getLocalService( )
: "not-local" ) );
}
/**
* Components are ordered by the lexicographic ordering of the name.
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
@Override
public int compareTo( Component that ) {
return this.getName( ).compareTo( that.getName( ) );
}
/**
* @see java.lang.Object#hashCode()
* @return
*/
@Override
public int hashCode( ) {
final int prime = 31;
int result = 1;
result = prime * result
+ ( ( this.identity == null )
? 0
: this.identity.hashCode( ) );
return result;
}
/**
* @see java.lang.Object#equals(java.lang.Object)
* @param obj
* @return
*/
@Override
public boolean equals( Object obj ) {
if ( this == obj ) {
return true;
}
if ( obj == null ) {
return false;
}
if ( getClass( ) != obj.getClass( ) ) {
return false;
}
Component other = ( Component ) obj;
if ( this.identity == null ) {
if ( other.identity != null ) {
return false;
}
} else if ( !this.identity.equals( other.identity ) ) {
return false;
}
return true;
}
class ServiceRegistry {
private final AtomicReference<BasicService> localService = new AtomicReference( null );
private final ConcurrentMap<ServiceConfiguration, BasicService> services = Maps.newConcurrentMap( );
public boolean hasLocalService( ) {
return this.localService.get( ) != null;
}
public BasicService getLocalService( ) {
BasicService ret = this.localService.get( );
if ( ret == null ) {
throw Exceptions.error( new NoSuchElementException( "Attempt to access a local service reference when none exists for: " + Component.this.toString( ) ) );
} else {
return ret;
}
}
/**
* Obtain a snapshot of the current service state. Note that this method creates a new set and
* changes to the returned set will not be reflected in the underlying services set.
*
* @return {@link NavigableSet<Service>} of the registered service of this {@link Component}
* type.
*/
public NavigableSet<ServiceConfiguration> getServices( ) {
return Sets.newTreeSet( this.services.keySet( ) );
}
/**
* Deregisters the service with the provided {@link FullName}.
*
* @param fullName
* @return {@link Service} instance of the deregistered service.
* @throws NoSuchElementException if no {@link Service} is registered with the provided
* {@link FullName}
*/
public BasicService deregister( ServiceConfiguration config ) throws NoSuchElementException {
BasicService ret = this.services.remove( config );
if ( ret == null ) {
throw new NoSuchElementException( "Failed to lookup service corresponding to full-name: " + config );
} else if ( config.isVmLocal( ) ) {
final Optional<ServiceConfiguration> newLocal =
Iterables.tryFind( this.services.keySet( ), ServiceConfigurations.filterVmLocal( ) );
if ( newLocal.isPresent( ) ) {
this.localService.compareAndSet( ret, this.services.get( newLocal.get( ) ) );
} else {
this.localService.compareAndSet( ret, null );
}
}
return ret;
}
/**
* Returns the {@link Service} instance which was registered with the provided
* {@link ServiceConfiguration}, if it exists. If a service with the given name
* does not exist a
* NoSuchElementException is thrown.
*
* @see #lookup(FullName)
* @param configuration
* @return {@link Service} corresponding to provided the {@link ServiceConfiguration}
* @throws NoSuchElementException
*/
public BasicService lookup( ServiceConfiguration config ) throws NoSuchElementException {
if ( !this.services.containsKey( config ) ) {
throw new NoSuchElementException( "Failed to lookup service corresponding to service configuration: " + config.getName( ) );
} else {
return this.services.get( config );
}
}
/**
* Register the given {@link Service} with the registry. Only used internally.
*
* @param service
* @throws ServiceRegistrationException
*/
BasicService register( ServiceConfiguration config ) {
LOG.debug( Threads.currentStackRange( 1, 5 ) );
BasicService service = this.services.containsKey( config ) ? this.services.get( config ) : new BasicService( config );
if ( config.isVmLocal( ) || config.isHostLocal( ) ) {
this.localService.set( service );
}
BasicService ret = this.services.putIfAbsent( config, service );
if ( ret == null ) {
ret = service;
try {
config.lookupStateMachine( ).transition( Component.State.INITIALIZED ).get( );
EventRecord.caller( Component.class, EventType.COMPONENT_SERVICE_REGISTERED,
Component.this.getName( ),
( config.isVmLocal( ) || config.isHostLocal( ) )
? "local"
: "remote",
config.toString( ) ).info( );
} catch ( Exception ex ) {
Logs.extreme( ).error( ex, ex );
}
} else {
if ( ret.getStateMachine( ).getState( ).ordinal( ) < Component.State.INITIALIZED.ordinal( ) ) {
try {
config.lookupStateMachine( ).transition( Component.State.INITIALIZED ).get( );
EventRecord.caller( Component.class, EventType.COMPONENT_SERVICE_REGISTERED,
Component.this.getName( ),
( config.isVmLocal( ) || config.isHostLocal( ) )
? "local"
: "remote",
config.toString( ) ).info( );
} catch ( Exception ex ) {
Logs.extreme( ).error( ex, ex );
}
}
}
return ret;
}
/**
* Returns the {@link Service} instance which was registered with the provided service name if
* it
* exists. If a service with the given name does not exist a NoSuchElementException is thrown.
*
* @param name - the name used to register the specific service.
* @return
* @throws NoSuchElementException
* @deprecated {@link #getServices(ServiceConfiguration)}
*/
public ServiceConfiguration getService( String name ) throws NoSuchElementException {
checkParam( name, notNullValue() );
for ( ServiceConfiguration s : this.services.keySet( ) ) {
if ( s.getName( ).equals( name ) ) {
return s;
}
}
throw new NoSuchElementException( "No service found matching name: " + name
+ " for component: "
+ Component.this.getName( ) );
}
/**
* TODO: DOCUMENT Component.java
*
* @param config
* @return
*/
public boolean hasService( ServiceConfiguration config ) {
return this.services.containsKey( config );
}
}
public ServiceConfiguration getLocalServiceConfiguration( ) {
return this.serviceRegistry.getLocalService( ).getServiceConfiguration( );
}
/**
* @param componentConfiguration
* @return
*/
public StateMachine<ServiceConfiguration, State, Transition> getStateMachine( ServiceConfiguration conf ) {
return this.serviceRegistry.lookup( conf ).getStateMachine( );
}
public void addBootstrapper( Bootstrapper bootstrapper ) {
this.bootstrapper.addBootstrapper( bootstrapper );
}
public boolean load( ) {
return this.bootstrapper.load( );
}
public boolean start( ) {
return this.bootstrapper.start( );
}
public boolean enable( ) {
return this.bootstrapper.enable( );
}
public boolean stop( ) {
return this.bootstrapper.stop( );
}
public void destroy( ) {
this.bootstrapper.destroy( );
}
public boolean disable( ) {
return this.bootstrapper.disable( );
}
public boolean check( ) {
return this.bootstrapper.check( );
}
public List<Bootstrapper> getBootstrappers( ) {
return this.bootstrapper.getBootstrappers( );
}
enum BootstrapChecks implements Predicate<Bootstrapper> {
CHECK_NO_TRANSITION {
@Override
public boolean apply(@Nullable Bootstrapper bootstrapper) {
try {
return bootstrapper.check();
} catch(Throwable f) {
LOG.debug("Bootstrap check failed", f);
return false;
}
}
}
}
static class ComponentBootstrapper implements CanBootstrap {
private final Multimap<Bootstrap.Stage, Bootstrapper> bootstrappers;
private final Multimap<Bootstrap.Stage, Bootstrapper> disabledBootstrappers;
private final Component component;
ComponentBootstrapper( Component component ) {
super( );
this.component = component;
Multimap<Bootstrap.Stage, Bootstrapper> a = ArrayListMultimap.create( );
this.bootstrappers = Multimaps.synchronizedMultimap( a );
Multimap<Bootstrap.Stage, Bootstrapper> b = ArrayListMultimap.create( );
this.disabledBootstrappers = Multimaps.synchronizedMultimap( b );
}
public void addBootstrapper( Bootstrapper bootstrapper ) {
if ( Stage.PrivilegedConfiguration.equals( bootstrapper.getBootstrapStage( ) ) ) {
EventRecord.here( Bootstrap.class, EventType.BOOTSTRAPPER_SKIPPED, "stage:" + bootstrapper.getBootstrapStage( ).toString( ),
this.component.getComponentId( ).name( ),
bootstrapper.getClass( ).getName( ),
"component=" + this.component.getComponentId( ).name( ) ).exhaust( );
} else {
EventRecord.here( Bootstrap.class, EventType.BOOTSTRAPPER_ADDED, "stage:" + bootstrapper.getBootstrapStage( ).toString( ),
this.component.getComponentId( ).name( ),
bootstrapper.getClass( ).getName( ),
"component=" + this.component.getComponentId( ).name( ) ).exhaust( );
this.bootstrappers.put( bootstrapper.getBootstrapStage( ), bootstrapper );
}
}
private synchronized void updateBootstrapDependencies( ) {
Iterable<Bootstrapper> currBootstrappers = Iterables.concat( Lists.newArrayList( this.bootstrappers.values( ) ),
Lists.newArrayList( this.disabledBootstrappers.values( ) ) );
this.bootstrappers.clear( );
this.disabledBootstrappers.clear( );
for ( Bootstrapper bootstrapper : currBootstrappers ) {
try {
Bootstrap.Stage stage = bootstrapper.getBootstrapStage( );
if ( bootstrapper.checkLocal( ) && bootstrapper.checkRemote( ) ) {
this.enableBootstrapper( stage, bootstrapper );
} else {
this.disableBootstrapper( stage, bootstrapper );
}
} catch ( Exception ex ) {
LOG.error( ex, ex );
}
}
}
private void enableBootstrapper( Bootstrap.Stage stage, Bootstrapper bootstrapper ) {
EventRecord.here( Bootstrap.class, EventType.BOOTSTRAPPER_MARK_ENABLED, "stage:", stage.toString( ), this.component.getComponentId( ).name( ),
bootstrapper.getClass( ).getName( ), "component=" + this.component.getComponentId( ).name( ) ).exhaust( );
this.disabledBootstrappers.remove( stage, bootstrapper );
this.bootstrappers.put( stage, bootstrapper );
}
private void disableBootstrapper( Bootstrap.Stage stage, Bootstrapper bootstrapper ) {
EventRecord.here( Bootstrap.class, EventType.BOOTSTRAPPER_MARK_DISABLED, "stage:" + stage.toString( ), this.component.getComponentId( ).name( ),
bootstrapper.getClass( ).getName( ), "component=" + this.component.getComponentId( ).name( ) ).exhaust( );
this.bootstrappers.remove( stage, bootstrapper );
this.disabledBootstrappers.put( stage, bootstrapper );
}
private boolean doTransition( EventType transition, Function<Bootstrapper, Boolean> checkedFunction ) {
return doTransition( transition, checkedFunction, Functions.forPredicate( ( Predicate ) Predicates.alwaysTrue( ) ) );
}
private boolean doTransition( EventType transition, Function<Bootstrapper, Boolean> checkedFunction, Function<Bootstrapper, Boolean> rollbackFunction ) {
String name = transition.name( ).replaceAll( ".*_", "" ).toLowerCase( );
List<Bootstrapper> rollbackBootstrappers = Lists.newArrayList( );
this.updateBootstrapDependencies( );
for ( Stage s : Bootstrap.Stage.values( ) ) {
for ( Bootstrapper b : Lists.newArrayList( this.bootstrappers.get( s ) ) ) {
EventRecord.here( this.component.getClass( ), transition, this.component.getComponentId( ).name( ), "stage", s.name( ),
b.getClass( ).getCanonicalName( ) ).extreme( );
TransitionException ex = null;
try {
if ( checkedFunction.apply( b ) ) {
rollbackBootstrappers.add( b );
} else {
//TODO: This needs reconciliation w/ Faults.advisory() especially to propagate exception information to describe services
ex = new OrderlyTransitionException( b.getClass( ).getSimpleName( ) + "."
+ name
+ "( ): returned false, terminating bootstrap for component: "
+ this.component.getName( ) );
}
} catch ( Exception e ) {
LOG.error( e );
Logs.extreme( ).error( e, e );
ex = new TransitionException( b.getClass( ).getSimpleName( ) + "."
+ name
+ "( ): failed because of: "
+ e.getMessage( )
+ ", terminating bootstrap for component: "
+ this.component.getName( ), e );
}
if ( ex != null ) {
for ( Bootstrapper rollback : Lists.reverse( rollbackBootstrappers ) ) {
try {
rollbackFunction.apply( rollback );
} catch ( Exception ex1 ) {
LOG.error( ex1 );
Logs.extreme( ).error( ex1, ex1 );
}
}
throw ex;
}
}
}
return true;
}
enum BootstrapperTransition implements Function<Bootstrapper, Boolean> {
LOAD {
@Override
public Boolean runBootstrapper( Bootstrapper arg0 ) throws Exception {
return arg0.load( );
}
},
START {
@Override
public Boolean runBootstrapper( Bootstrapper arg0 ) throws Exception {
return arg0.start( );
}
},
ENABLE {
@Override
public Boolean runBootstrapper( Bootstrapper arg0 ) throws Exception {
return arg0.enable( );
}
},
DISABLE {
@Override
public Boolean runBootstrapper( Bootstrapper arg0 ) throws Exception {
return arg0.disable( );
}
},
STOP {
@Override
public Boolean runBootstrapper( Bootstrapper arg0 ) throws Exception {
try {
arg0.stop( );
} catch ( Exception ex ) {
LOG.error( ex, ex );
}
return true;
}
},
DESTROY {
@Override
public Boolean runBootstrapper( Bootstrapper arg0 ) throws Exception {
try {
arg0.destroy( );
} catch ( Exception ex ) {
LOG.error( ex, ex );
}
return true;
}
},
CHECK {
@Override
public Boolean runBootstrapper( Bootstrapper arg0 ) throws Exception {
return arg0.check( );
}
};
public abstract Boolean runBootstrapper( Bootstrapper arg0 ) throws Exception;
@Override
public Boolean apply( Bootstrapper input ) {
try {
return this.runBootstrapper( input );
} catch ( Exception ex ) {
throw Exceptions.toUndeclared( ex );
}
}
}
@Override
public boolean load( ) {
return this.doTransition( EventType.BOOTSTRAPPER_LOAD, BootstrapperTransition.LOAD, BootstrapperTransition.DESTROY );
}
@Override
public boolean start( ) {
return this.doTransition( EventType.BOOTSTRAPPER_START, BootstrapperTransition.START, BootstrapperTransition.STOP );
}
@Override
public boolean enable( ) {
return this.doTransition( EventType.BOOTSTRAPPER_ENABLE, BootstrapperTransition.ENABLE, BootstrapperTransition.DISABLE );
}
@Override
public boolean stop( ) {
return this.doTransition( EventType.BOOTSTRAPPER_ENABLE, BootstrapperTransition.STOP );
}
@Override
public void destroy( ) {
this.doTransition( EventType.BOOTSTRAPPER_ENABLE, BootstrapperTransition.DESTROY );
}
@Override
public boolean disable( ) {
return this.doTransition( EventType.BOOTSTRAPPER_ENABLE, BootstrapperTransition.DISABLE );
}
@Override
public boolean check( ) {
return this.doTransition( EventType.BOOTSTRAPPER_ENABLE, BootstrapperTransition.CHECK );
}
public List<Bootstrapper> getBootstrappers( ) {
return Lists.newArrayList( this.bootstrappers.values( ) );
}
@Override
public String toString( ) {
return Joiner.on( "\n" ).join( this.bootstrappers.values( ) );
}
}
}