/*
* Copyright (c) 2008, Rickard Öberg. All Rights Reserved.
* Copyright (c) 2012, Paul Merlin.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.qi4j.runtime.activation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.qi4j.api.activation.Activation;
import org.qi4j.api.activation.ActivationEventListener;
import org.qi4j.api.activation.ActivationException;
import org.qi4j.api.activation.PassivationException;
import org.qi4j.api.service.ServiceReference;
/**
* This class will manage Activation of a target and propagates to children.
*/
public final class ActivationDelegate
{
private final Object target;
private ActivatorsInstance targetActivators = null;
private final LinkedList<Activation> activeChildren = new LinkedList<Activation>();
public ActivationDelegate( Object target )
{
this.target = target;
}
public void activate( ActivatorsInstance targetActivators, Activation child )
throws Exception
{
activate( targetActivators, Collections.singleton( child ), null );
}
public void activate( ActivatorsInstance targetActivators, Activation child, Runnable callback )
throws Exception
{
activate( targetActivators, Collections.singleton( child ), callback );
}
public void activate( ActivatorsInstance targetActivators, Iterable<? extends Activation> children )
throws ActivationException
{
activate( targetActivators, children, null );
}
public void activate( ActivatorsInstance targetActivators, Iterable<? extends Activation> children, Runnable callback )
throws ActivationException
{
if ( this.targetActivators != null ) {
throw new IllegalStateException( "Activation.activate() called multiple times or without calling passivate() first!" );
}
// Before Activation
targetActivators.beforeActivation( target instanceof ServiceReference
? new PassiveServiceReference( ( ServiceReference ) target )
: target );
try
{
// Activation
for( Activation child : children )
{
if( ! activeChildren.contains( child ) )
{
child.activate();
}
activeChildren.addFirst( child );
}
// Internal Activation Callback
if( callback != null )
{
callback.run();
}
// After Activation
targetActivators.afterActivation( target );
this.targetActivators = targetActivators;
}
catch( Throwable e )
{
// Passivate actives
try
{
passivate();
}
catch( PassivationException e1 )
{
throw new ActivationException( "Passivation Exception during cleanup of Activation:" + e1, e );
}
if( e instanceof ActivationException )
throw ((ActivationException)e);
throw new ActivationException( "Unable to Activate application.", e );
}
}
public void passivate()
throws PassivationException
{
passivate( ( Runnable ) null );
}
public void passivate( Runnable callback )
throws PassivationException
{
List<Exception> exceptions = new ArrayList<Exception>();
// Before Passivation
if ( targetActivators != null )
{
try
{
targetActivators.beforePassivation( target );
}
catch( Exception ex )
{
if( ex instanceof PassivationException )
{
exceptions.addAll( Arrays.asList( ( ( PassivationException ) ex ).causes() ) );
}
else
{
exceptions.add( ex );
}
}
}
// Passivation
while( !activeChildren.isEmpty() )
{
passivateOneChild( exceptions );
}
// Internal Passivation Callback
if( callback != null )
{
callback.run();
}
// After Passivation
if ( targetActivators != null )
{
try
{
targetActivators.afterPassivation( target instanceof ServiceReference
? new PassiveServiceReference( ( ServiceReference ) target )
: target );
}
catch( Exception ex )
{
if( ex instanceof PassivationException )
{
exceptions.addAll( Arrays.asList( ( ( PassivationException ) ex ).causes() ) );
}
else
{
exceptions.add( ex );
}
}
}
targetActivators = null;
// Error handling
if( exceptions.isEmpty() )
{
return;
}
throw new PassivationException( exceptions );
}
private void passivateOneChild( List<Exception> exceptions )
{
Activation activeChild = activeChildren.removeFirst();
try
{
activeChild.passivate();
}
catch( Exception ex )
{
if( ex instanceof PassivationException )
{
exceptions.addAll( Arrays.asList( ( ( PassivationException ) ex ).causes() ) );
}
else
{
exceptions.add( ex );
}
}
}
private static class PassiveServiceReference
implements ServiceReference
{
private final ServiceReference reference;
private PassiveServiceReference( ServiceReference reference )
{
this.reference = reference;
}
@Override
public String identity()
{
return reference.identity();
}
@Override
public Object get()
{
throw new IllegalStateException( "Service is passive, either activating and"
+ " cannot be used yet or passivating and cannot be used anymore." );
}
@Override
public boolean isActive()
{
return false;
}
@Override
public boolean isAvailable()
{
return false;
}
@Override
public Iterable<Class<?>> types()
{
return reference.types();
}
@Override
public <T> T metaInfo( Class<T> infoType )
{
return reference.metaInfo( infoType );
}
@Override
public void registerActivationEventListener( ActivationEventListener listener )
{
reference.registerActivationEventListener( listener );
}
@Override
public void deregisterActivationEventListener( ActivationEventListener listener )
{
reference.deregisterActivationEventListener( listener );
}
@Override
public int hashCode()
{
return identity().hashCode();
}
@Override
public boolean equals( Object obj )
{
if ( obj == null ) {
return false;
}
if ( getClass() != obj.getClass() ) {
return false;
}
final ServiceReference other = ( ServiceReference ) obj;
return identity().equals( other.identity() );
}
}
}