001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.xbean.kernel;
018    
019    /**
020     * This condition that requires another service be in the RUNNING state to be satisfied.
021     *
022     * @author Dain Sundstrom
023     * @version $Id$
024     * @since 2.0
025     */
026    public class RunningServiceCondition implements ServiceCondition {
027        private final ServiceName dependency;
028        private final boolean ownedRelationship;
029        private final boolean stopOnServiceShutdown;
030        private final DependencyServiceMonitor serviceMonitor = new DependencyServiceMonitor();
031    
032        private ServiceConditionContext context;
033        private boolean satisfied = true;
034        private StoppedServiceCondition stoppedServiceCondition;
035    
036        /**
037         * Creates a condition that requires the specified service be in the RUNNING state to be satisfied.
038         *
039         * @param dependency the service that must be running
040         * @param ownedRelationship if true the condition will register the relationship
041         * @param stopOnServiceShutdown if the our service should be stopped when the specified service shutsdown
042         */
043        public RunningServiceCondition(ServiceName dependency, boolean ownedRelationship, boolean stopOnServiceShutdown) {
044            if (dependency == null) throw new NullPointerException("dependency is null");
045            this.dependency = dependency;
046            this.ownedRelationship = ownedRelationship;
047            this.stopOnServiceShutdown = stopOnServiceShutdown;
048        }
049    
050        /**
051         * {@inheritDoc}
052         */
053        public synchronized void initialize(ServiceConditionContext context) {
054            if (context == null) throw new NullPointerException("context is null");
055    
056            // if we have no been destroyed, destroy not
057            if (this.context != null) {
058                destroy();
059            }
060    
061            this.context = context;
062    
063            satisfied = false;
064            context.getKernel().addServiceMonitor(serviceMonitor, dependency);
065            if (ownedRelationship) {
066                // todo register owned relationship
067            }
068    
069            if (stopOnServiceShutdown) {
070                stoppedServiceCondition = new StoppedServiceCondition(context.getServiceName());
071            }
072        }
073    
074        /**
075         * {@inheritDoc}
076         */
077        public synchronized boolean isSatisfied() {
078            if (context == null) {
079                // we are not initialized so default to true
080                return true;
081            }
082    
083            if (!satisfied) {
084                try {
085                    // grab a synchronized lock on the service factory to assure that the state doesn't change while
086                    // adding the dependency.... the kernel will grab the same lock when getting the stop dependencies
087                    ServiceFactory serviceFactory = context.getKernel().getServiceFactory(dependency);
088                    synchronized (serviceFactory) {
089                        if (context.getKernel().getService(dependency) == ServiceState.RUNNING) {
090                            if (stopOnServiceShutdown) {
091                                serviceFactory.addStopCondition(stoppedServiceCondition);
092                            }
093                            satisfied = true;
094                            context.getKernel().removeServiceMonitor(serviceMonitor);
095                        }
096                    }
097                } catch (ServiceNotFoundException ignored) {
098                    // service hasn't registered yet
099                }
100            }
101            return satisfied;
102        }
103    
104        /**
105         * {@inheritDoc}
106         */
107        public synchronized void destroy() {
108            if (context == null) {
109                // we are already destroyed
110                return;
111            }
112    
113            context.getKernel().removeServiceMonitor(serviceMonitor);
114            context = null;
115            satisfied = true;
116            if (ownedRelationship) {
117                // todo unregister owned relationship
118            }
119            if (stopOnServiceShutdown) {
120                stoppedServiceCondition.destroy();
121                stoppedServiceCondition = null;
122            }
123        }
124    
125        private class DependencyServiceMonitor extends NullServiceMonitor {
126            public void serviceRunning(ServiceEvent serviceEvent) {
127                synchronized (RunningServiceCondition.this) {
128                    if (context != null) {
129                        // we aren't running anymore
130                        return;
131                    }
132    
133                    if (!satisfied) {
134                        return;
135                    }
136    
137                    if (isSatisfied()) {
138                        context.setSatisfied();
139                    }
140                }
141            }
142        }
143    }