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.geronimo.gbean.runtime;
018    
019    import org.apache.geronimo.gbean.AbstractName;
020    import org.apache.geronimo.gbean.GReferenceInfo;
021    import org.apache.geronimo.gbean.InvalidConfigurationException;
022    import org.apache.geronimo.kernel.ClassLoading;
023    import org.apache.geronimo.kernel.GBeanNotFoundException;
024    import org.apache.geronimo.kernel.Kernel;
025    import org.apache.geronimo.kernel.management.State;
026    import org.apache.commons.logging.Log;
027    import org.apache.commons.logging.LogFactory;
028    
029    import java.lang.reflect.Method;
030    import java.lang.reflect.Modifier;
031    
032    /**
033     * @version $Rev: 549825 $ $Date: 2007-06-22 10:17:31 -0400 (Fri, 22 Jun 2007) $
034     */
035    public abstract class AbstractGBeanReference implements GBeanReference {
036        /**
037         * Should we proxy references.
038         */
039        protected static final boolean NO_PROXY = Boolean.getBoolean("Xorg.apache.geronimo.gbean.NoProxy");
040        static {
041            if (NO_PROXY) {
042                Log log = LogFactory.getLog(AbstractGBeanReference.class);
043                log.warn("GBean reference proxies has been disabled:  This is an experimental and untested operating mode");
044            }
045        }
046    
047        /**
048         * Name of this reference.
049         */
050        private final String name;
051    
052        /**
053         * Interface this GBeanInstance uses to refer to the other.
054         */
055        private final Class referenceType;
056    
057        /**
058         * Proxy type which is injected into the GBeanInstance.
059         */
060        private final Class proxyType;
061    
062        /**
063         * The GBeanInstance to which this reference belongs.
064         */
065        private final GBeanInstance gbeanInstance;
066    
067        /**
068         * The method that will be called to set the attribute value.  If null, the value will be set with
069         * a constructor argument
070         */
071        private final MethodInvoker setInvoker;
072    
073        private final boolean hasTargets;
074    
075        /**
076         * The metadata for this reference
077         */
078        private final GReferenceInfo referenceInfo;
079    
080        /**
081         * The kernel to which the reference is bound.
082         */
083        private final Kernel kernel;
084    
085        /**
086         * Proxy for this reference
087         */
088        private Object proxy;
089    
090    
091        public AbstractGBeanReference(GBeanInstance gbeanInstance, GReferenceInfo referenceInfo, Kernel kernel, boolean hasTargets) throws InvalidConfigurationException {
092            this.gbeanInstance = gbeanInstance;
093            this.referenceInfo = referenceInfo;
094            this.kernel = kernel;
095            this.hasTargets = hasTargets;
096    
097            this.name = referenceInfo.getName();
098            try {
099                this.referenceType = ClassLoading.loadClass(referenceInfo.getReferenceType(), gbeanInstance.getType().getClassLoader());
100            } catch (ClassNotFoundException e) {
101                throw new InvalidConfigurationException("Could not load Reference Type: " + getDescription(), e);
102            }
103            if (Modifier.isFinal(referenceType.getModifiers())) {
104                throw new IllegalArgumentException("Proxy interface cannot be a final class: " + referenceType.getName());
105            }
106            try {
107                this.proxyType = ClassLoading.loadClass(referenceInfo.getProxyType(), gbeanInstance.getType().getClassLoader());
108            } catch (ClassNotFoundException e) {
109                throw new InvalidConfigurationException("Could not load Proxy Type:" + getDescription(), e);
110            }
111    
112            if (referenceInfo.getSetterName() != null) {
113                try {
114                    String setterName = referenceInfo.getSetterName();
115                    Method setterMethod = gbeanInstance.getType().getMethod(setterName, new Class[] {proxyType});
116                    if (NO_PROXY) {
117                        setInvoker = new ReflectionMethodInvoker(setterMethod);
118                    } else {
119                        setInvoker = new FastMethodInvoker(setterMethod);
120                    }
121                } catch (NoSuchMethodException e) {
122                    throw new InvalidConfigurationException("Setter method not found " + getDescription(), e);
123                }
124            } else {
125                setInvoker = null;
126            }
127    
128        }
129    
130        protected final Kernel getKernel() {
131            return kernel;
132        }
133    
134        public final GBeanInstance getGBeanInstance() {
135            return gbeanInstance;
136        }
137    
138        public final String getName() {
139            return name;
140        }
141    
142        public final GReferenceInfo getReferenceInfo() {
143            return referenceInfo;
144        }
145    
146        public final Class getReferenceType() {
147            return referenceType;
148        }
149    
150        public final Class getProxyType() {
151            return proxyType;
152        }
153    
154        public final Object getProxy() {
155            return proxy;
156        }
157    
158        protected final void setProxy(Object proxy) {
159            this.proxy = proxy;
160        }
161    
162        /**
163         * Is the component in the Running state
164         *
165         * @param abstractName name of the component to check
166         * @return true if the component is running; false otherwise
167         */
168        protected boolean isRunning(Kernel kernel, AbstractName abstractName) {
169            try {
170                final int state = kernel.getGBeanState(abstractName);
171                return state == State.RUNNING_INDEX;
172            } catch (GBeanNotFoundException e) {
173                // mbean is no longer registerd
174                return false;
175            } catch (Exception e) {
176                // problem getting the attribute, mbean has most likely failed
177                return false;
178            }
179        }
180    
181        protected final String getDescription() {
182            return "\n    GBeanInstance: " + gbeanInstance.getName() +
183                    "\n    Reference Name: " + getName() +
184                    "\n    Reference Type: " + referenceInfo.getReferenceType() +
185                    "\n    Proxy Type: " + referenceInfo.getProxyType();
186        }
187    
188        public final synchronized void inject(Object target) throws Exception {
189            // set the proxy into the instance
190            if (setInvoker != null && hasTargets) {
191                setInvoker.invoke(target, new Object[]{getProxy()});
192            }
193        }
194    }