001    /**
002     *
003     * Copyright 2004 The Apache Software Foundation
004     *
005     *  Licensed under the Apache License, Version 2.0 (the "License");
006     *  you may not use this file except in compliance with the License.
007     *  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.geronimo.gbean.runtime;
018    
019    import org.apache.commons.logging.Log;
020    import org.apache.commons.logging.LogFactory;
021    import org.apache.geronimo.gbean.AbstractName;
022    import org.apache.geronimo.gbean.AbstractNameQuery;
023    import org.apache.geronimo.gbean.InvalidConfigurationException;
024    import org.apache.geronimo.kernel.GBeanNotFoundException;
025    import org.apache.geronimo.kernel.Kernel;
026    import org.apache.geronimo.kernel.lifecycle.LifecycleAdapter;
027    import org.apache.geronimo.kernel.lifecycle.LifecycleListener;
028    import org.apache.geronimo.kernel.management.State;
029    
030    /**
031     * @version $Rev: 430508 $ $Date: 2006-08-10 12:56:47 -0700 (Thu, 10 Aug 2006) $
032     */
033    public final class GBeanDependency {
034    
035    
036        private static final Log log = LogFactory.getLog(GBeanDependency.class);
037    
038        /**
039         * The GBeanInstance to which this reference belongs.
040         */
041        private final GBeanInstance gbeanInstance;
042    
043        /**
044         * The target objectName targetName to watch for a connection.
045         */
046        private final AbstractName targetName;
047    
048        /**
049         * Our listener for lifecycle events
050         */
051        private final LifecycleListener listener;
052    
053        /**
054         * The kernel to which the reference is bound.
055         */
056        private final Kernel kernel;
057    
058        private boolean targetRunning = false;
059        private boolean dependencyRegistered = false;
060    
061        public GBeanDependency(GBeanInstance gbeanInstance, AbstractName targetName, Kernel kernel) throws InvalidConfigurationException {
062            this.gbeanInstance = gbeanInstance;
063            this.kernel = kernel;
064            this.targetName = targetName;
065            listener = createLifecycleListener();
066        }
067    
068        public AbstractName getTargetName() {
069            return targetName;
070        }
071    
072        public final synchronized void online() {
073            //TODO consider including interfaces in query
074            AbstractNameQuery query = new AbstractNameQuery(targetName, null);
075            kernel.getLifecycleMonitor().addLifecycleListener(listener, query);
076            targetRunning = isRunning(kernel, targetName);
077        }
078    
079        public synchronized boolean start() {
080            if (targetRunning && !dependencyRegistered) {
081                AbstractName abstractName = gbeanInstance.getAbstractName();
082                kernel.getDependencyManager().addDependency(abstractName, targetName);
083                dependencyRegistered = true;
084            }
085            return targetRunning;
086        }
087    
088    
089        public synchronized void stop() {
090            if (dependencyRegistered) {
091                AbstractName abstractName = gbeanInstance.getAbstractName();
092                kernel.getDependencyManager().removeDependency(abstractName, targetName);
093                dependencyRegistered = false;
094            }
095        }
096    
097        public final synchronized void offline() {
098            // make sure we are stopped
099            stop();
100    
101            kernel.getLifecycleMonitor().removeLifecycleListener(listener);
102            targetRunning = false;
103        }
104    
105        private synchronized void attemptFullStart() {
106            try {
107                // there could be an issue with really badly written components holding up a stop when the
108                // component never reached the starting phase... then a target registers and we automatically
109                // attempt to restart
110    //            waitingForMe = false;
111                gbeanInstance.start();
112            } catch (Exception e) {
113                log.warn("Exception occured while attempting to fully start: objectName=" + gbeanInstance.getObjectName(), e);
114            }
115        }
116    
117        protected LifecycleListener createLifecycleListener() {
118            return new LifecycleAdapter() {
119                public void running(AbstractName abstractName) {
120                    addTarget(abstractName);
121                }
122    
123                public void stopped(AbstractName abstractName) {
124                    removeTarget(abstractName);
125                }
126    
127                public void failed(AbstractName abstractName) {
128                    removeTarget(abstractName);
129                }
130    
131                public void unloaded(AbstractName abstractName) {
132                    removeTarget(abstractName);
133                }
134            };
135        }
136    
137        protected final void addTarget(AbstractName abstractName) {
138            // if we are running, and we now have two valid targets, which is an illegal state so we need to fail
139            synchronized (this) {
140                targetRunning = true;
141                GBeanInstance gbeanInstance1 = gbeanInstance;
142                if (gbeanInstance1.getStateInstance() == State.RUNNING) {
143                    log.error("Illegal state: two or more targets are running for a dependency: " + getDescription() +
144                            ",\n    newTarget=" + abstractName);
145                }
146                attemptFullStart();
147            }
148        }
149    
150        protected final void removeTarget(AbstractName abstractName) {
151            synchronized (this) {
152                targetRunning = false;
153                GBeanInstance gbeanInstance1 = gbeanInstance;
154                if (gbeanInstance1.getStateInstance() == State.RUNNING) {
155                    // we no longer have a valid target, which is an illegal state so we need to fail
156                    log.error("Illegal state: current target for a single valued reference stopped: " + getDescription() +
157                            ",\n    stopped Target=" + abstractName);
158                    gbeanInstance1.referenceFailed();
159                }
160            }
161        }
162    
163    
164        /**
165         * Is the component in the Running state
166         *
167         * @param objectName name of the component to check
168         * @return true if the component is running; false otherwise
169         */
170        private boolean isRunning(Kernel kernel, AbstractName objectName) {
171            try {
172                final int state = kernel.getGBeanState(objectName);
173                return state == State.RUNNING_INDEX;
174            } catch (GBeanNotFoundException e) {
175                // gbean is no longer registerd
176                return false;
177            } catch (Exception e) {
178                // problem getting the attribute, gbean has most likely failed
179                return false;
180            }
181        }
182    
183        protected final String getDescription() {
184            return "\n    GBeanInstance: " + gbeanInstance.getName() +
185                    "\n    Target Name: " + targetName;
186        }
187    
188        public boolean equals(Object o) {
189            if (this == o) return true;
190            if (o == null || getClass() != o.getClass()) return false;
191    
192            final GBeanDependency that = (GBeanDependency) o;
193    
194            if (gbeanInstance != null ? !gbeanInstance.equals(that.gbeanInstance) : that.gbeanInstance != null) {
195                return false;
196            }
197            return !(targetName != null ? !targetName.equals(that.targetName) : that.targetName != null);
198    
199        }
200    
201        public int hashCode() {
202            int result;
203            result = (gbeanInstance != null ? gbeanInstance.hashCode() : 0);
204            result = 29 * result + (targetName != null ? targetName.hashCode() : 0);
205            return result;
206        }
207    }