001/*
002 * This file is part of the Kompics component model runtime.
003 * <p>
004 * Copyright (C) 2009 Swedish Institute of Computer Science (SICS)
005 * Copyright (C) 2009 Royal Institute of Technology (KTH)
006 * <p>
007 * Kompics is free software; you can redistribute it and/or modify it under the
008 * terms of the GNU General Public License as published by the Free Software
009 * Foundation; either version 2 of the License, or (at your option) any later
010 * version.
011 * <p>
012 * This program is distributed in the hope that it will be useful, but WITHOUT
013 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
014 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
015 * details.
016 * <p>
017 * You should have received a copy of the GNU General Public License along with
018 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
019 * Place - Suite 330, Boston, MA 02111-1307, USA.
020 */
021package se.sics.kompics;
022
023import java.util.Optional;
024import java.lang.reflect.Constructor;
025import java.lang.reflect.InvocationTargetException;
026import java.util.HashMap;
027import java.util.HashSet;
028import java.util.Map;
029import java.util.Objects;
030import java.util.Set;
031import org.slf4j.Logger;
032import org.slf4j.MDC;
033import se.sics.kompics.Fault.ResolveAction;
034import se.sics.kompics.HandlerStore.HandlerList;
035import se.sics.kompics.HandlerStore.MatchedHandlerList;
036import se.sics.kompics.config.Config;
037import se.sics.kompics.config.ConfigUpdate;
038import se.sics.kompics.config.ValueMerger;
039
040/**
041 * The <code>ComponentCore</code> class.
042 * <p>
043 * 
044 * @author Cosmin Arad {@literal <[email protected]>}
045 * @author Jim Dowling {@literal <[email protected]>}
046 * @author Lars Kroll {@literal <[email protected]>}
047 * @version $Id$
048 */
049@SuppressWarnings("serial")
050public class JavaComponent extends ComponentCore {
051
052    private final int executeNEvents;
053    /*
054     * outside ports
055     */
056    private HashMap<Class<? extends PortType>, JavaPort<? extends PortType>> positivePorts;
057    private HashMap<Class<? extends PortType>, JavaPort<? extends PortType>> negativePorts;
058    private JavaPort<ControlPort> positiveControl, negativeControl;
059    ComponentDefinition component;
060
061    /**
062     * Instantiates a new component core.
063     * <p>
064     * 
065     * @param componentDefinition
066     *            the component definition
067     */
068    public JavaComponent(ComponentDefinition componentDefinition) {
069        this.positivePorts = new HashMap<Class<? extends PortType>, JavaPort<? extends PortType>>();
070        this.negativePorts = new HashMap<Class<? extends PortType>, JavaPort<? extends PortType>>();
071        this.parent = parentThreadLocal.get();
072        if (this.parent != null) {
073            this.conf = parent.conf.copy(componentDefinition.separateConfigId());
074        } else {
075            this.conf = Kompics.getConfig().copy(componentDefinition.separateConfigId());
076        }
077
078        if (childUpdate.get().isPresent()) {
079            Config.Impl ci = (Config.Impl) this.conf;
080            ci.apply(childUpdate.get().get(), ValueMerger.NONE);
081            Optional<ConfigUpdate> resetUpdate = Optional.empty();
082            childUpdate.set(resetUpdate);
083        }
084        this.component = componentDefinition;
085        parentThreadLocal.set(null);
086        executeNEvents = Kompics.maxNumOfExecutedEvents.get();
087    }
088
089    // public JavaComponent(JavaComponent other) {
090    // this.positivePorts = other.positivePorts;
091    // this.negativePorts = other.negativePorts;
092    // this.parent = other.parent;
093    // this.conf = other.conf;
094    // this.component = other.component;
095    // parentThreadLocal.set(null);
096    // }
097    @Override
098    protected Logger logger() {
099        return this.component.logger;
100    }
101
102    /*
103     * (non-Javadoc)
104     *
105     * @see se.sics.kompics.Component#getControl()
106     */
107    @Override
108    public Positive<ControlPort> getControl() {
109        return positiveControl;
110    }
111
112    @Override
113    public Positive<ControlPort> control() {
114        return positiveControl;
115    }
116
117    Map<Class<? extends PortType>, JavaPort<? extends PortType>> getNegativePorts() {
118        return negativePorts;
119    }
120
121    /*
122     * (non-Javadoc)
123     *
124     * @see se.sics.kompics.Component#getNegative(java.lang.Class)
125     */
126    @SuppressWarnings("unchecked")
127    @Override
128    public <P extends PortType> Negative<P> getNegative(Class<P> portType) {
129        Negative<P> port = (Negative<P>) negativePorts.get(portType);
130        if (port == null) {
131            throw new RuntimeException(component + " has no negative " + portType.getCanonicalName());
132        }
133        return port;
134    }
135
136    @Override
137    public <P extends PortType> Negative<P> required(Class<P> portType) {
138        return getNegative(portType);
139    }
140
141    Map<Class<? extends PortType>, JavaPort<? extends PortType>> getPositivePorts() {
142        return positivePorts;
143    }
144
145    /*
146     * (non-Javadoc)
147     *
148     * @see se.sics.kompics.Component#getPositive(java.lang.Class)
149     */
150    @SuppressWarnings("unchecked")
151    @Override
152    public <P extends PortType> Positive<P> getPositive(Class<P> portType) {
153        Positive<P> port = (Positive<P>) positivePorts.get(portType);
154        if (port == null) {
155            throw new RuntimeException(component + " has no positive " + portType.getCanonicalName());
156        }
157        return port;
158    }
159
160    @Override
161    public <P extends PortType> Positive<P> provided(Class<P> portType) {
162        return getPositive(portType);
163    }
164
165    @Override
166    public <P extends PortType> Negative<P> createNegativePort(Class<P> portType) {
167        JavaPort<P> negativePort = new JavaPort<P>(false, PortType.getPortType(portType), this);
168        JavaPort<P> positivePort = new JavaPort<P>(true, PortType.getPortType(portType), parent);
169
170        negativePort.setPair(positivePort);
171        positivePort.setPair(negativePort);
172
173        Positive<?> existing = positivePorts.put(portType, positivePort);
174        if (existing != null) {
175            throw new RuntimeException("Cannot create multiple negative " + portType.getCanonicalName());
176        }
177        return negativePort;
178    }
179
180    @Override
181    public <P extends PortType> Positive<P> createPositivePort(Class<P> portType) {
182        JavaPort<P> negativePort = new JavaPort<P>(false, PortType.getPortType(portType), parent);
183        JavaPort<P> positivePort = new JavaPort<P>(true, PortType.getPortType(portType), this);
184
185        negativePort.setPair(positivePort);
186        positivePort.setPair(negativePort);
187
188        Negative<?> existing = negativePorts.put(portType, negativePort);
189        if (existing != null) {
190            throw new RuntimeException("Cannot create multiple positive " + portType.getCanonicalName());
191        }
192        return positivePort;
193    }
194
195    @Override
196    public Negative<ControlPort> createControlPort() {
197        negativeControl = new JavaPort<ControlPort>(false, PortType.getPortType(ControlPort.class), this);
198        positiveControl = new JavaPort<ControlPort>(true, PortType.getPortType(ControlPort.class), parent);
199
200        positiveControl.setPair(negativeControl);
201        negativeControl.setPair(positiveControl);
202
203        negativeControl.doSubscribe(handleStart);
204        negativeControl.doSubscribe(handleStop);
205        negativeControl.doSubscribe(handleKill);
206
207        negativeControl.doSubscribe(handleStarted);
208        negativeControl.doSubscribe(handleStopped);
209        negativeControl.doSubscribe(handleKilled);
210
211        negativeControl.doInternalSubscribe(handleFault);
212
213        negativeControl.doInternalSubscribe(configHandler);
214
215        return negativeControl;
216    }
217
218    @Override
219    protected void cleanPorts() {
220        for (JavaPort<? extends PortType> port : negativePorts.values()) {
221            port.cleanChannels();
222        }
223        for (JavaPort<? extends PortType> port : positivePorts.values()) {
224            port.cleanChannels();
225        }
226    }
227
228    @Override
229    public <T extends ComponentDefinition> Component doCreate(Class<T> definition, Optional<Init<T>> initEvent) {
230        Optional<ConfigUpdate> update = Optional.empty();
231        return doCreate(definition, initEvent, update);
232    }
233
234    @Override
235    public <T extends ComponentDefinition> Component doCreate(Class<T> definition, Optional<Init<T>> initEvent,
236            Optional<ConfigUpdate> update) {
237        // create an instance of the implementing component type
238        ComponentDefinition component;
239        childrenLock.writeLock().lock();
240        try {
241            parentThreadLocal.set(this);
242            childUpdate.set(update);
243            component = createInstance(definition, initEvent);
244            ComponentCore child = component.getComponentCore();
245
246            // child.workCount.incrementAndGet();
247            child.setScheduler(scheduler);
248
249            children.add(child);
250
251            return child;
252        } catch (InstantiationException e) {
253            throw new RuntimeException("Cannot create component " + definition.getCanonicalName(), e);
254        } catch (IllegalAccessException e) {
255            throw new RuntimeException("Cannot create component " + definition.getCanonicalName(), e);
256        } catch (NoSuchMethodException e) {
257            throw new RuntimeException("Cannot create component " + definition.getCanonicalName(), e);
258        } catch (InvocationTargetException e) {
259            throw new RuntimeException("Cannot create component " + definition.getCanonicalName(), e);
260        } finally {
261            childrenLock.writeLock().unlock();
262        }
263    }
264
265    private <T extends ComponentDefinition> T createInstance(Class<T> definition, Optional<Init<T>> initEvent)
266            throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
267        if (!initEvent.isPresent()) {
268            return definition.newInstance();
269        }
270        Init<T> init = initEvent.get();
271        if (init instanceof Init.None) {
272            return definition.newInstance();
273        }
274        // look for a constructor that takes a single parameter
275        // and is assigment compatible with the given init event
276        Constructor<T> constr = definition.getConstructor(init.getClass());
277        return constr.newInstance(init);
278    }
279
280    @Override
281    public void execute(int wid) {
282        State previousState = state;
283        if ((state == State.DESTROYED) || (state == State.FAULTY)) {
284            return; // don't schedule these components
285        }
286        this.wid = wid;
287        // System.err.println("Executing " + wid);
288
289        // New scheduling code: Run n and move to end of schedule
290        //
291        int count = 0;
292        int wc = workCount.get();
293
294        this.component.setMDC();
295        MDC.put(ComponentDefinition.MDC_KEY_CSTATE, state.name());
296        try {
297
298            while ((count < executeNEvents) && wc > 0) {
299                if (previousState != state) { // state might have changed between iterations
300                    if (state == State.FAULTY) {
301                        return;
302                    }
303                    previousState = state;
304                    MDC.put(ComponentDefinition.MDC_KEY_CSTATE, state.name());
305                }
306
307                KompicsEvent event;
308                JavaPort<?> nextPort;
309                if ((state == State.PASSIVE) || (state == State.STARTING)) {
310                    // System.err.println("non-active state " + wid);
311
312                    event = negativeControl.pickFirstEvent();
313                    nextPort = negativeControl;
314
315                    if (event == null) {
316                        logger().debug("Not scheduling component.");
317                        // try again
318                        if (wc > 0) {
319                            schedule(wid);
320                        }
321                        return; // Don't run anything else
322                    }
323                    readyPorts.remove(nextPort);
324                } else {
325                    // System.err.println("active state " + wid);
326                    nextPort = (JavaPort<?>) readyPorts.poll();
327                    if (nextPort == null) {
328                        wc = workCount.decrementAndGet();
329                        count++;
330                        continue;
331                    }
332                    event = nextPort.pickFirstEvent();
333                }
334
335                if (event == null) {
336                    logger().debug("Couldn't find event to schedule: wc={}", wc);
337                    wc = workCount.decrementAndGet();
338                    count++;
339                    continue;
340                }
341
342                HandlerList handlers = nextPort.getSubscribedHandlers(event);
343
344                if ((handlers != null) && (handlers.length > 0)) {
345                    for (int i = 0; i < handlers.length; i++) {
346                        if (executeEvent(event, handlers.subscriptions[i])) {
347                            break; // state changed don't handle the rest of the event
348                        }
349                    }
350                }
351                if (event instanceof PatternExtractor) {
352                    PatternExtractor<?, ?> pe = (PatternExtractor<?, ?>) event;
353                    MatchedHandlerList mhandlers = nextPort.getSubscribedMatchers(pe);
354                    if ((mhandlers != null) && (mhandlers.length > 0)) {
355                        for (int i = 0; i < mhandlers.length; i++) {
356                            if (executeEvent(pe, mhandlers.subscriptions[i])) {
357                                break; // state changed don't handle the rest of the event
358                            }
359                        }
360                    }
361                }
362                wc = workCount.decrementAndGet();
363                count++;
364            }
365
366        } finally {
367            MDC.clear();
368        }
369
370        if (wc > 0) {
371            schedule(wid);
372        }
373    }
374
375    @SuppressWarnings("unchecked")
376    private boolean executeEvent(KompicsEvent event, Handler<?> handler) {
377        try {
378            ((Handler<KompicsEvent>) handler).handle(event);
379            return false; // no state change
380        } catch (Throwable throwable) {
381            logger().error("Handling an event caused a fault! Might be handled later...", throwable);
382            markSubtreeAs(State.FAULTY);
383            escalateFault(new Fault(throwable, this, event));
384            return true; // state changed
385        }
386    }
387
388    @SuppressWarnings("unchecked")
389    private boolean executeEvent(PatternExtractor<?, ?> event, MatchedHandler<?, ?, ?> handler) {
390        try {
391            PatternExtractor<?, Object> pe = (PatternExtractor<?, Object>) event;
392            MatchedHandler<?, Object, PatternExtractor<?, Object>> h = (MatchedHandler<?, Object, PatternExtractor<?, Object>>) handler;
393            h.handle(pe.extractValue(), pe);
394            return false; // no state change
395        } catch (Throwable throwable) {
396            logger().error("Handling an event caused a fault! Might be handled later...", throwable);
397            markSubtreeAs(State.FAULTY);
398            escalateFault(new Fault(throwable, this, event));
399            return true; // state changed
400        }
401    }
402
403    @Override
404    public void escalateFault(Fault fault) {
405        if (parent != null) {
406            parent.control().doTrigger(fault, wid, this);
407        } else {
408            // StackTraceElement[] stackTrace = throwable.getStackTrace();
409            // System.err.println("Kompics isolated fault: "
410            // + throwable.getMessage());
411            // do {
412            // for (int i = 0; i < stackTrace.length; i++) {
413            // System.err.println(" " + stackTrace[i]);
414            // }
415            // throwable = throwable.getCause();
416            // if (throwable != null) {
417            // stackTrace = throwable.getStackTrace();
418            // System.err.println("Caused by: " + throwable + ": "
419            // + throwable.getMessage());
420            // }
421            // } while (throwable != null);
422            logger().error("A fault was escalated to the root component: \n{} \n\n", fault);
423            Kompics.handleFault(fault);
424            // System.exit(1);
425        }
426    }
427
428    Handler<Fault> handleFault = new Handler<Fault>() {
429
430        @Override
431        public void handle(Fault event) {
432
433            ResolveAction ra = component.handleFault(event);
434            switch (ra) {
435            case RESOLVED:
436                logger().info("Fault {} was resolved by user.", event);
437                break;
438            case IGNORE:
439                logger().info("Fault {} was declared to be ignored by user. Resuming component...", event);
440                markSubtreeAtAs(event.source, State.PASSIVE);
441                event.source.control().doTrigger(Start.event, wid, JavaComponent.this);
442                break;
443            case DESTROY:
444                logger().info("User declared that Fault {} should destroy component tree...", event);
445                destroyTreeAtParentOf(event.source);
446                logger().info("finished destroying the subtree.");
447                break;
448            default:
449                escalateFault(event);
450            }
451        }
452    };
453    Handler<Update> configHandler = new Handler<Update>() {
454
455        @Override
456        public void handle(Update event) {
457            UpdateAction action = JavaComponent.this.component.handleUpdate(event.update);
458            switch (action.selfStrategy) {
459            case ORIGINAL:
460                ((Config.Impl) conf).apply(event.update, action.merger);
461                break;
462            case MAP:
463                ((Config.Impl) conf).apply(action.selfMapper.map(event.update, event.update.modify(id())),
464                        action.merger);
465                break;
466            case SWALLOW:
467                break;
468            }
469            if ((parent != null) && (event.forwarder == parent.id())) { // downwards
470                switch (action.downStrategy) {
471                case ORIGINAL: {
472                    Update forwardedEvent = new Update(event.update, id());
473                    for (Component child : children) {
474                        ((PortCore<ControlPort>) child.getControl()).doTrigger(forwardedEvent, wid,
475                                component.getComponentCore());
476                    }
477                }
478                    break;
479                case MAP: {
480                    ConfigUpdate mappedUpdate = action.downMapper.map(event.update, event.update.modify(id()));
481                    Update forwardedEvent = new Update(mappedUpdate, id());
482                    for (Component child : children) {
483                        ((PortCore<ControlPort>) child.getControl()).doTrigger(forwardedEvent, wid,
484                                component.getComponentCore());
485                    }
486                }
487                    break;
488                case SWALLOW:
489                    break;
490                }
491            } else { // upwards and to other children
492                switch (action.downStrategy) {
493                case ORIGINAL: {
494                    Update forwardedEvent = new Update(event.update, id());
495                    for (Component child : children) {
496                        if (child.id() != event.forwarder) {
497                            ((PortCore<ControlPort>) child.getControl()).doTrigger(forwardedEvent, wid,
498                                    component.getComponentCore());
499                        }
500                    }
501                }
502                    break;
503                case MAP: {
504                    ConfigUpdate mappedUpdate = action.downMapper.map(event.update, event.update.modify(id()));
505                    Update forwardedEvent = new Update(mappedUpdate, id());
506                    for (Component child : children) {
507                        if (child.id() != event.forwarder) {
508                            ((PortCore<ControlPort>) child.getControl()).doTrigger(forwardedEvent, wid,
509                                    component.getComponentCore());
510                        }
511                    }
512                }
513                    break;
514                case SWALLOW:
515                    break;
516                }
517                if (parent != null) {
518                    switch (action.upStrategy) {
519                    case ORIGINAL: {
520                        Update forwardedEvent = new Update(event.update, id());
521                        ((PortCore<ControlPort>) parent.getControl()).doTrigger(forwardedEvent, wid,
522                                component.getComponentCore());
523                    }
524                        break;
525
526                    case MAP: {
527                        ConfigUpdate mappedUpdate = action.upMapper.map(event.update, event.update.modify(id()));
528                        Update forwardedEvent = new Update(mappedUpdate, id());
529                        ((PortCore<ControlPort>) parent.getControl()).doTrigger(forwardedEvent, wid,
530                                component.getComponentCore());
531                    }
532                        break;
533                    case SWALLOW:
534                        break;
535                    }
536                }
537            }
538            component.postUpdate();
539        }
540    };
541
542    @Override
543    public ComponentDefinition getComponent() {
544        return component;
545    }
546
547    @Override
548    void doConfigUpdate(ConfigUpdate update) {
549        Config.Impl impl = (Config.Impl) conf;
550        impl.apply(update, ValueMerger.NONE);
551        Update forwardedEvent = new Update(update, id());
552        // forward down
553        for (Component child : children) {
554            ((PortCore<ControlPort>) child.getControl()).doTrigger(forwardedEvent, wid, this);
555        }
556        // forward up
557        if (parent != null) {
558            ((PortCore<ControlPort>) parent.getControl()).doTrigger(forwardedEvent, wid, this);
559        }
560        component.postUpdate();
561    }
562
563    @Override
564    public boolean equals(Object o) {
565        if (o instanceof JavaComponent) {
566            JavaComponent that = (JavaComponent) o;
567            return this.id().equals(that.id());
568        }
569        return false;
570    }
571
572    @Override
573    public int hashCode() {
574        int hash = 7;
575        hash = 11 * hash + Objects.hashCode(this.id());
576        return hash;
577    }
578    /*
579     * === LIFECYCLE ===
580     */
581
582    @Override
583    protected void setInactive(Component child) {
584        activeSet.remove(child);
585    }
586
587    private Set<Component> activeSet = new HashSet<Component>();
588    Handler<Start> handleStart = new Handler<Start>() {
589        @Override
590        public void handle(Start event) {
591            if (state != Component.State.PASSIVE) {
592                throw new KompicsException(JavaComponent.this + " received a Start event while in " + state + " state. "
593                        + "Duplicate Start events are not allowed!");
594            }
595            try {
596                childrenLock.readLock().lock();
597                if (!children.isEmpty()) {
598                    logger().debug("Starting...");
599                    state = Component.State.STARTING;
600                    for (ComponentCore child : children) {
601                        logger().debug("Sending Start to child: {}", child);
602                        // start child
603                        ((PortCore<ControlPort>) child.getControl()).doTrigger(Start.event, wid,
604                                component.getComponentCore());
605                    }
606                } else {
607                    logger().debug("Started!");
608                    state = Component.State.ACTIVE;
609                    if (parent != null) {
610                        ((PortCore<ControlPort>) parent.getControl()).doTrigger(
611                                new Started(component.getComponentCore()), wid, component.getComponentCore());
612                    }
613                }
614            } finally {
615                childrenLock.readLock().unlock();
616            }
617        }
618
619        @Override
620        public java.lang.Class<Start> getEventType() {
621            return Start.class;
622        };
623    };
624
625    Handler<Stop> handleStop = new Handler<Stop>() {
626        @Override
627        public void handle(Stop event) {
628            if (state != Component.State.ACTIVE) {
629                throw new KompicsException(JavaComponent.this + " received a Stop event while in " + state + " state. "
630                        + "Duplicate Stop events are not allowed!");
631            }
632            try {
633                childrenLock.readLock().lock();
634                if (!children.isEmpty()) {
635                    logger().debug("Stopping...");
636                    state = Component.State.STOPPING;
637                    for (ComponentCore child : children) {
638                        if (child.state() != Component.State.ACTIVE) {
639                            continue; // don't send stop events to already stopping components
640                        }
641                        logger().debug("Sending Stop to child: {}", child);
642                        // stop child
643                        ((PortCore<ControlPort>) child.getControl()).doTrigger(Stop.event, wid,
644                                component.getComponentCore());
645                    }
646                } else {
647                    logger().debug("Stopped!");
648                    state = Component.State.PASSIVE;
649                    component.tearDown();
650                    if (parent != null) {
651                        ((PortCore<ControlPort>) parent.getControl()).doTrigger(
652                                new Stopped(component.getComponentCore()), wid, component.getComponentCore());
653                    } else {
654                        synchronized (component.getComponentCore()) {
655                            component.getComponentCore().notifyAll();
656                        }
657                    }
658                }
659            } finally {
660                childrenLock.readLock().unlock();
661            }
662        }
663
664        @Override
665        public java.lang.Class<Stop> getEventType() {
666            return Stop.class;
667        };
668    };
669
670    Handler<Kill> handleKill = new Handler<Kill>() {
671
672        @Override
673        public void handle(Kill event) {
674            if (state != Component.State.ACTIVE) {
675                throw new KompicsException(JavaComponent.this + " received a Kill event while in " + state + " state. "
676                        + "Duplicate Kill events are not allowed!");
677            }
678            try {
679                childrenLock.readLock().lock();
680                if (!children.isEmpty()) {
681                    logger().debug("Slowly dying...");
682                    state = Component.State.STOPPING;
683                    ((PortCore<ControlPort>) getControl().getPair()).cleanEvents(); // if multiple kills are queued up
684                                                                                    // just ignore everything
685                    for (ComponentCore child : children) {
686                        if (child.state() != Component.State.ACTIVE) {
687                            continue; // don't send stop events to already stopping components
688                        }
689                        logger().debug("Sending Kill to child: {}", child);
690                        // stop child
691                        ((PortCore<ControlPort>) child.getControl()).doTrigger(Kill.event, wid,
692                                component.getComponentCore());
693                    }
694                } else {
695                    logger().debug("dying...");
696                    state = Component.State.PASSIVE;
697                    ((PortCore<ControlPort>) getControl().getPair()).cleanEvents(); // if multiple kills are queued up
698                                                                                    // just ignore everything
699                    component.tearDown();
700                    if (parent != null) {
701                        ((PortCore<ControlPort>) parent.getControl())
702                                .doTrigger(new Killed(component.getComponentCore()), wid, component.getComponentCore());
703                    } else {
704                        synchronized (component.getComponentCore()) {
705                            component.getComponentCore().notifyAll();
706                        }
707                    }
708                }
709            } finally {
710                childrenLock.readLock().unlock();
711            }
712        }
713
714        @Override
715        public java.lang.Class<Kill> getEventType() {
716            return Kill.class;
717        }
718
719    };
720
721    Handler<Killed> handleKilled = new Handler<Killed>() {
722
723        @Override
724        public void handle(Killed event) {
725            logger().debug("Got Killed event from {}", event.component);
726
727            activeSet.remove(event.component);
728            doDestroy(event.component);
729            logger().debug("Active set has {} members", activeSet.size());
730            if (activeSet.isEmpty() && (state == Component.State.STOPPING)) {
731                logger().debug("Stopped!");
732                state = Component.State.PASSIVE;
733                component.tearDown();
734                if (parent != null) {
735                    ((PortCore<ControlPort>) parent.getControl()).doTrigger(new Killed(component.getComponentCore()),
736                            wid, component.getComponentCore());
737                } else {
738                    synchronized (component.getComponentCore()) {
739                        component.getComponentCore().notifyAll();
740                    }
741                }
742            }
743        }
744
745        @Override
746        public java.lang.Class<Killed> getEventType() {
747            return Killed.class;
748        }
749    };
750
751    Handler<Started> handleStarted = new Handler<Started>() {
752        @Override
753        public void handle(Started event) {
754            logger().debug("Got Started event from {}", event.component);
755            activeSet.add(event.component);
756            logger().debug("Active set has {} members", activeSet.size());
757            try {
758                childrenLock.readLock().lock();
759                if ((activeSet.size() == children.size()) && (state == Component.State.STARTING)) {
760                    logger().debug("Started!");
761                    state = Component.State.ACTIVE;
762                    if (parent != null) {
763                        ((PortCore<ControlPort>) parent.getControl()).doTrigger(
764                                new Started(component.getComponentCore()), wid, component.getComponentCore());
765                    }
766                }
767            } finally {
768                childrenLock.readLock().unlock();
769            }
770
771        }
772
773        @Override
774        public java.lang.Class<Started> getEventType() {
775            return Started.class;
776        };
777    };
778
779    Handler<Stopped> handleStopped = new Handler<Stopped>() {
780        @Override
781        public void handle(Stopped event) {
782            logger().debug("Got Stopped event from {}", event.component);
783
784            activeSet.remove(event.component);
785            logger().debug("Active set has {} members", activeSet.size());
786            if (activeSet.isEmpty() && (state == Component.State.STOPPING)) {
787                logger().debug("Stopped!");
788                state = Component.State.PASSIVE;
789                component.tearDown();
790                if (parent != null) {
791                    ((PortCore<ControlPort>) parent.getControl()).doTrigger(new Stopped(component.getComponentCore()),
792                            wid, component.getComponentCore());
793                } else {
794                    synchronized (component.getComponentCore()) {
795                        component.getComponentCore().notifyAll();
796                    }
797                }
798            }
799
800        }
801
802        @Override
803        public java.lang.Class<Stopped> getEventType() {
804            return Stopped.class;
805        };
806
807    };
808
809}