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.kernel.basic;
018    
019    import java.util.Collections;
020    import java.util.HashMap;
021    import java.util.HashSet;
022    import java.util.IdentityHashMap;
023    import java.util.Iterator;
024    import java.util.Map;
025    import java.util.Set;
026    import javax.management.ObjectName;
027    import javax.management.MalformedObjectNameException;
028    
029    import org.apache.geronimo.gbean.AbstractName;
030    import org.apache.geronimo.gbean.AbstractNameQuery;
031    import org.apache.geronimo.gbean.runtime.GBeanInstance;
032    import org.apache.geronimo.gbean.runtime.InstanceRegistry;
033    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
034    import org.apache.geronimo.kernel.GBeanNotFoundException;
035    import org.apache.geronimo.kernel.Kernel;
036    
037    /**
038     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
039     */
040    public class BasicRegistry implements InstanceRegistry {
041        private final Map objectNameRegistry = new HashMap();
042        private final Map infoRegistry = new HashMap();
043        private final IdentityHashMap instanceRegistry = new IdentityHashMap();
044        private String kernelName = "";
045    
046        /**
047         * Start the objectNameRegistry and associate it with a kernel.
048         *
049         * @param kernel the kernel to associate with
050         */
051        public void start(Kernel kernel) {
052            kernelName = kernel.getKernelName();
053        }
054    
055        /**
056         * Shut down the objectNameRegistry and unregister any GBeans
057         */
058        public void stop() {
059            synchronized (this) {
060                objectNameRegistry.clear();
061            }
062            kernelName = "";
063        }
064    
065        /**
066         * See if there is a GBean registered with a specific name.
067         *
068         * @param name the name of the GBean to check for
069         * @return true if there is a GBean registered with that name
070         */
071        public synchronized boolean isRegistered(ObjectName name) {
072            return objectNameRegistry.containsKey(normalizeObjectName(name));
073        }
074    
075        public synchronized boolean isRegistered(AbstractName refInfo) {
076            return infoRegistry.containsKey(refInfo);
077        }
078    
079        /**
080         * Register a GBean instance.
081         *
082         * @param gbeanInstance the GBean to register
083         * @throws GBeanAlreadyExistsException if there is already a GBean registered with the instance's name
084         */
085        public synchronized void register(GBeanInstance gbeanInstance) throws GBeanAlreadyExistsException {
086            ObjectName name = normalizeObjectName(gbeanInstance.getObjectNameObject());
087            if (objectNameRegistry.containsKey(name)) {
088                throw new GBeanAlreadyExistsException("GBean already registered: " + name);
089            }
090            objectNameRegistry.put(name, gbeanInstance);
091            infoRegistry.put(gbeanInstance.getAbstractName(), gbeanInstance);
092            gbeanInstance.setInstanceRegistry(this);
093        }
094    
095        public synchronized void unregister(AbstractName abstractName) throws GBeanNotFoundException {
096            GBeanInstance gbeanInstance = (GBeanInstance) infoRegistry.remove(abstractName);
097            if (gbeanInstance == null) {
098                throw new GBeanNotFoundException(abstractName);
099            }
100            objectNameRegistry.remove(gbeanInstance.getObjectNameObject());
101        }
102    
103        public synchronized void instanceCreated(Object instance, GBeanInstance gbeanInstance) {
104            instanceRegistry.put(instance, gbeanInstance);
105        }
106    
107        public synchronized void instanceDestroyed(Object instance) {
108            instanceRegistry.remove(instance);
109        }
110    
111        public synchronized GBeanInstance getGBeanInstanceByInstance(Object instance) {
112            return (GBeanInstance) instanceRegistry.get(instance);
113        }
114    
115        /**
116         * Return the GBeanInstance registered with the supplied name.
117         *
118         * @param name the name of the instance to return
119         * @return the GBeanInstance
120         * @throws GBeanNotFoundException if there is no GBean registered with the supplied name
121         */
122        public synchronized GBeanInstance getGBeanInstance(ObjectName name) throws GBeanNotFoundException {
123            GBeanInstance instance = (GBeanInstance) objectNameRegistry.get(normalizeObjectName(name));
124            if (instance == null) {
125                throw new GBeanNotFoundException(name);
126            }
127            return instance;
128        }
129    
130        public synchronized GBeanInstance getGBeanInstance(AbstractName abstractName) throws GBeanNotFoundException {
131            GBeanInstance instance = (GBeanInstance) infoRegistry.get(abstractName);
132            if (instance == null) {
133                throw new GBeanNotFoundException(abstractName);
134            }
135            return instance;
136        }
137    
138    
139        public synchronized GBeanInstance getGBeanInstance(String shortName, Class type) throws GBeanNotFoundException {
140            if (shortName == null && type == null) throw new IllegalArgumentException("shortName and type are both null");
141    
142            AbstractNameQuery nameQuery;
143            if (type == null) {
144                nameQuery = new AbstractNameQuery(null, Collections.singletonMap("name", shortName));
145            } else if (shortName == null) {
146                nameQuery = new AbstractNameQuery(null, Collections.EMPTY_MAP, type.getName());
147            } else {
148                nameQuery = new AbstractNameQuery(null, Collections.singletonMap("name", shortName), type.getName());
149            }
150            Set instances = listGBeans(nameQuery);
151    
152            if (instances.size() == 0) {
153                throw new GBeanNotFoundException("No GBeans found", Collections.singleton(nameQuery), null);
154            }
155    
156            if (instances.size() > 1) {
157                if (type == null) {
158                    throw new GBeanNotFoundException("More then one GBean was found with shortName '" + shortName + "'", Collections.singleton(nameQuery), mapToNames(instances));
159                }
160                if (shortName == null) {
161                    throw new GBeanNotFoundException("More then one GBean was found with type '" + type.getName() + "'", Collections.singleton(nameQuery), mapToNames(instances));
162                }
163                throw new GBeanNotFoundException("More then one GBean was found with shortName '" + shortName + "' and type '" + type.getName() + "'", Collections.singleton(nameQuery), mapToNames(instances));
164            }
165    
166            return (GBeanInstance) instances.iterator().next();
167        }
168    
169        private Set<AbstractName> mapToNames(Set<GBeanInstance> instances) {
170            Set<AbstractName> names = new HashSet<AbstractName>(instances.size());
171            for (GBeanInstance instance: instances) {
172                names.add(instance.getAbstractName());
173            }
174            return names;
175        }
176    
177    
178        /**
179         * Search the objectNameRegistry for GBeans matching a name pattern.
180         *
181         * @param pattern the object name pattern to search for
182         * @return an unordered Set<GBeanInstance> of GBeans that matched the pattern
183         */
184        public Set listGBeans(ObjectName pattern) {
185            pattern = normalizeObjectName(pattern);
186    
187            // fairly dumb implementation that iterates the list of all registered GBeans
188            Map clone;
189            synchronized (this) {
190                clone = new HashMap(objectNameRegistry);
191            }
192            Set result = new HashSet(clone.size());
193            for (Iterator i = clone.entrySet().iterator(); i.hasNext();) {
194                Map.Entry entry = (Map.Entry) i.next();
195                ObjectName name = (ObjectName) entry.getKey();
196                if (pattern == null || pattern.apply(name)) {
197                    result.add(entry.getValue());
198                }
199            }
200            return result;
201        }
202    
203        public Set listGBeans(AbstractNameQuery query) {
204            Map clone;
205            synchronized (this) {
206                clone = new HashMap(infoRegistry);
207            }
208            Set result = new HashSet(clone.size());
209            for (Iterator i = clone.entrySet().iterator(); i.hasNext();) {
210                Map.Entry entry = (Map.Entry) i.next();
211                AbstractName abstractName = (AbstractName) entry.getKey();
212                GBeanInstance gbeanData = (GBeanInstance) entry.getValue();
213                if (query == null || query.matches(abstractName, gbeanData.getGBeanInfo().getInterfaces())) {
214                    result.add(gbeanData);
215                }
216            }
217            return result;
218        }
219    
220        private ObjectName normalizeObjectName(ObjectName objectName) {
221            if (objectName != null && objectName.getDomain().length() == 0) {
222                try {
223                    return new ObjectName(kernelName, objectName.getKeyPropertyList());
224                } catch (MalformedObjectNameException e) {
225                    throw new AssertionError(e);
226                }
227            }
228            return objectName;
229        }
230    }