001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.loading;
023:
024: import java.lang.reflect.Constructor;
025: import java.io.Serializable;
026: import java.util.HashMap;
027: import javax.management.InstanceNotFoundException;
028: import javax.management.JMException;
029: import javax.management.MalformedObjectNameException;
030: import javax.management.MBeanServer;
031: import javax.management.ObjectInstance;
032: import javax.management.ObjectName;
033:
034: import org.jboss.logging.Logger;
035: import org.jboss.mx.server.ServerConstants;
036:
037: import org.w3c.dom.Element;
038: import org.w3c.dom.NodeList;
039: import org.w3c.dom.Node;
040:
041: /** A factory for LoaderRepository instances. This is used to obtain repository
042: * instances for scoped class loading.
043: *
044: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
045: * @author Scott.Stark@jboss.org
046: * @version $Revision: 57200 $
047: */
048: public class LoaderRepositoryFactory {
049: /** The JMX name of the parent LoaderRepository */
050: public static ObjectName DEFAULT_LOADER_REPOSITORY;
051: private static Logger log = Logger
052: .getLogger(LoaderRepositoryFactory.class);
053: /** A HashMap<ObjectName, Integer> for the active references to LoaderRepositorys */
054: private static HashMap referenceCountMap = new HashMap();
055:
056: static {
057: try {
058: // Initialize the default LoaderRepository name
059: DEFAULT_LOADER_REPOSITORY = new ObjectName(
060: ServerConstants.DEFAULT_LOADER_NAME);
061: } catch (Exception e) {
062: log.error("Failed to init DEFAULT_LOADER_REPOSITORY name",
063: e);
064: }
065: }
066:
067: /** A class that represents the configuration of the a LoaderRepository.
068: * This defines the JMX ObjectName, the LoaderRepository implementation
069: * class, the repository config parser and a string representation of
070: * the repository config.
071: */
072: public static class LoaderRepositoryConfig implements Serializable {
073: static final long serialVersionUID = 4226952985429700362L;
074:
075: /** The ObjectName of the loader repository for this deployment */
076: public ObjectName repositoryName = DEFAULT_LOADER_REPOSITORY;
077: public String repositoryClassName;
078: public String configParserClassName;
079: public String repositoryConfig;
080:
081: public String toString() {
082: StringBuffer tmp = new StringBuffer(
083: "LoaderRepositoryConfig(");
084: tmp.append("repositoryName: ");
085: tmp.append(repositoryName);
086: tmp.append(", repositoryClassName: ");
087: tmp.append(repositoryClassName);
088: tmp.append(", configParserClassName: ");
089: tmp.append(configParserClassName);
090: tmp.append(", repositoryConfig: ");
091: tmp.append(repositoryConfig);
092: tmp.append(")");
093: return tmp.toString();
094: }
095: }
096:
097: /** The interface representing a LoaderRepository configuration parser. A
098: * LoaderRepositoryConfigParser knows how to take a string representation of
099: * a config and map that onto a LoaderRepository implementation.
100: */
101: static public interface LoaderRepositoryConfigParser {
102: public void configure(LoaderRepository repository, String config)
103: throws Exception;
104: }
105:
106: /** Given a loader-repository element fragment like:
107: <loader-repository loaderRepositoryClass='...'>
108: jboss.test.cts:loader=cts-cmp2v2.ear
109: <loader-repository-config configParserClass='...'>
110: ...
111: </loader-repository-config>
112: </loader-repository>
113: create a LoaderRepositoryConfig representation.
114: @param config the xml loader-repository element
115: @return a LoaderRepositoryConfig representation of the config
116: */
117: public static LoaderRepositoryConfig parseRepositoryConfig(
118: Element config) throws MalformedObjectNameException {
119: LoaderRepositoryConfig repositoryConfig = new LoaderRepositoryConfig();
120: repositoryConfig.repositoryClassName = config
121: .getAttribute("loaderRepositoryClass");
122: if (repositoryConfig.repositoryClassName.length() == 0)
123: repositoryConfig.repositoryClassName = ServerConstants.DEFAULT_SCOPED_REPOSITORY_CLASS;
124:
125: // Get the object name of the repository
126: NodeList children = config.getChildNodes();
127: int count = children.getLength();
128: if (count > 0) {
129: for (int n = 0; n < count; n++) {
130: Node node = children.item(n);
131: int type = node.getNodeType();
132: // Get the ObjectName string
133: if (type == Node.TEXT_NODE
134: || type == Node.CDATA_SECTION_NODE) {
135: String objectName = node.getNodeValue().trim();
136: repositoryConfig.repositoryName = new ObjectName(
137: objectName);
138: break;
139: }
140: }
141:
142: // Next load any repository config
143: children = config
144: .getElementsByTagName("loader-repository-config");
145: count = children.getLength();
146: if (count > 0) {
147: Element loaderRepositoryConfig = (Element) children
148: .item(0);
149: children = loaderRepositoryConfig.getChildNodes();
150: count = children.getLength();
151: repositoryConfig.configParserClassName = loaderRepositoryConfig
152: .getAttribute("configParserClass");
153: if (repositoryConfig.configParserClassName.length() == 0)
154: repositoryConfig.configParserClassName = ServerConstants.DEFAULT_SCOPED_REPOSITORY_PARSER_CLASS;
155: StringBuffer configData = new StringBuffer();
156: for (int n = 0; n < count; n++) {
157: Node node = children.item(n);
158: int type = node.getNodeType();
159: if (type == Node.TEXT_NODE
160: || type == Node.CDATA_SECTION_NODE) {
161: configData.append(node.getNodeValue());
162: }
163: }
164: repositoryConfig.repositoryConfig = configData
165: .toString().trim();
166: }
167: }
168: return repositoryConfig;
169: }
170:
171: /** Create a LoaderRepository instance of type repositoryClassName and
172: * register it under repositoryName if there is not already an instance
173: * registered.
174: *
175: * @param server the MBeanServer to register with
176: * @param repositoryClassName the class which implements LoaderRepository
177: * @param repositoryName the JMX name to register under
178: * @throws JMException thrown on any failure to create or register the repository
179: */
180: public static synchronized void createLoaderRepository(
181: MBeanServer server, String repositoryClassName,
182: ObjectName repositoryName) throws JMException {
183: LoaderRepositoryConfig config = new LoaderRepositoryConfig();
184: config.repositoryClassName = repositoryClassName;
185: config.repositoryName = repositoryName;
186: createLoaderRepository(server, config);
187: }
188:
189: /** Create and configure a LoaderRepository instance using the given config
190: * if there is not already an instance registered.
191: *
192: * @param server the MBeanServer to register with
193: * @param config the configuration information which will be used to create
194: * register and configure the LoaderRepository instance.
195: * @throws JMException thrown on any failure to create or register the repository
196: */
197: public static synchronized void createLoaderRepository(
198: MBeanServer server, LoaderRepositoryConfig config)
199: throws JMException {
200: if (config == null)
201: config = new LoaderRepositoryConfig();
202: String repositoryClassName = config.repositoryClassName;
203: ObjectName repositoryName = config.repositoryName;
204:
205: try {
206: ObjectInstance oi = server
207: .getObjectInstance(repositoryName);
208: if ((repositoryClassName != null)
209: && !oi.getClassName().equals(repositoryClassName)) {
210: throw new JMException(
211: "Inconsistent LoaderRepository class specification in repository: "
212: + repositoryName);
213: } // end of if ()
214: } catch (InstanceNotFoundException e) {
215: //we are the first, make the repository.
216: if (repositoryClassName == null)
217: repositoryClassName = ServerConstants.DEFAULT_SCOPED_REPOSITORY_CLASS;
218:
219: ClassLoader loader = Thread.currentThread()
220: .getContextClassLoader();
221: LoaderRepository repository = null;
222: try {
223: // Create the repository loader
224: Class repositoryClass = loader
225: .loadClass(repositoryClassName);
226: Class[] ctorSig = { MBeanServer.class, ObjectName.class };
227: Constructor ctor = repositoryClass
228: .getConstructor(ctorSig);
229: Object[] args = { server, DEFAULT_LOADER_REPOSITORY };
230: repository = (LoaderRepository) ctor.newInstance(args);
231: server.registerMBean(repository, repositoryName);
232: } catch (Exception e2) {
233: log.debug("Failed to create loader repository: ", e2);
234: throw new JMException(
235: "Failed to create loader repository:" + e2);
236: }
237:
238: try {
239: // Configure the repository
240: if (config.configParserClassName != null
241: && config.repositoryConfig != null) {
242: Class parserClass = loader
243: .loadClass(config.configParserClassName);
244: LoaderRepositoryConfigParser parser = (LoaderRepositoryConfigParser) parserClass
245: .newInstance();
246: parser.configure(repository,
247: config.repositoryConfig);
248: }
249: } catch (Exception e2) {
250: log
251: .debug(
252: "Failed to configure loader repository: ",
253: e2);
254: throw new JMException(
255: "Failed to configure loader repository: " + e2);
256: }
257: } // end of try-catch
258:
259: Integer activeCount = (Integer) referenceCountMap
260: .get(repositoryName);
261: if (activeCount == null)
262: activeCount = new Integer(1);
263: else
264: activeCount = new Integer(activeCount.intValue() + 1);
265: referenceCountMap.put(repositoryName, activeCount);
266: }
267:
268: public static synchronized void destroyLoaderRepository(
269: MBeanServer server, ObjectName repositoryName) {
270: if (repositoryName.equals(DEFAULT_LOADER_REPOSITORY) == false) {
271: try {
272: Integer activeCount = (Integer) referenceCountMap
273: .get(repositoryName);
274: if (activeCount != null) {
275: if (activeCount.intValue() == 1) {
276: server.unregisterMBean(repositoryName);
277: referenceCountMap.remove(repositoryName);
278: log.debug("Unregistered repository: "
279: + repositoryName);
280: } else {
281: activeCount = new Integer(activeCount
282: .intValue() - 1);
283: referenceCountMap.put(repositoryName,
284: activeCount);
285: }
286: }
287: } catch (Exception e) {
288: log.warn("Failed to unregister ear loader repository",
289: e);
290: }
291: }
292: }
293:
294: private LoaderRepositoryFactory() {
295: }
296: }// LoaderRepositoryFactory
|