001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *  http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    
020    package org.apache.geronimo.openjpa;
021    
022    import java.net.URI;
023    import java.net.URISyntaxException;
024    import java.util.Collections;
025    import java.util.HashMap;
026    
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    import org.apache.geronimo.gbean.AbstractName;
030    import org.apache.geronimo.gbean.AbstractNameQuery;
031    import org.apache.geronimo.gbean.GBeanLifecycle;
032    import org.apache.geronimo.gbean.GBeanInfo;
033    import org.apache.geronimo.gbean.GBeanInfoBuilder;
034    import org.apache.geronimo.kernel.Kernel;
035    import org.apache.geronimo.kernel.GBeanNotFoundException;
036    import org.apache.geronimo.kernel.config.Configuration;
037    import org.apache.geronimo.kernel.lifecycle.LifecycleListener;
038    import org.apache.geronimo.kernel.repository.Artifact;
039    
040    import org.apache.openjpa.enhance.PCRegistry;
041    
042    /**
043     * Monitor configuration lifecycle events. Whenever a configuration is stopped, inform OpenJPA that the ClassLoader is no longer needed.
044     * 
045     * @version $Rev: 562311 $ $Date: 2007-08-02 22:25:05 -0400 (Thu, 02 Aug 2007) $
046     */
047    public class ConfigurationMonitorGBean implements GBeanLifecycle {
048        private static final Log log = LogFactory.getLog(ConfigurationMonitorGBean.class);
049        
050        private final Kernel kernel;
051        private final LifecycleListener listener;
052        private HashMap<AbstractName,ClassLoader> classLoaderMap = new HashMap<AbstractName,ClassLoader>();
053    
054        public ConfigurationMonitorGBean(Kernel kernel) {
055            this.kernel = kernel;
056            this.listener = createLifecycleListener();
057        }
058    
059        /**
060         * Create a LifecycleListenr that will be informed of lifecycle events.
061         * We only care about running (the configuration ClassLoader cannot be retrieved when the Configuration is stopping)
062         * and stopped.
063         */
064        private LifecycleListener createLifecycleListener() {
065            return new LifecycleListener() {
066                public void loaded(AbstractName abstractName) {
067                }
068                public void starting(AbstractName abstractName) {
069                }
070                public void running(AbstractName abstractName) {
071                    configurationRunning(abstractName);
072                }
073                public void stopping(AbstractName abstractName) {
074                }
075                public void stopped(AbstractName abstractName) {
076                    configurationStopped(abstractName);
077                }
078                public void failed(AbstractName abstractName) {
079                }
080                public void unloaded(AbstractName abstractName) {
081                }
082    
083            };
084        }
085    
086        /**
087         * Cache the ClassLoader for a newly started Configuration.  
088         */
089        private void configurationRunning(AbstractName name) {
090            try {
091                Configuration config = (Configuration)kernel.getGBean(name);
092                classLoaderMap.put(name, config.getConfigurationClassLoader());
093            } catch (GBeanNotFoundException gnfe) {
094                log.warn("Could not retrieve GBean for artifact: " + name.toString(), gnfe);
095            }
096        }
097    
098        /**
099         * Notify OpenJPA that the ClassLoader will no longer be used. This allows OpenJPA to free up 
100         * HARD references that would otherwise prevent Geronimo ClassLoaders from being GCed.
101         */
102        private void configurationStopped(AbstractName name) {
103            ClassLoader classLoader = classLoaderMap.remove(name);
104            if (classLoader == null) {
105                log.debug("Could not locate ClassLoader for artifact: " + name.toString());
106            }
107            PCRegistry.deRegister(classLoader);
108        }
109    
110        /**
111         * This GBean is being started. Register our listener with the Lifecycle monitor.
112         */
113        public void doStart() {
114            AbstractNameQuery configurationQuery = new AbstractNameQuery(Configuration.class.getName());
115            kernel.getLifecycleMonitor().addLifecycleListener(listener, configurationQuery);
116         }
117    
118        /**
119         * This GBean is being stopped. Remove the LifecycleListener.
120         */
121        public void doStop() {
122            kernel.getLifecycleMonitor().removeLifecycleListener(listener);
123        }
124    
125        public void doFail() {
126            doStop();
127        }
128    
129        public static final GBeanInfo GBEAN_INFO;
130    
131        static {
132            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(ConfigurationMonitorGBean.class);
133            infoBuilder.addAttribute("kernel", Kernel.class, false);
134            infoBuilder.setConstructor(new String[] {
135                    "kernel",
136            });
137            GBEAN_INFO = infoBuilder.getBeanInfo();
138        }
139    
140        public static GBeanInfo getGBeanInfo() {
141            return GBEAN_INFO;
142        }
143    }