| /* |
| * 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.Collections; |
| import java.util.LinkedHashSet; |
| import java.util.LinkedList; |
| import java.util.Set; |
| import org.qi4j.api.activation.Activation; |
| import org.qi4j.api.activation.ActivationEvent; |
| import org.qi4j.api.activation.ActivationEventListener; |
| import org.qi4j.api.activation.ActivationException; |
| import org.qi4j.api.activation.PassivationException; |
| import org.qi4j.api.service.ServiceReference; |
| |
| import static org.qi4j.api.activation.ActivationEvent.EventType.ACTIVATED; |
| import static org.qi4j.api.activation.ActivationEvent.EventType.ACTIVATING; |
| import static org.qi4j.api.activation.ActivationEvent.EventType.PASSIVATED; |
| import static org.qi4j.api.activation.ActivationEvent.EventType.PASSIVATING; |
| |
| /** |
| * This class manage Activation of a target and propagates to children. |
| */ |
| @SuppressWarnings( "raw" ) |
| public final class ActivationDelegate |
| extends ActivationEventListenerSupport |
| { |
| private final Object target; |
| private final boolean fireEvents; |
| private ActivatorsInstance targetActivators = null; |
| private final LinkedList<Activation> activeChildren = new LinkedList<>(); |
| |
| /** |
| * Create a new ActivationDelegate that will fire events. |
| * @param target target of Activation |
| */ |
| public ActivationDelegate( Object target ) |
| { |
| this( target, true ); |
| } |
| |
| /** |
| * Create a new ActivationDelegate. |
| * @param target target of Activation |
| * @param fireEvents if {@link ActivationEvent}s should be fired |
| */ |
| public ActivationDelegate( Object target, boolean fireEvents ) |
| { |
| super(); |
| this.target = target; |
| this.fireEvents = fireEvents; |
| } |
| |
| 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 ); |
| } |
| |
| @SuppressWarnings( "unchecked" ) |
| 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!" ); |
| } |
| |
| try |
| { |
| // Before Activation Events |
| if( fireEvents ) |
| { |
| fireEvent( new ActivationEvent( target, ACTIVATING ) ); |
| } |
| |
| // Before Activation for Activators |
| targetActivators.beforeActivation( target instanceof ServiceReference |
| ? new PassiveServiceReference( (ServiceReference) target ) |
| : target ); |
| |
| // 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 ); |
| |
| // After Activation Events |
| if( fireEvents ) |
| { |
| fireEvent( new ActivationEvent( target, ACTIVATED ) ); |
| } |
| |
| // Activated |
| this.targetActivators = targetActivators; |
| } |
| catch( Exception e ) |
| { |
| // Passivate actives |
| try |
| { |
| passivate(); |
| } |
| catch( PassivationException e1 ) |
| { |
| ActivationException activationEx = new ActivationException( "Unable to Activate application.", e ); |
| activationEx.addSuppressed( e1 ); |
| throw activationEx; |
| } |
| if( e instanceof ActivationException ) |
| { |
| throw ( (ActivationException) e ); |
| } |
| throw new ActivationException( "Unable to Activate application.", e ); |
| } |
| } |
| |
| public void passivate() |
| throws PassivationException |
| { |
| passivate( (Runnable) null ); |
| } |
| |
| @SuppressWarnings( "unchecked" ) |
| public void passivate( Runnable callback ) |
| throws PassivationException |
| { |
| Set<Exception> exceptions = new LinkedHashSet<>(); |
| |
| // Before Passivation Events |
| if( fireEvents ) |
| { |
| ActivationEvent event = new ActivationEvent( target, PASSIVATING ); |
| for( ActivationEventListener listener : listeners ) |
| { |
| try |
| { |
| listener.onEvent( event ); |
| } |
| catch( Exception ex ) |
| { |
| if( ex instanceof PassivationException ) |
| { |
| exceptions.addAll( ( (PassivationException) ex ).causes() ); |
| } |
| else |
| { |
| exceptions.add( ex ); |
| } |
| } |
| } |
| } |
| |
| // Before Passivation for Activators |
| if( targetActivators != null ) |
| { |
| try |
| { |
| targetActivators.beforePassivation( target ); |
| } |
| catch( PassivationException ex ) |
| { |
| exceptions.addAll( ex.causes() ); |
| } |
| catch( Exception ex ) |
| { |
| exceptions.add( ex ); |
| } |
| } |
| |
| // Passivation |
| while( !activeChildren.isEmpty() ) |
| { |
| passivateOneChild( exceptions ); |
| } |
| |
| // Internal Passivation Callback |
| if( callback != null ) |
| { |
| try |
| { |
| callback.run(); |
| } |
| catch( Exception ex ) |
| { |
| if( ex instanceof PassivationException ) |
| { |
| exceptions.addAll( ( (PassivationException) ex ).causes() ); |
| } |
| else |
| { |
| exceptions.add( ex ); |
| } |
| } |
| } |
| |
| // After Passivation for Activators |
| if( targetActivators != null ) |
| { |
| try |
| { |
| targetActivators.afterPassivation( target instanceof ServiceReference |
| ? new PassiveServiceReference( (ServiceReference) target ) |
| : target ); |
| } |
| catch( PassivationException ex ) |
| { |
| exceptions.addAll( ex.causes() ); |
| } |
| catch( Exception ex ) |
| { |
| exceptions.add( ex ); |
| } |
| } |
| targetActivators = null; |
| |
| // After Passivation Events |
| if( fireEvents ) |
| { |
| ActivationEvent event = new ActivationEvent( target, PASSIVATED ); |
| for( ActivationEventListener listener : listeners ) |
| { |
| try |
| { |
| listener.onEvent( event ); |
| } |
| catch( Exception ex ) |
| { |
| if( ex instanceof PassivationException ) |
| { |
| exceptions.addAll( ( (PassivationException) ex ).causes() ); |
| } |
| else |
| { |
| exceptions.add( ex ); |
| } |
| } |
| } |
| } |
| |
| // Error handling |
| if( exceptions.isEmpty() ) |
| { |
| return; |
| } |
| throw new PassivationException( exceptions ); |
| } |
| |
| @SuppressWarnings( "TooBroadCatch" ) |
| private void passivateOneChild( Set<Exception> exceptions ) |
| { |
| Activation activeChild = activeChildren.removeFirst(); |
| try |
| { |
| activeChild.passivate(); |
| } |
| catch( PassivationException ex ) |
| { |
| exceptions.addAll( ex.causes() ); |
| } |
| catch( Exception ex ) |
| { |
| exceptions.add( ex ); |
| } |
| } |
| |
| @SuppressWarnings( "raw" ) |
| 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() ); |
| } |
| |
| @Override |
| public String toString() |
| { |
| return reference.toString(); |
| } |
| } |
| |
| } |