/** * * Copyright 2004 The Apache Software Foundation * * 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.apache.geronimo.gbean.runtime; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import javax.management.ObjectName; import org.apache.geronimo.gbean.GReferenceInfo; import org.apache.geronimo.gbean.InvalidConfigurationException; import org.apache.geronimo.kernel.ClassLoading; import org.apache.geronimo.kernel.DependencyManager; import org.apache.geronimo.kernel.GBeanNotFoundException; import org.apache.geronimo.kernel.Kernel; import org.apache.geronimo.kernel.lifecycle.LifecycleListener; import org.apache.geronimo.kernel.management.State; /** * @version $Rev$ $Date$ */ public abstract class AbstractGBeanReference implements GBeanReference { /** * Name of this reference. */ private final String name; /** * Interface this GBeanInstance uses to refer to the other. */ private final Class referenceType; /** * Proxy type which is injected into the GBeanInstance. */ private final Class proxyType; /** * The GBeanInstance to which this reference belongs. */ private final GBeanInstance gbeanInstance; /** * The method that will be called to set the attribute value. If null, the value will be set with * a constructor argument */ private final MethodInvoker setInvoker; /** * The target objectName patterns to watch for a connection. */ private Set patterns = Collections.EMPTY_SET; /** * Our listener for lifecycle events */ private final LifecycleListener listener; /** * Current set of targets */ private final Set targets = new HashSet(); /** * The metadata for this reference */ private final GReferenceInfo referenceInfo; /** * The kernel to which the reference is bound. */ private final Kernel kernel; /** * The dependency manager of the kernel. */ private final DependencyManager dependencyManager; /** * Proxy for this reference */ private Object proxy; /** * is this reference online */ private boolean isOnline = false; public AbstractGBeanReference(GBeanInstance gbeanInstance, GReferenceInfo referenceInfo, Kernel kernel, DependencyManager dependencyManager) throws InvalidConfigurationException { this.gbeanInstance = gbeanInstance; this.referenceInfo = referenceInfo; this.kernel = kernel; this.dependencyManager = dependencyManager; this.name = referenceInfo.getName(); try { this.referenceType = ClassLoading.loadClass(referenceInfo.getReferenceType(), gbeanInstance.getType().getClassLoader()); } catch (ClassNotFoundException e) { throw new InvalidConfigurationException("Could not load Reference Type: " + getDescription()); } if (Modifier.isFinal(referenceType.getModifiers())) { throw new IllegalArgumentException("Proxy interface cannot be a final class: " + referenceType.getName()); } try { this.proxyType = ClassLoading.loadClass(referenceInfo.getProxyType(), gbeanInstance.getType().getClassLoader()); } catch (ClassNotFoundException e) { throw new InvalidConfigurationException("Could not load Proxy Type:" + getDescription()); } if (referenceInfo.getSetterName() != null) { try { String setterName = referenceInfo.getSetterName(); Method setterMethod = gbeanInstance.getType().getMethod(setterName, new Class[] {proxyType}); setInvoker = new FastMethodInvoker(setterMethod); } catch (NoSuchMethodException e) { throw new InvalidConfigurationException("Setter method not found " + getDescription()); } } else { setInvoker = null; } listener = createLifecycleListener(); } protected abstract LifecycleListener createLifecycleListener(); protected abstract void targetAdded(ObjectName target); protected abstract void targetRemoved(ObjectName target); protected final Kernel getKernel() { return kernel; } protected final DependencyManager getDependencyManager() { return dependencyManager; } public final GBeanInstance getGBeanInstance() { return gbeanInstance; } public final String getName() { return name; } public final GReferenceInfo getReferenceInfo() { return referenceInfo; } public final Class getReferenceType() { return referenceType; } public final Class getProxyType() { return proxyType; } public final Object getProxy() { return proxy; } protected final void setProxy(Object proxy) { this.proxy = proxy; } public final Set getPatterns() { return patterns; } public final void setPatterns(Set patterns) { if (isOnline) { throw new IllegalStateException("Pattern set can not be modified while online"); } if (patterns == null || patterns.isEmpty() || (patterns.size() == 1 && patterns.iterator().next() == null)) { this.patterns = Collections.EMPTY_SET; } else { patterns = new HashSet(patterns); for (Iterator iterator = this.patterns.iterator(); iterator.hasNext();) { if (iterator.next() == null) { iterator.remove(); //there can be at most one null value in a set. break; } } this.patterns = Collections.unmodifiableSet(patterns); } } public final synchronized void online() { Set gbeans = kernel.listGBeans(patterns); for (Iterator objectNameIterator = gbeans.iterator(); objectNameIterator.hasNext();) { ObjectName target = (ObjectName) objectNameIterator.next(); if (!targets.contains(target)) { // if the bean is running add it to the runningTargets list if (isRunning(kernel, target)) { targets.add(target); } } } kernel.getLifecycleMonitor().addLifecycleListener(listener, patterns); isOnline = true; } public final synchronized void offline() { // make sure we are stoped stop(); kernel.getLifecycleMonitor().removeLifecycleListener(listener); targets.clear(); isOnline = false; } protected final Set getTargets() { return targets; } protected final void addTarget(ObjectName objectName) { if (!targets.contains(objectName)) { targets.add(objectName); targetAdded(objectName); } } protected final void removeTarget(ObjectName objectName) { boolean wasTarget = targets.remove(objectName); if (wasTarget) { targetRemoved(objectName); } } public final synchronized void inject(Object target) throws Exception { // set the proxy into the instance if (setInvoker != null && patterns.size() > 0) { setInvoker.invoke(target, new Object[]{getProxy()}); } } /** * Is the component in the Running state * * @param objectName name of the component to check * @return true if the component is running; false otherwise */ private boolean isRunning(Kernel kernel, ObjectName objectName) { try { final int state = kernel.getGBeanState(objectName); return state == State.RUNNING_INDEX; } catch (GBeanNotFoundException e) { // mbean is no longer registerd return false; } catch (Exception e) { // problem getting the attribute, mbean has most likely failed return false; } } protected final String getDescription() { return "\n GBeanInstance: " + gbeanInstance.getName() + "\n Reference Name: " + getName() + "\n Reference Type: " + referenceInfo.getReferenceType() + "\n Proxy Type: " + referenceInfo.getProxyType(); } }