You are viewing a plain text version of this content. The canonical link for it is here.
Posted to scm@geronimo.apache.org by da...@apache.org on 2004/11/23 21:37:05 UTC

svn commit: r106345 - in geronimo/trunk/modules/kernel/src/java/org/apache/geronimo: gbean/jmx kernel

Author: dain
Date: Tue Nov 23 12:37:03 2004
New Revision: 106345

Added:
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractGBeanReference.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanCollectionProxy.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanCollectionReference.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanReference.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanSingleProxy.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanSingleReference.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleAdapter.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleListener.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleMonitor.java
Removed:
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CollectionProxy.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBeanReference.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/Proxy.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/SingleProxy.java
Modified:
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractManagedObject.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibMethodInterceptor.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibProxyFactory.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBean.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/ProxyMethodInterceptor.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/VMMethodInterceptor.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/DependencyManager.java
   geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/Kernel.java
Log:
Fixed lifecycle notification bugs.
Moved notification monitor code from GBeanReference to a LifecycleMonitor kernel service.
The LifecycleMoniter serverice should NOT be used until we are happy with it.


Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractGBeanReference.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractGBeanReference.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractGBeanReference.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,260 @@
+/**
+ *
+ * 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.jmx;
+
+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.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.ObjectName;
+
+import org.apache.geronimo.kernel.LifecycleAdapter;
+import org.apache.geronimo.kernel.LifecycleListener;
+import org.apache.geronimo.gbean.GReferenceInfo;
+import org.apache.geronimo.gbean.InvalidConfigurationException;
+import org.apache.geronimo.kernel.ClassLoading;
+import org.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.kernel.LifecycleListener;
+import org.apache.geronimo.kernel.LifecycleAdapter;
+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 GBeanMBean uses to refer to the other.
+     */
+    private final Class type;
+
+    /**
+     * The GBeanMBean to which this reference belongs.
+     */
+    private final GBeanMBean gmbean;
+
+    /**
+     * 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 kernel to which the reference is bound.
+     */
+    private Kernel kernel;
+
+    public AbstractGBeanReference(GBeanMBean gmbean, GReferenceInfo referenceInfo, Class constructorType) throws InvalidConfigurationException {
+        this.gmbean = gmbean;
+        this.name = referenceInfo.getName();
+        try {
+            this.type = ClassLoading.loadClass(referenceInfo.getType(), gmbean.getClassLoader());
+        } catch (ClassNotFoundException e) {
+            throw new InvalidConfigurationException("Could not load reference proxy interface class:" +
+                    " name=" + name +
+                    " class=" + referenceInfo.getType());
+        }
+        if (Modifier.isFinal(type.getModifiers())) {
+            throw new IllegalArgumentException("Proxy interface cannot be a final class: " + type.getName());
+        }
+
+        if (constructorType != null) {
+            setInvoker = null;
+        } else {
+            Method setterMethod = searchForSetter(gmbean, referenceInfo);
+            setInvoker = new FastMethodInvoker(setterMethod);
+        }
+
+        listener = new LifecycleAdapter() {
+            public void running(ObjectName objectName) {
+                if (!targets.contains(objectName)) {
+                    targets.add(objectName);
+                    targetAdded(objectName);
+                }
+            }
+
+            public void stoping(ObjectName objectName) {
+                boolean wasTarget = targets.remove(objectName);
+                if (wasTarget) {
+                    targetRemoved(objectName);
+                }
+            }
+        };
+    }
+
+    protected final Kernel getKernel() {
+        return kernel;
+    }
+
+    protected final GBeanMBean getGBeanMBean() {
+        return gmbean;
+    }
+
+    public final String getName() {
+        return name;
+    }
+
+    public final Class getType() {
+        return type;
+    }
+
+    public final Set getPatterns() {
+        return patterns;
+    }
+
+    public final void setPatterns(Set patterns) {
+        if (kernel != null) {
+            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(Kernel kernel) {
+        this.kernel = kernel;
+
+        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);
+    }
+
+    public final synchronized void offline() {
+        // make sure we are stoped
+        stop();
+
+        kernel.getLifecycleMonitor().removeLifecycleListener(listener);
+
+        targets.clear();
+        kernel = null;
+    }
+
+    protected abstract void targetAdded(ObjectName target);
+
+    protected abstract void targetRemoved(ObjectName target);
+
+    protected final Set getTargets() {
+        return targets;
+    }
+
+    public final synchronized void inject() throws Exception {
+        // set the proxy into the instance
+        if (setInvoker != null && patterns.size() > 0) {
+            setInvoker.invoke(gmbean.getTarget(), 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 = ((Integer) kernel.getAttribute(objectName, "state")).intValue();
+            return state == State.RUNNING_INDEX;
+        } catch (AttributeNotFoundException e) {
+            // ok -- mbean is not a startable
+            return true;
+        } catch (InstanceNotFoundException e) {
+            // mbean is no longer registerd
+            return false;
+        } catch (Exception e) {
+            // problem getting the attribute, mbean has most likely failed
+            return false;
+        }
+    }
+
+    protected static Method searchForSetter(GBeanMBean gMBean, GReferenceInfo referenceInfo) throws InvalidConfigurationException {
+        if (referenceInfo.getSetterName() == null) {
+            // no explicit name give so we must search for a name
+            String setterName = "set" + referenceInfo.getName();
+            Method[] methods = gMBean.getType().getMethods();
+            for (int i = 0; i < methods.length; i++) {
+                Method method = methods[i];
+                if (method.getParameterTypes().length == 1 &&
+                        method.getReturnType() == Void.TYPE &&
+                        setterName.equalsIgnoreCase(method.getName())) {
+
+                    return method;
+                }
+            }
+        } else {
+            // even though we have an exact name we need to search the methods because
+            // we don't know the parameter type
+            Method[] methods = gMBean.getType().getMethods();
+            String setterName = referenceInfo.getSetterName();
+            for (int i = 0; i < methods.length; i++) {
+                Method method = methods[i];
+                if (method.getParameterTypes().length == 1 &&
+                        method.getReturnType() == Void.TYPE &&
+                        setterName.equals(method.getName())) {
+
+                    return method;
+                }
+            }
+        }
+        throw new InvalidConfigurationException("Target does not have specified method:" +
+                " name=" + referenceInfo.getName() +
+                " targetClass=" + gMBean.getType().getName());
+    }
+}

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractManagedObject.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractManagedObject.java?view=diff&rev=106345&p1=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractManagedObject.java&r1=106344&p2=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractManagedObject.java&r2=106345
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractManagedObject.java	(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/AbstractManagedObject.java	Tue Nov 23 12:37:03 2004
@@ -166,10 +166,10 @@
     }
 
     public void preDeregister() throws Exception {
+        sendNotification(NotificationType.OBJECT_DELETED);
     }
 
     public void postDeregister() {
-        sendNotification(NotificationType.OBJECT_DELETED);
         synchronized (this) {
             server = null;
             objectName = null;

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibMethodInterceptor.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibMethodInterceptor.java?view=diff&rev=106345&p1=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibMethodInterceptor.java&r1=106344&p2=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibMethodInterceptor.java&r2=106345
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibMethodInterceptor.java	(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibMethodInterceptor.java	Tue Nov 23 12:37:03 2004
@@ -67,13 +67,9 @@
     }
 
     public synchronized void connect(MBeanServerConnection server, ObjectName objectName) {
-        this.connect(server, objectName, false);
-    }
-
-    public synchronized void connect(MBeanServerConnection server, ObjectName objectName, boolean stopped) {
         assert server != null && objectName != null;
         this.objectName = objectName;
-        this.stopped = stopped;
+        stopped = false;
         gbeanInvokers = createGBeanInvokers(server, objectName);
     }
 
@@ -81,17 +77,6 @@
         stopped = true;
         objectName = null;
         gbeanInvokers = null;
-    }
-
-    public synchronized void start() {
-        if (gbeanInvokers == null) {
-            throw new IllegalStateException("Proxy is not connected");
-        }
-        this.stopped = false;
-    }
-
-    public synchronized void stop() {
-        this.stopped = true;
     }
 
     public final Object intercept(final Object object, final Method method, final Object[] args, final MethodProxy proxy) throws Throwable {

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibProxyFactory.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibProxyFactory.java?view=diff&rev=106345&p1=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibProxyFactory.java&r1=106344&p2=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibProxyFactory.java&r2=106345
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibProxyFactory.java	(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CGLibProxyFactory.java	Tue Nov 23 12:37:03 2004
@@ -16,8 +16,6 @@
  */
 package org.apache.geronimo.gbean.jmx;
 
-import java.lang.reflect.InvocationTargetException;
-
 import net.sf.cglib.proxy.Callback;
 import net.sf.cglib.proxy.Enhancer;
 import net.sf.cglib.proxy.MethodInterceptor;

Deleted: /geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CollectionProxy.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/CollectionProxy.java?view=auto&rev=106344
==============================================================================

Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanCollectionProxy.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanCollectionProxy.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanCollectionProxy.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,293 @@
+/**
+ *
+ * Copyright 2003-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.jmx;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.geronimo.gbean.ReferenceCollection;
+import org.apache.geronimo.gbean.ReferenceCollectionEvent;
+import org.apache.geronimo.gbean.ReferenceCollectionListener;
+import org.apache.geronimo.kernel.Kernel;
+
+/**
+ * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
+ */
+public class GBeanCollectionProxy {
+    private static final Log log = LogFactory.getLog(GBeanCollectionProxy.class);
+
+    /**
+     * Name of the reference
+     */
+    public String name;
+
+    /**
+     * A map from object names to the proxy
+     */
+    private Map proxies = new HashMap();
+
+    /**
+     * A map from object names to the proxy interceptor
+     */
+    private Map interceptors = new HashMap();
+
+    /**
+     * Proxy collection implementation held by the component
+     */
+    private ClientCollection proxy = new ClientCollection();
+
+    /**
+     * Facotry for proxy instances.
+     */
+    private ProxyFactory factory;
+    private Kernel kernel;
+
+    public GBeanCollectionProxy(Kernel kernel, String name, Class type, Set targets) {
+        this.kernel = kernel;
+        this.name = name;
+        factory = ProxyFactory.newProxyFactory(type);
+
+        for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+            addTarget((ObjectName) iterator.next());
+        }
+    }
+
+    public synchronized void destroy() {
+        for (Iterator iterator = interceptors.values().iterator(); iterator.hasNext();) {
+            ProxyMethodInterceptor interceptor = (ProxyMethodInterceptor) iterator.next();
+            interceptor.disconnect();
+        }
+        proxy.listeners = null;
+        kernel = null;
+        name = null;
+        proxies = null;
+        interceptors = null;
+        proxy = null;
+        factory = null;
+    }
+
+    public synchronized Object getProxy() {
+        return proxy;
+    }
+
+    public synchronized void addTarget(ObjectName target) {
+        // if this is a new target...
+        if (!proxies.containsKey(target)) {
+            // create the interceptor
+            ProxyMethodInterceptor interceptor = factory.getMethodInterceptor();
+            interceptor.connect(kernel.getMBeanServer(), target);
+            interceptors.put(target, interceptor);
+
+            // create the proxy
+            Object targetProxy = factory.create(interceptor);
+            proxies.put(target, targetProxy);
+            proxy.fireMemberAdddedEvent(targetProxy);
+        }
+    }
+
+    public synchronized void removeTarget(ObjectName target) {
+        Object targetProxy = proxies.remove(target);
+        if (targetProxy != null) {
+            proxy.fireMemberRemovedEvent(targetProxy);
+            ProxyMethodInterceptor interceptor = (ProxyMethodInterceptor) interceptors.remove(target);
+            if (interceptor != null) {
+                interceptor.disconnect();
+            }
+        }
+    }
+
+    private class ClientCollection implements ReferenceCollection {
+        private Set listeners = new HashSet();
+
+        public boolean isStopped() {
+            synchronized (GBeanCollectionProxy.this) {
+                return proxy == null;
+            }
+        }
+
+        public void addReferenceCollectionListener(ReferenceCollectionListener listener) {
+            synchronized (GBeanCollectionProxy.this) {
+                listeners.add(listener);
+            }
+        }
+
+        public void removeReferenceCollectionListener(ReferenceCollectionListener listener) {
+            synchronized (GBeanCollectionProxy.this) {
+                listeners.remove(listener);
+            }
+        }
+
+        private void fireMemberAdddedEvent(Object member) {
+            ArrayList listenerCopy;
+            synchronized (GBeanCollectionProxy.this) {
+                listenerCopy = new ArrayList(listeners);
+            }
+            for (Iterator iterator = listenerCopy.iterator(); iterator.hasNext();) {
+                ReferenceCollectionListener listener = (ReferenceCollectionListener) iterator.next();
+                try {
+                    listener.memberAdded(new ReferenceCollectionEvent(name, member));
+                } catch (Throwable t) {
+                    log.error("Listener threw exception", t);
+                }
+            }
+        }
+
+        private void fireMemberRemovedEvent(Object member) {
+            ArrayList listenerCopy;
+            synchronized (GBeanCollectionProxy.this) {
+                listenerCopy = new ArrayList(listeners);
+            }
+            for (Iterator iterator = listenerCopy.iterator(); iterator.hasNext();) {
+                ReferenceCollectionListener listener = (ReferenceCollectionListener) iterator.next();
+                try {
+                    listener.memberRemoved(new ReferenceCollectionEvent(name, member));
+                } catch (Throwable t) {
+                    log.error("Listener threw exception", t);
+                }
+            }
+        }
+
+        public int size() {
+            synchronized (GBeanCollectionProxy.this) {
+                if (proxy == null) {
+                    return 0;
+                }
+                return proxies.size();
+            }
+        }
+
+        public boolean isEmpty() {
+            synchronized (GBeanCollectionProxy.this) {
+                if (proxy == null) {
+                    return true;
+                }
+                return proxies.isEmpty();
+            }
+        }
+
+        public boolean contains(Object o) {
+            synchronized (GBeanCollectionProxy.this) {
+                if (proxy == null) {
+                    return false;
+                }
+                return proxies.containsValue(o);
+            }
+        }
+
+        public Iterator iterator() {
+            synchronized (GBeanCollectionProxy.this) {
+                if (proxy == null) {
+                    return new Iterator() {
+                        public boolean hasNext() {
+                            return false;
+                        }
+
+                        public Object next() {
+                            throw new NoSuchElementException();
+                        }
+
+                        public void remove() {
+                            throw new UnsupportedOperationException();
+                        }
+                    };
+                }
+
+                return new Iterator() {
+                    // copy the proxies, so the client can iterate without concurrent modification
+                    // this is necssary since the client has nothing to synchronize on
+                    private final Iterator iterator = new ArrayList(proxies.values()).iterator();
+
+                    public boolean hasNext() {
+                        return iterator.hasNext();
+                    }
+
+                    public Object next() {
+                        return iterator.next();
+                    }
+
+                    public void remove() {
+                        throw new UnsupportedOperationException();
+                    }
+                };
+            }
+        }
+
+        public Object[] toArray() {
+            synchronized (GBeanCollectionProxy.this) {
+                if (proxy == null) {
+                    return new Object[0];
+                }
+                return proxies.values().toArray();
+            }
+        }
+
+        public Object[] toArray(Object a[]) {
+            synchronized (GBeanCollectionProxy.this) {
+                if (proxy == null) {
+                    if (a.length > 0) {
+                        a[0] = null;
+                    }
+                    return a;
+                }
+                return proxies.values().toArray(a);
+            }
+        }
+
+        public boolean containsAll(Collection c) {
+            synchronized (GBeanCollectionProxy.this) {
+                if (proxy == null) {
+                    return c.isEmpty();
+                }
+                return proxies.values().containsAll(c);
+            }
+        }
+
+        public boolean add(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean addAll(Collection c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean removeAll(Collection c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public boolean retainAll(Collection c) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void clear() {
+            throw new UnsupportedOperationException();
+        }
+    }
+}

Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanCollectionReference.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanCollectionReference.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanCollectionReference.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,79 @@
+/**
+ *
+ * Copyright 2003-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.jmx;
+
+import javax.management.ObjectName;
+
+import org.apache.geronimo.gbean.GReferenceInfo;
+import org.apache.geronimo.gbean.InvalidConfigurationException;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class GBeanCollectionReference extends AbstractGBeanReference {
+    /**
+     * Proxy to the to this connection.
+     */
+    private GBeanCollectionProxy proxy;
+
+    public GBeanCollectionReference(GBeanMBean gmbean, GReferenceInfo referenceInfo, Class constructorType) throws InvalidConfigurationException {
+        super(gmbean, referenceInfo, constructorType);
+    }
+
+    public synchronized void start() throws Exception {
+        // if there are no patterns then there is nothing to start
+        if (getPatterns().isEmpty()) {
+            return;
+        }
+
+        // if we already have a proxy then we have already been started
+        if (proxy != null) {
+            return;
+        }
+
+        // add a dependency on our target and create the proxy
+        proxy = new GBeanCollectionProxy(getKernel(), getName(), getType(), getTargets());
+    }
+
+    public synchronized void stop() {
+        if (proxy != null) {
+            proxy.destroy();
+            proxy = null;
+        }
+    }
+
+    public Object getProxy() {
+        if (proxy == null) {
+            return null;
+        } else {
+            return proxy.getProxy();
+        }
+    }
+
+    public synchronized void targetAdded(ObjectName target) {
+        if (proxy != null) {
+            proxy.addTarget(target);
+        }
+    }
+
+    public synchronized void targetRemoved(ObjectName target) {
+        if (proxy != null) {
+            proxy.removeTarget(target);
+        }
+    }
+}

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBean.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBean.java?view=diff&rev=106345&p1=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBean.java&r1=106344&p2=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBean.java&r2=106345
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBean.java	(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBean.java	Tue Nov 23 12:37:03 2004
@@ -19,6 +19,7 @@
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -45,6 +46,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.geronimo.gbean.GAttributeInfo;
+import org.apache.geronimo.gbean.GBeanData;
 import org.apache.geronimo.gbean.GBeanInfo;
 import org.apache.geronimo.gbean.GBeanLifecycle;
 import org.apache.geronimo.gbean.GBeanLifecycleController;
@@ -53,7 +55,7 @@
 import org.apache.geronimo.gbean.GOperationSignature;
 import org.apache.geronimo.gbean.GReferenceInfo;
 import org.apache.geronimo.gbean.InvalidConfigurationException;
-import org.apache.geronimo.gbean.GBeanData;
+import org.apache.geronimo.gbean.WaitingException;
 import org.apache.geronimo.kernel.Kernel;
 import org.apache.geronimo.kernel.management.NotificationType;
 
@@ -106,7 +108,7 @@
     /**
      * References lookup table
      */
-    private final GBeanMBeanReference[] references;
+    private final GBeanReference[] references;
 
     /**
      * References supported by this GBeanMBean by (String) name.
@@ -173,6 +175,8 @@
      */
     private final RawInvoker rawInvoker;
 
+    private Kernel kernel;
+
     /**
      * Constructa a GBeanMBean using the supplied GBeanData and class loader
      *
@@ -238,9 +242,14 @@
         Set referencesSet = new HashSet();
         for (Iterator iterator = gbeanInfo.getReferences().iterator(); iterator.hasNext();) {
             GReferenceInfo referenceInfo = (GReferenceInfo) iterator.next();
-            referencesSet.add(new GBeanMBeanReference(this, referenceInfo, (Class) constructorTypes.get(referenceInfo.getName())));
+            Class constructorType = (Class) constructorTypes.get(referenceInfo.getName());
+            if (isCollectionValuedReference(this, referenceInfo, constructorType)) {
+                referencesSet.add(new GBeanCollectionReference(this, referenceInfo, constructorType));
+            } else {
+                referencesSet.add(new GBeanSingleReference(this, referenceInfo, constructorType));
+            }
         }
-        references = (GBeanMBeanReference[]) referencesSet.toArray(new GBeanMBeanReference[gbeanInfo.getReferences().size()]);
+        references = (GBeanReference[]) referencesSet.toArray(new GBeanReference[gbeanInfo.getReferences().size()]);
         for (int i = 0; i < references.length; i++) {
             referenceIndex.put(references[i].getName(), new Integer(i));
         }
@@ -297,6 +306,15 @@
         gbeanLifecycleController = new GBeanMBeanLifecycleController(this);
     }
 
+    private static boolean isCollectionValuedReference(GBeanMBean gbeanMBean, GReferenceInfo referenceInfo, Class constructorType) {
+        if (constructorType != null) {
+            return Collection.class == constructorType;
+        } else {
+            Method setterMethod = AbstractGBeanReference.searchForSetter(gbeanMBean, referenceInfo);
+            return Collection.class == setterMethod.getParameterTypes()[0];
+        }
+    }
+
     /**
      * Search for a single valid constructor in the class.  A valid constructor is determined by the
      * attributes and references declared in the GBeanInfo.  For each, constructor gbean attribute
@@ -523,17 +541,12 @@
         setAttribute("classLoader", classLoader);
         try {
             String kernelName = (String) server.getAttribute(Kernel.KERNEL, "KernelName");
-            Kernel kernel = Kernel.getKernel(kernelName);
+            kernel = Kernel.getKernel(kernelName);
             setAttribute("kernel", kernel);
         } catch (Exception e) {
             setAttribute("kernel", null);
         }
 
-        // bring any reference not used in the constructor online
-        for (int i = 0; i < references.length; i++) {
-            references[i].online();
-        }
-
         return returnValue;
     }
 
@@ -542,39 +555,50 @@
 
         if (registrationDone.booleanValue()) {
             // we're now offically on line
-            offline = false;
-        } else {
-            // we need to bring the reference back off line
             for (int i = 0; i < references.length; i++) {
-                references[i].offline();
+                references[i].online(kernel);
             }
 
+            offline = false;
+        } else {
+            kernel = null;
             target = null;
         }
     }
 
     public void postDeregister() {
-        // take all of the reference offline
+        // just to be sure, stop all the references again
         for (int i = 0; i < references.length; i++) {
             references[i].offline();
         }
 
         offline = true;
+        kernel = null;
         target = null;
 
         super.postDeregister();
     }
 
     protected void doStart() throws Exception {
-        // start all of the proxies
+        // start each of the references... if they need to wait remember the
+        // waiting exception so we can throw it later. this way we the dependecies
+        // are held until we can start
+        WaitingException waitingException = null;
         for (int i = 0; i < references.length; i++) {
-            references[i].start();
+            try {
+                references[i].start();
+            } catch (WaitingException e) {
+                waitingException = e;
+            }
+        }
+        if (waitingException != null) {
+            throw waitingException;
         }
 
         GConstructorInfo constructorInfo = gbeanInfo.getConstructor();
         Class[] parameterTypes = constructor.getParameterTypes();
 
-        // create parameter array
+        // create constructor parameter array
         Object[] parameters = new Object[parameterTypes.length];
         Iterator names = constructorInfo.getAttributeNames().iterator();
         for (int i = 0; i < parameters.length; i++) {
@@ -614,7 +638,7 @@
             attributes[i].inject();
         }
 
-        // inject the proxy into the new instance
+        // inject the proxies into the new instance
         for (int i = 0; i < references.length; i++) {
             references[i].inject();
         }
@@ -641,6 +665,7 @@
         for (int i = 0; i < attributes.length; i++) {
             GBeanMBeanAttribute attribute = attributes[i];
             if (attribute.isPersistent() && attribute.isReadable()) {
+                // copy the current attribute value to the persistent value
                 Object value = attribute.getValue();
                 attribute.setPersistentValue(value);
             }
@@ -748,7 +773,7 @@
 
         // add the references
         for (int i = 0; i < references.length; i++) {
-            GBeanMBeanReference reference = references[i];
+            GBeanReference reference = references[i];
             String name = reference.getName();
             Set patterns = reference.getPatterns();
             gbeanData.setReferencePatterns(name, patterns);
@@ -943,12 +968,12 @@
         getReferenceByName(name).setPatterns(patterns);
     }
 
-    private GBeanMBeanReference getReferenceByName(String name) {
+    private GBeanReference getReferenceByName(String name) {
         Integer index = (Integer) referenceIndex.get(name);
         if (index == null) {
             throw new IllegalArgumentException("Unknown reference " + name);
         }
-        GBeanMBeanReference reference = references[index.intValue()];
+        GBeanReference reference = references[index.intValue()];
         return reference;
     }
 

Deleted: /geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBeanReference.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanMBeanReference.java?view=auto&rev=106344
==============================================================================

Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanReference.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanReference.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanReference.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,46 @@
+/**
+ *
+ * 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.jmx;
+
+import java.util.Set;
+
+import org.apache.geronimo.kernel.Kernel;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface GBeanReference {
+    String getName();
+
+    Class getType();
+
+    Set getPatterns();
+
+    void setPatterns(Set patterns);
+
+    void online(Kernel kernel);
+
+    void offline();
+
+    void start() throws Exception;
+
+    void stop();
+
+    Object getProxy();
+
+    void inject() throws Exception;
+}

Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanSingleProxy.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanSingleProxy.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanSingleProxy.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,70 @@
+/**
+ *
+ * Copyright 2003-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.jmx;
+
+import javax.management.ObjectName;
+
+import org.apache.geronimo.kernel.Kernel;
+
+/**
+ * @version $Rev: 46019 $ $Date: 2004-09-14 02:56:06 -0700 (Tue, 14 Sep 2004) $
+ */
+public class GBeanSingleProxy {
+    /**
+     * The GBean we are proxying.
+     */
+    private ObjectName target;
+
+    /**
+     * Proxy implementation held by the component
+     */
+    private Object proxy;
+
+    /**
+     * The interceptor for the proxy instance
+     */
+    private ProxyMethodInterceptor methodInterceptor;
+
+    public GBeanSingleProxy(Kernel kernel, Class type, ObjectName target) throws Exception {
+        assert kernel != null: "kernel is null";
+        assert type != null: "type is null";
+        assert target != null: "target is null";
+
+        this.target = target;
+        ProxyFactory factory = ProxyFactory.newProxyFactory(type);
+        methodInterceptor = factory.getMethodInterceptor();
+        proxy = factory.create(methodInterceptor);
+
+        methodInterceptor.connect(kernel.getMBeanServer(), target);
+    }
+
+    public synchronized void destroy() {
+        methodInterceptor.disconnect();
+
+        proxy = null;
+        methodInterceptor = null;
+    }
+
+    public synchronized Object getProxy() {
+        return proxy;
+    }
+
+    public ObjectName getTarget() {
+        return target;
+    }
+}

Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanSingleReference.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanSingleReference.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/GBeanSingleReference.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,150 @@
+/**
+ *
+ * Copyright 2003-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.jmx;
+
+import java.util.Set;
+import javax.management.ObjectName;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.geronimo.gbean.GReferenceInfo;
+import org.apache.geronimo.gbean.InvalidConfigurationException;
+import org.apache.geronimo.gbean.WaitingException;
+import org.apache.geronimo.kernel.Kernel;
+import org.apache.geronimo.kernel.management.State;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class GBeanSingleReference extends AbstractGBeanReference {
+    private static final Log log = LogFactory.getLog(GBeanSingleReference.class);
+
+    /**
+     * Is the GBeanMBean waitng for me to start?
+     */
+    private boolean waitingForMe = false;
+
+    /**
+     * Proxy to the to this connection.
+     */
+    private GBeanSingleProxy proxy;
+
+    public GBeanSingleReference(GBeanMBean gmbean, GReferenceInfo referenceInfo, Class constructorType) throws InvalidConfigurationException {
+        super(gmbean, referenceInfo, constructorType);
+    }
+
+    public synchronized void start() throws Exception {
+        // if there are no patterns then there is nothing to start
+        if (getPatterns().isEmpty()) {
+            return;
+        }
+
+        // if we already have a proxy then we have already been started
+        if (proxy != null) {
+            return;
+        }
+
+        //
+        // We must have exactally one running target
+        //
+        Set targets = getTargets();
+        if (targets.size() == 0) {
+            waitingForMe = true;
+            throw new WaitingException("No targets are running for " + getName() + " reference");
+        } else if (targets.size() > 1) {
+            waitingForMe = true;
+            throw new WaitingException("More then one targets are running for " + getName() + " reference");
+        }
+        waitingForMe = false;
+
+        // stop all gbeans that would match our patterns from starting
+        Kernel kernel = getKernel();
+        ObjectName objectName = getGBeanMBean().getObjectNameObject();
+        kernel.getDependencyManager().addStartHolds(objectName, getPatterns());
+
+        // add a dependency on our target and create the proxy
+        ObjectName target = (ObjectName) targets.iterator().next();
+        kernel.getDependencyManager().addDependency(objectName, target);
+        proxy = new GBeanSingleProxy(kernel, getType(), target);
+    }
+
+    public synchronized void stop() {
+        waitingForMe = false;
+        Kernel kernel = getKernel();
+        ObjectName objectName = getGBeanMBean().getObjectNameObject();
+        Set patterns = getPatterns();
+        if (!patterns.isEmpty()) {
+            kernel.getDependencyManager().removeStartHolds(objectName, patterns);
+        }
+
+        if (proxy != null) {
+            kernel.getDependencyManager().removeDependency(objectName, proxy.getTarget());
+            proxy.destroy();
+            proxy = null;
+        }
+    }
+
+    public Object getProxy() {
+        if (proxy == null) {
+            return null;
+        } else {
+            return proxy.getProxy();
+        }
+    }
+
+    public synchronized void targetAdded(ObjectName target) {
+        // if we are running, and we now have two valid targets, which is an illegal state so we need to fail
+        GBeanMBean gbeanMBean = getGBeanMBean();
+        if (gbeanMBean.getStateInstance() == State.RUNNING) {
+            gbeanMBean.fail();
+        } else if (waitingForMe) {
+            Set targets = getTargets();
+            if (targets.size() == 1) {
+                // the gbean was waiting for me and not there is now just one target
+                attemptFullStart();
+            }
+        }
+    }
+
+    public synchronized void targetRemoved(ObjectName target) {
+        GBeanMBean gbeanMBean = getGBeanMBean();
+        if (gbeanMBean.getStateInstance() == State.RUNNING) {
+            // we no longer have a valid target, which is an illegal state so we need to fail
+            gbeanMBean.fail();
+        } else if (waitingForMe) {
+            Set targets = getTargets();
+            if (targets.size() == 1) {
+                // the gbean was waiting for me and not there is now just one target
+                attemptFullStart();
+            }
+        }
+    }
+
+    private synchronized void attemptFullStart() {
+        try {
+            // there could be an issue with really badly written components holding up a stop when the
+            // component never reached the starting phase... then a target registers and we automatically
+            // attempt to restart
+            waitingForMe = false;
+            getGBeanMBean().attemptFullStart();
+        } catch (Exception e) {
+            log.warn("Exception occured while attempting to fully start: objectName=" + getGBeanMBean().getObjectName(), e);
+        }
+    }
+
+}

Deleted: /geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/Proxy.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/Proxy.java?view=auto&rev=106344
==============================================================================

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/ProxyMethodInterceptor.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/ProxyMethodInterceptor.java?view=diff&rev=106345&p1=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/ProxyMethodInterceptor.java&r1=106344&p2=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/ProxyMethodInterceptor.java&r2=106345
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/ProxyMethodInterceptor.java	(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/ProxyMethodInterceptor.java	Tue Nov 23 12:37:03 2004
@@ -27,13 +27,7 @@
 
     void connect(MBeanServerConnection server, ObjectName objectName);
 
-    void connect(MBeanServerConnection server, ObjectName objectName, boolean stopped);
-
     void disconnect();
-
-    void start();
-
-    void stop();
 
     static final class HashCodeInvoke implements GBeanInvoker {
         public Object invoke(ObjectName objectName, Object[] arguments) throws Throwable {

Deleted: /geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/SingleProxy.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/SingleProxy.java?view=auto&rev=106344
==============================================================================

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/VMMethodInterceptor.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/VMMethodInterceptor.java?view=diff&rev=106345&p1=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/VMMethodInterceptor.java&r1=106344&p2=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/VMMethodInterceptor.java&r2=106345
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/VMMethodInterceptor.java	(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/gbean/jmx/VMMethodInterceptor.java	Tue Nov 23 12:37:03 2004
@@ -45,13 +45,9 @@
     }
 
     public void connect(MBeanServerConnection server, ObjectName objectName) {
-        connect(server, objectName, false);
-    }
-
-    public void connect(MBeanServerConnection server, ObjectName objectName, boolean stopped) {
         assert server != null && objectName != null;
         this.objectName = objectName;
-        this.stopped = stopped;
+        stopped = false;
         gbeanInvokers = createGBeanInvokers(server, objectName);
     }
 
@@ -59,17 +55,6 @@
         stopped = true;
         objectName = null;
         gbeanInvokers = null;
-    }
-
-    public void start() {
-        if (gbeanInvokers == null) {
-            throw new DeadProxyException("Proxy is no longer valid");
-        }
-        this.stopped = false;
-    }
-
-    public void stop() {
-        this.stopped = true;
     }
 
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/DependencyManager.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/DependencyManager.java?view=diff&rev=106345&p1=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/DependencyManager.java&r1=106344&p2=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/DependencyManager.java&r2=106345
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/DependencyManager.java	(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/DependencyManager.java	Tue Nov 23 12:37:03 2004
@@ -193,7 +193,7 @@
         if (parents == null) {
             return Collections.EMPTY_SET;
         }
-        return parents;
+        return new HashSet(parents);
     }
 
     /**
@@ -208,7 +208,7 @@
         if (children == null) {
             return Collections.EMPTY_SET;
         }
-        return children;
+        return new HashSet(children);
     }
 
     /**

Modified: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/Kernel.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/Kernel.java?view=diff&rev=106345&p1=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/Kernel.java&r1=106344&p2=geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/Kernel.java&r2=106345
==============================================================================
--- geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/Kernel.java	(original)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/Kernel.java	Tue Nov 23 12:37:03 2004
@@ -28,6 +28,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Iterator;
+import java.util.HashSet;
 import javax.management.Attribute;
 import javax.management.InstanceAlreadyExistsException;
 import javax.management.InstanceNotFoundException;
@@ -44,12 +46,12 @@
 import org.apache.geronimo.gbean.GBeanData;
 import org.apache.geronimo.gbean.GBeanInfo;
 import org.apache.geronimo.gbean.jmx.GBeanMBean;
+import org.apache.geronimo.kernel.config.Configuration;
 import org.apache.geronimo.kernel.config.ConfigurationManager;
 import org.apache.geronimo.kernel.config.ConfigurationManagerImpl;
 import org.apache.geronimo.kernel.config.InvalidConfigException;
 import org.apache.geronimo.kernel.config.NoSuchConfigException;
 import org.apache.geronimo.kernel.config.NoSuchStoreException;
-import org.apache.geronimo.kernel.config.Configuration;
 import org.apache.geronimo.kernel.jmx.JMXUtil;
 
 
@@ -158,6 +160,12 @@
     private GBeanMBean configurationManagerGBean;
 
     /**
+     * Monitors the lifecycle of all gbeans.
+     * @deprecated don't use this yet... it may go away
+     */
+    private LifecycleMonitor lifecycleMonitor;
+
+    /**
      * No-arg constructor allowing this class to be used as a GBean reference.
      */
     public Kernel() {
@@ -249,6 +257,14 @@
         return configurationManager;
     }
 
+    /**
+     * Gets the lifecycle monitor.
+     * @deprecated don't use this yet... it may change or go away
+     */
+    public LifecycleMonitor getLifecycleMonitor() {
+        return lifecycleMonitor;
+    }
+
     public Object getAttribute(ObjectName objectName, String attributeName) throws Exception {
         try {
             return mbServer.getAttribute(objectName, attributeName);
@@ -404,6 +420,15 @@
         return mbServer.queryNames(query, null);
     }
 
+    public Set listGBeans(Set patterns) {
+        Set gbeans = new HashSet();
+        for (Iterator iterator = patterns.iterator(); iterator.hasNext();) {
+            ObjectName pattern = (ObjectName) iterator.next();
+            gbeans.addAll(listGBeans(pattern));
+        }
+        return gbeans;
+    }
+
     public List listConfigurationStores() {
         return getConfigurationManager().listStores();
     }
@@ -479,12 +504,13 @@
         mbServer.registerMBean(this, KERNEL);
         dependencyManager = new DependencyManager(mbServer);
 
+        lifecycleMonitor = new LifecycleMonitor(mbServer);
+
         configurationManagerGBean = new GBeanMBean(ConfigurationManagerImpl.GBEAN_INFO);
         configurationManagerGBean.setReferencePatterns("Stores", Collections.singleton(CONFIGURATION_STORE_PATTERN));
         mbServer.registerMBean(configurationManagerGBean, CONFIGURATION_MANAGER_NAME);
         configurationManagerGBean.start();
         configurationManager = (ConfigurationManager) configurationManagerGBean.getTarget();
-
         running = true;
         log.info("Booted");
     }

Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleAdapter.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleAdapter.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleAdapter.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,42 @@
+/**
+ *
+ * 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.kernel;
+
+import javax.management.ObjectName;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class LifecycleAdapter implements LifecycleListener {
+    public void created(ObjectName objectName) {
+    }
+
+    public void starting(ObjectName objectName) {
+    }
+
+    public void running(ObjectName objectName) {
+    }
+
+    public void stopping(ObjectName objectName) {
+    }
+
+    public void stopped(ObjectName objectName) {
+    }
+
+    public void deleted(ObjectName objectName) {
+    }
+}

Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleListener.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleListener.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleListener.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,32 @@
+/**
+ *
+ * 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.kernel;
+
+import java.util.EventListener;
+import javax.management.ObjectName;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface LifecycleListener extends EventListener {
+    public void created(ObjectName objectName);
+    public void starting(ObjectName objectName);
+    public void running(ObjectName objectName);
+    public void stopping(ObjectName objectName);
+    public void stopped(ObjectName objectName);
+    public void deleted(ObjectName objectName);
+}

Added: geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleMonitor.java
Url: http://svn.apache.org/viewcvs/geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleMonitor.java?view=auto&rev=106345
==============================================================================
--- (empty file)
+++ geronimo/trunk/modules/kernel/src/java/org/apache/geronimo/kernel/LifecycleMonitor.java	Tue Nov 23 12:37:03 2004
@@ -0,0 +1,276 @@
+/**
+ *
+ * Copyright 2003-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.kernel;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.Map;
+import java.util.Collections;
+import java.util.HashMap;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanServer;
+import javax.management.MBeanServerNotification;
+import javax.management.Notification;
+import javax.management.NotificationFilterSupport;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.NotificationBroadcaster;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.geronimo.kernel.jmx.JMXUtil;
+import org.apache.geronimo.kernel.management.NotificationType;
+
+/**
+ * @version $Rev: 71492 $ $Date: 2004-11-14 21:31:50 -0800 (Sun, 14 Nov 2004) $
+ */
+public class LifecycleMonitor implements NotificationListener {
+    private static final Log log = LogFactory.getLog(LifecycleMonitor.class);
+
+    private final MBeanServer server;
+
+    // todo we should only hold weak references to the listeners
+    private final Map boundListeners = new HashMap();
+    private final Map listenerPatterns = new HashMap();
+
+    /**
+     * @deprecated don't use this yet... it may change or go away
+     */
+    public LifecycleMonitor(MBeanServer server) {
+        this.server = server;
+
+        // listen for all mbean registration events
+        try {
+            NotificationFilterSupport mbeanServerFilter = new NotificationFilterSupport();
+            mbeanServerFilter.enableType(MBeanServerNotification.REGISTRATION_NOTIFICATION);
+            mbeanServerFilter.enableType(MBeanServerNotification.UNREGISTRATION_NOTIFICATION);
+            server.addNotificationListener(JMXUtil.DELEGATE_NAME, this, mbeanServerFilter, null);
+        } catch (Exception e) {
+            // this will never happen... all of the above is well formed
+            throw new AssertionError(e);
+        }
+
+        // register for state change notifications with all mbeans that match the target patterns
+        Set names = server.queryNames(null, null);
+        for (Iterator objectNameIterator = names.iterator(); objectNameIterator.hasNext();) {
+            addSource((ObjectName) objectNameIterator.next());
+        }
+
+        for (Iterator iterator = boundListeners.keySet().iterator(); iterator.hasNext();) {
+            ObjectName source = (ObjectName) iterator.next();
+            try {
+                if (server.isInstanceOf(source, NotificationBroadcaster.class.getName())) {
+                    server.addNotificationListener(source, this, NotificationType.STATE_CHANGE_FILTER, null);
+                }
+            } catch (InstanceNotFoundException e) {
+                // the instance died before we could get going... not a big deal
+                break;
+            } catch (Throwable e) {
+                log.warn("Could not add state change listener to: " + source + " on behalf of objectName", e);
+            }
+        }
+    }
+
+    public synchronized void destroy() {
+        try {
+            server.removeNotificationListener(JMXUtil.DELEGATE_NAME, this);
+        } catch (Exception ignore) {
+            // don't care... we tried
+        }
+
+        // unregister for all notifications
+        for (Iterator iterator = boundListeners.keySet().iterator(); iterator.hasNext();) {
+            ObjectName target = (ObjectName) iterator.next();
+            try {
+                server.removeNotificationListener(target, this, NotificationType.STATE_CHANGE_FILTER, null);
+            } catch (Exception ignore) {
+                // don't care... we tried
+            }
+        }
+
+        boundListeners.clear();
+        listenerPatterns.clear();
+    }
+
+    private synchronized void addSource(ObjectName source) {
+        if (boundListeners.containsKey(source)) {
+            // alreayd registered
+            return;
+        }
+
+        // find all listeners interested in events from this source
+        HashSet listeners = new HashSet();
+        for (Iterator listenerIterator = listenerPatterns.entrySet().iterator(); listenerIterator.hasNext();) {
+            Map.Entry entry = (Map.Entry) listenerIterator.next();
+            Set patterns = (Set) entry.getValue();
+            for (Iterator patternIterator = patterns.iterator(); patternIterator.hasNext();) {
+                ObjectName pattern = (ObjectName) patternIterator.next();
+                if (pattern.apply(source)) {
+                    LifecycleListener listener = (LifecycleListener) entry.getKey();
+                    listeners.add(listener);
+                }
+            }
+        }
+
+        boundListeners.put(source, listeners);
+    }
+
+    private synchronized void removeSource(ObjectName source) {
+        boundListeners.remove(source);
+    }
+
+    public synchronized void addLifecycleListener(LifecycleListener listener, Set patterns) {
+        for (Iterator patternIterator = patterns.iterator(); patternIterator.hasNext();) {
+            ObjectName pattern = (ObjectName) patternIterator.next();
+            for (Iterator iterator = boundListeners.entrySet().iterator(); iterator.hasNext();) {
+                Map.Entry entry = (Map.Entry) iterator.next();
+                ObjectName source = (ObjectName) entry.getKey();
+                if (pattern.apply(source)) {
+                    Set listeners = (Set) entry.getValue();
+                    listeners.add(listener);
+                }
+            }
+        }
+        listenerPatterns.put(listener, patterns);
+    }
+
+    public synchronized void removeLifecycleListener(LifecycleListener listener) {
+        for (Iterator iterator = boundListeners.values().iterator(); iterator.hasNext();) {
+            Set set = (Set) iterator.next();
+            set.remove(listener);
+        }
+        listenerPatterns.remove(listener);
+    }
+
+    private synchronized Set getTargets(ObjectName source) {
+        Set targets = (Set) boundListeners.get(source);
+        if (targets == null) {
+            // no one is interested in this event
+            return Collections.EMPTY_SET;
+        } else {
+            return new HashSet(targets);
+        }
+    }
+
+    private void fireCreatedEvent(ObjectName objectName) {
+        Set targets = getTargets(objectName);
+        for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+            LifecycleListener listener = (LifecycleListener) iterator.next();
+            try {
+                listener.created(objectName);
+            } catch (Throwable e) {
+                log.warn("Exception occured while notifying listener", e);
+            }
+        }
+    }
+
+    private void fireStartingEvent(ObjectName source) {
+        Set targets = getTargets(source);
+        for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+            LifecycleListener listener = (LifecycleListener) iterator.next();
+            try {
+                listener.starting(source);
+            } catch (Throwable e) {
+                log.warn("Exception occured while notifying listener", e);
+            }
+        }
+    }
+
+    private void fireRunningEvent(ObjectName source) {
+        Set targets = getTargets(source);
+        for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+            LifecycleListener listener = (LifecycleListener) iterator.next();
+            try {
+                listener.running(source);
+            } catch (Throwable e) {
+                log.warn("Exception occured while notifying listener", e);
+            }
+        }
+    }
+
+    private void fireStoppingEvent(ObjectName source) {
+        Set targets = getTargets(source);
+        for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+            LifecycleListener listener = (LifecycleListener) iterator.next();
+            try {
+                listener.stopping(source);
+            } catch (Throwable e) {
+                log.warn("Exception occured while notifying listener", e);
+            }
+        }
+    }
+
+    private void fireStoppedEvent(ObjectName source) {
+        Set targets = getTargets(source);
+        for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+            LifecycleListener listener = (LifecycleListener) iterator.next();
+            try {
+                listener.stopped(source);
+            } catch (Throwable e) {
+                log.warn("Exception occured while notifying listener", e);
+            }
+        }
+    }
+
+    private void fireDeleteEvent(ObjectName source) {
+        Set targets = getTargets(source);
+        for (Iterator iterator = targets.iterator(); iterator.hasNext();) {
+            LifecycleListener listener = (LifecycleListener) iterator.next();
+            try {
+                listener.deleted(source);
+            } catch (Throwable e) {
+                log.warn("Exception occured while notifying listener", e);
+            }
+        }
+    }
+
+    public void handleNotification(Notification notification, Object o) {
+        String type = notification.getType();
+
+        if (MBeanServerNotification.REGISTRATION_NOTIFICATION.equals(type)) {
+            ObjectName source = ((MBeanServerNotification) notification).getMBeanName();
+            addSource(source);
+
+            // register for state change notifications
+            try {
+                server.addNotificationListener(source, this, NotificationType.STATE_CHANGE_FILTER, null);
+            } catch (InstanceNotFoundException e) {
+                // the instance died before we could get going... not a big deal
+                return;
+            }
+        } else if (MBeanServerNotification.UNREGISTRATION_NOTIFICATION.equals(type)) {
+            removeSource(((MBeanServerNotification) notification).getMBeanName());
+        } else {
+            final ObjectName source = (ObjectName) notification.getSource();
+            if (NotificationType.OBJECT_CREATED.equals(type)) {
+                fireCreatedEvent(source);
+            } else if (NotificationType.STATE_STARTING.equals(type)) {
+                fireStartingEvent(source);
+            } else if (NotificationType.STATE_RUNNING.equals(type)) {
+                fireRunningEvent(source);
+            } else if (NotificationType.STATE_STOPPING.equals(type)) {
+                fireStoppingEvent(source);
+            } else if (NotificationType.STATE_STOPPED.equals(type)) {
+                fireStoppedEvent(source);
+            } else if (NotificationType.OBJECT_DELETED.equals(type)) {
+                fireDeleteEvent(source);
+            }
+        }
+    }
+}