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.resource.connectionmanager;
023:
024: import java.beans.PropertyEditor;
025: import java.beans.PropertyEditorManager;
026: import java.lang.reflect.InvocationTargetException;
027: import java.lang.reflect.Method;
028: import java.util.Collection;
029: import java.util.Iterator;
030: import javax.management.Notification;
031: import javax.management.ObjectName;
032: import javax.resource.ResourceException;
033: import javax.resource.spi.ConnectionManager;
034: import javax.resource.spi.ConnectionRequestInfo;
035: import javax.resource.spi.ManagedConnection;
036: import javax.resource.spi.ManagedConnectionFactory;
037: import javax.resource.spi.ResourceAdapter;
038: import javax.resource.spi.ResourceAdapterAssociation;
039:
040: import org.jboss.deployment.DeploymentException;
041: import org.jboss.logging.Logger;
042: import org.jboss.metadata.MetaData;
043: import org.jboss.resource.metadata.ConfigPropertyMetaData;
044: import org.jboss.resource.metadata.ConnectionDefinitionMetaData;
045: import org.jboss.resource.metadata.ConnectorMetaData;
046: import org.jboss.system.ServiceMBeanSupport;
047: import org.jboss.util.Classes;
048: import org.jboss.util.NestedRuntimeException;
049: import org.w3c.dom.Element;
050: import org.w3c.dom.Node;
051: import org.w3c.dom.NodeList;
052:
053: /**
054: * The RARDeployment mbean manages instantiation and configuration of a
055: * ManagedConnectionFactory instance. It is intended to be configured
056: * primarily by xslt transformation of the ra.xml from a jca adapter.
057: * Until that is implemented, it uses the old RARDeployment and RARDeployer
058: * mechanism to obtain information from the ra.xml. Properties for the
059: * ManagedConectionFactory should be supplied with their values in the
060: * ManagedConnectionFactoryProperties element.
061: *
062: * @author <a href="toby.allsopp@peace.com">Toby Allsopp</a>
063: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
064: * @version $Revision: 57189 $
065: */
066: public class RARDeployment extends ServiceMBeanSupport implements
067: RARDeploymentMBean, ManagedConnectionFactory {
068: static final long serialVersionUID = -294341806721616790L;
069:
070: public final static String MCF_ATTRIBUTE_CHANGED_NOTIFICATION = "jboss.mcfattributechangednotification";
071:
072: private Logger log = Logger.getLogger(getClass());
073:
074: //Hack to use previous ra.xml parsing code until xslt deployment is written.
075: private ObjectName oldRarDeployment;
076:
077: private String rarName;
078:
079: private String connectionDefinition;
080:
081: private String vendorName;
082:
083: private String specVersion;
084:
085: private String eisType;
086:
087: private String version;
088:
089: private String managedConnectionFactoryClass;
090:
091: private String connectionFactoryInterface;
092:
093: private String connectionFactoryImplClass;
094:
095: private String connectionInterface;
096:
097: private String connectionImplClass;
098:
099: private String transactionSupport;
100:
101: private Element managedConnectionFactoryProperties;
102:
103: private String authenticationMechanismType;
104:
105: private String credentialInterface;
106:
107: private boolean reauthenticationSupport;
108:
109: private Class mcfClass;
110:
111: private ManagedConnectionFactory mcf;
112:
113: /**
114: * Default managed constructor for RARDeployment mbeans.
115: */
116: public RARDeployment() {
117: }
118:
119: public ObjectName getOldRarDeployment() {
120: return oldRarDeployment;
121: }
122:
123: public void setOldRarDeployment(final ObjectName oldRarDeployment) {
124: this .oldRarDeployment = oldRarDeployment;
125: }
126:
127: public String getRARName() {
128: return rarName;
129: }
130:
131: public void setRARName(String rarName) {
132: this .rarName = rarName;
133: }
134:
135: public String getConnectionDefinition() {
136: return connectionDefinition;
137: }
138:
139: public void setConnectionDefinition(String connectionDefinition) {
140: this .connectionDefinition = connectionDefinition;
141: }
142:
143: public String getVendorName() {
144: return vendorName;
145: }
146:
147: public void setVendorName(String vendorName) {
148: this .vendorName = vendorName;
149: }
150:
151: public String getSpecVersion() {
152: return specVersion;
153: }
154:
155: public void setSpecVersion(String specVersion) {
156: this .specVersion = specVersion;
157: }
158:
159: public String getEisType() {
160: return eisType;
161: }
162:
163: public void setEisType(String eisType) {
164: this .eisType = eisType;
165: }
166:
167: public String getVersion() {
168: return version;
169: }
170:
171: public void setVersion(String version) {
172: this .version = version;
173: }
174:
175: public String getManagedConnectionFactoryClass() {
176: return managedConnectionFactoryClass;
177: }
178:
179: public void setManagedConnectionFactoryClass(
180: final String managedConnectionFactoryClass) {
181: this .managedConnectionFactoryClass = managedConnectionFactoryClass;
182: }
183:
184: public String getConnectionFactoryInterface() {
185: return connectionFactoryInterface;
186: }
187:
188: public void setConnectionFactoryInterface(
189: String connectionFactoryInterface) {
190: this .connectionFactoryInterface = connectionFactoryInterface;
191: }
192:
193: public String getConnectionFactoryImplClass() {
194: return connectionFactoryImplClass;
195: }
196:
197: public void setConnectionFactoryImplClass(
198: String connectionFactoryImplClass) {
199: this .connectionFactoryImplClass = connectionFactoryImplClass;
200: }
201:
202: public String getConnectionInterface() {
203: return connectionInterface;
204: }
205:
206: public void setConnectionInterface(String connectionInterface) {
207: this .connectionInterface = connectionInterface;
208: }
209:
210: public String getConnectionImplClass() {
211: return connectionImplClass;
212: }
213:
214: public void setConnectionImplClass(String connectionImplClass) {
215: this .connectionImplClass = connectionImplClass;
216: }
217:
218: public String getTransactionSupport() {
219: return transactionSupport;
220: }
221:
222: public void setTransactionSupport(String transactionSupport) {
223: this .transactionSupport = transactionSupport;
224: }
225:
226: public Element getManagedConnectionFactoryProperties() {
227: return managedConnectionFactoryProperties;
228: }
229:
230: public void setManagedConnectionFactoryProperties(
231: Element managedConnectionFactoryProperties) {
232: this .managedConnectionFactoryProperties = managedConnectionFactoryProperties;
233: }
234:
235: public String getAuthenticationMechanismType() {
236: return authenticationMechanismType;
237: }
238:
239: public void setAuthenticationMechanismType(
240: String authenticationMechanismType) {
241: this .authenticationMechanismType = authenticationMechanismType;
242: }
243:
244: public String getCredentialInterface() {
245: return credentialInterface;
246: }
247:
248: public void setCredentialInterface(String credentialInterface) {
249: this .credentialInterface = credentialInterface;
250: }
251:
252: public boolean isReauthenticationSupport() {
253: return reauthenticationSupport;
254: }
255:
256: public void setReauthenticationSupport(
257: boolean reauthenticationSupport) {
258: this .reauthenticationSupport = reauthenticationSupport;
259: }
260:
261: public ManagedConnectionFactory getMcfInstance() {
262: return mcf;
263: }
264:
265: protected void startService() throws Exception {
266: if (mcf != null)
267: throw new DeploymentException(
268: "Stop the RARDeployment before restarting it");
269:
270: ConnectorMetaData cmd = null;
271: ConnectionDefinitionMetaData cdmd = null;
272: ResourceAdapter resourceAdapter = null;
273: if (oldRarDeployment != null) {
274: try {
275: resourceAdapter = (ResourceAdapter) getServer()
276: .getAttribute(oldRarDeployment,
277: "ResourceAdapter");
278: cmd = (ConnectorMetaData) getServer().getAttribute(
279: oldRarDeployment, "MetaData");
280: cdmd = cmd
281: .getConnectionDefinition(connectionDefinition);
282: if (cdmd == null)
283: throw new DeploymentException(
284: "ConnectionDefinition '"
285: + connectionDefinition
286: + "' not found in rar '" + rarName
287: + "'");
288: setManagedConnectionFactoryClass(cdmd
289: .getManagedConnectionFactoryClass());
290: setReauthenticationSupport(cmd
291: .getReauthenticationSupport());
292: } catch (Exception e) {
293: throw new DeploymentException(
294: "couldn't get oldRarDeployment! "
295: + oldRarDeployment, e);
296: }
297: }
298: try {
299: mcfClass = Thread.currentThread().getContextClassLoader()
300: .loadClass(managedConnectionFactoryClass);
301: } catch (ClassNotFoundException cnfe) {
302: log.error("Could not find ManagedConnectionFactory class: "
303: + managedConnectionFactoryClass, cnfe);
304: throw new DeploymentException(
305: "Could not find ManagedConnectionFactory class: "
306: + managedConnectionFactoryClass);
307: }
308: try {
309: mcf = (ManagedConnectionFactory) mcfClass.newInstance();
310: } catch (Exception e) {
311: log.error(
312: "Could not instantiate ManagedConnectionFactory: "
313: + managedConnectionFactoryClass, e);
314: throw new DeploymentException(
315: "Could not instantiate ManagedConnectionFactory: "
316: + managedConnectionFactoryClass);
317: }
318: if (cmd != null) {
319: // Set the resource adapter properties
320: setMcfProperties(cmd.getProperties(), false);
321: // Set the connection definition properties
322: setMcfProperties(cdmd.getProperties(), true);
323: }
324: //set overridden properties;
325: setMcfProperties(managedConnectionFactoryProperties);
326:
327: if (resourceAdapter != null
328: && mcf instanceof ResourceAdapterAssociation) {
329: ResourceAdapterAssociation raa = (ResourceAdapterAssociation) mcf;
330: raa.setResourceAdapter(resourceAdapter);
331: }
332: }
333:
334: protected void stopService() {
335: mcf = null;
336: mcfClass = null;
337: }
338:
339: public void setManagedConnectionFactoryAttribute(String name,
340: Class clazz, Object value) {
341: setManagedConnectionFactoryAttribute(name, clazz, value, false);
342: }
343:
344: protected void setManagedConnectionFactoryAttribute(String name,
345: Class clazz, Object value, boolean mustExist) {
346: if (name == null || name.length() == 0)
347: throw new IllegalArgumentException(
348: "Null or empty attribute name " + name);
349: String setterName = "set"
350: + Character.toUpperCase(name.charAt(0));
351: if (name.length() > 1)
352: setterName = setterName.concat(name.substring(1));
353: Method setter;
354: try {
355: setter = mcfClass.getMethod(setterName,
356: new Class[] { clazz });
357: } catch (NoSuchMethodException nsme) {
358: String error = "The class '" + mcfClass.toString()
359: + "' has no setter for config property '" + name
360: + "'";
361: if (mustExist)
362: throw new IllegalArgumentException(error);
363: else {
364: log.trace(error, nsme);
365: return;
366: }
367: }
368: try {
369: setter.invoke(mcf, new Object[] { value });
370: log.debug("set property " + name + " to value " + value);
371: } catch (Exception e) {
372: String error = "Unable to invoke setter method '" + setter
373: + "' " + "on object '" + mcf + "'";
374: if (e instanceof InvocationTargetException)
375: throw new NestedRuntimeException(error,
376: ((InvocationTargetException) e).getCause());
377: else
378: throw new NestedRuntimeException(error, e);
379: }
380: sendNotification(new Notification(
381: MCF_ATTRIBUTE_CHANGED_NOTIFICATION, getServiceName(),
382: getNextNotificationSequenceNumber()));
383: }
384:
385: public Object getManagedConnectionFactoryAttribute(String name) {
386: if (name == null || name.length() == 0)
387: throw new IllegalArgumentException(
388: "Null or empty attribute name " + name);
389: String getterName = "get"
390: + Character.toUpperCase(name.charAt(0));
391: if (name.length() > 1)
392: getterName = getterName.concat(name.substring(1));
393: Method getter;
394: try {
395: getter = mcfClass.getMethod(getterName, new Class[] {});
396: } catch (NoSuchMethodException e) {
397: String msg = "The class '" + mcfClass + "' has no getter("
398: + getterName + ") for config property '" + name
399: + "'";
400: log.debug(msg, e);
401: throw new IllegalArgumentException(msg);
402: }
403: try {
404: Object value = getter.invoke(mcf, new Object[] {});
405: log.debug("get property " + name + ": value " + value);
406: return value;
407: } catch (Exception e) {
408: String error = "Unable to invoke getter method '" + getter
409: + "' " + "on object '" + mcf + "'";
410: log.debug(error, e);
411: if (e instanceof InvocationTargetException)
412: throw new NestedRuntimeException(error,
413: ((InvocationTargetException) e).getCause());
414: else
415: throw new NestedRuntimeException(error, e);
416: }
417: }
418:
419: protected void setMcfProperties(Collection properties,
420: boolean mustExist) throws DeploymentException {
421: for (Iterator i = properties.iterator(); i.hasNext();) {
422: ConfigPropertyMetaData cpmd = (ConfigPropertyMetaData) i
423: .next();
424: String name = cpmd.getName();
425: String type = cpmd.getType();
426: String value = cpmd.getValue();
427: if (name == null || name.length() == 0 || value == null
428: || value.length() == 0) {
429: log.debug("Not setting config property '" + name + "'");
430: continue;
431: }
432: // see if it is a primitive type first
433: Class clazz = Classes.getPrimitiveTypeForName(type);
434: if (clazz == null) {
435: //not primitive, look for it.
436: try {
437: clazz = Thread.currentThread()
438: .getContextClassLoader().loadClass(type);
439: } catch (ClassNotFoundException cnfe) {
440: log.warn("Unable to find class '" + type + "' for "
441: + "property '" + name
442: + "' - skipping property.");
443: continue;
444: }
445: }
446: PropertyEditor pe = PropertyEditorManager.findEditor(clazz);
447: if (pe == null) {
448: log.warn("Unable to find a PropertyEditor for class '"
449: + clazz + "' of property '" + name + "' - "
450: + "skipping property");
451: continue;
452: }
453: log.debug("setting property: " + name + " to value "
454: + value);
455: try {
456: pe.setAsText(value);
457: } catch (IllegalArgumentException iae) {
458: log.warn("Value '" + value
459: + "' is not valid for property '" + name
460: + "' of class '" + clazz + "' - skipping "
461: + "property");
462: continue;
463: }
464: Object v = pe.getValue();
465: setManagedConnectionFactoryAttribute(name, clazz, v,
466: mustExist);
467: }
468: }
469:
470: protected void setMcfProperties(Element mcfProps)
471: throws DeploymentException {
472: if (mcfProps == null)
473: return;
474: // the properties that the deployment descriptor says we need to set
475: NodeList props = mcfProps.getChildNodes();
476: for (int i = 0; i < props.getLength(); i++) {
477: if (props.item(i).getNodeType() == Node.ELEMENT_NODE) {
478: Element prop = (Element) props.item(i);
479: if (prop.getTagName().equals("config-property")) {
480: String name = null;
481: String type = null;
482: String value = null;
483: //Support for more friendly config style
484: //<config-property name="" type=""></config-property>
485: if (prop.hasAttribute("name")) {
486: name = prop.getAttribute("name");
487: type = prop.getAttribute("type");
488: value = MetaData.getElementContent(prop, null,
489: false);
490: } else {
491: name = MetaData.getElementContent(MetaData
492: .getUniqueChild(prop,
493: "config-property-name"));
494: type = MetaData.getElementContent(MetaData
495: .getUniqueChild(prop,
496: "config-property-type"));
497: value = MetaData.getElementContent(MetaData
498: .getOptionalChild(prop,
499: "config-property-value"), null,
500: false);
501: }
502: if (name == null || name.length() == 0
503: || value == null || value.length() == 0) {
504: log.debug("Not setting config property '"
505: + name + "'");
506: continue;
507: }
508: if (type == null || type.length() == 0) {
509: // Default to String for convenience.
510: type = "java.lang.String";
511: }
512: // see if it is a primitive type first
513: Class clazz = Classes.getPrimitiveTypeForName(type);
514: if (clazz == null) {
515: //not primitive, look for it.
516: try {
517: clazz = Thread.currentThread()
518: .getContextClassLoader().loadClass(
519: type);
520: } catch (ClassNotFoundException cnfe) {
521: log.warn("Unable to find class '" + type
522: + "' for " + "property '" + name
523: + "' - skipping property.");
524: continue;
525: }
526: }
527: PropertyEditor pe = PropertyEditorManager
528: .findEditor(clazz);
529: if (pe == null) {
530: log
531: .warn("Unable to find a PropertyEditor for class '"
532: + clazz
533: + "' of property '"
534: + name
535: + "' - "
536: + "skipping property");
537: continue;
538: }
539: log.debug("setting property: " + name
540: + " to value " + value);
541: try {
542: pe.setAsText(value);
543: } catch (IllegalArgumentException iae) {
544: log.warn("Value '" + value
545: + "' is not valid for property '"
546: + name + "' of class '" + clazz
547: + "' - skipping " + "property");
548: continue;
549: }
550: Object v = pe.getValue();
551: setManagedConnectionFactoryAttribute(name, clazz, v);
552: }
553: }
554: }
555: }
556:
557: public Object createConnectionFactory() throws ResourceException {
558: return mcf.createConnectionFactory();
559: }
560:
561: public Object createConnectionFactory(ConnectionManager cxManager)
562: throws ResourceException {
563: return mcf.createConnectionFactory(cxManager);
564: }
565:
566: public ManagedConnection createManagedConnection(
567: javax.security.auth.Subject subject,
568: ConnectionRequestInfo cxRequestInfo)
569: throws ResourceException {
570: return mcf.createManagedConnection(subject, cxRequestInfo);
571: }
572:
573: public boolean equals(Object other) {
574: return mcf.equals(other);
575: }
576:
577: public java.io.PrintWriter getLogWriter() throws ResourceException {
578: return mcf.getLogWriter();
579: }
580:
581: public String toString() {
582: StringBuffer buffer = new StringBuffer();
583: buffer.append(getClass().getName());
584: buffer.append('@');
585: buffer.append(Integer
586: .toHexString(System.identityHashCode(this )));
587: return buffer.toString();
588: }
589:
590: public int hashCode() {
591: return mcf.hashCode();
592: }
593:
594: public ManagedConnection matchManagedConnections(
595: java.util.Set connectionSet,
596: javax.security.auth.Subject subject,
597: ConnectionRequestInfo cxRequestInfo)
598: throws ResourceException {
599: return mcf.matchManagedConnections(connectionSet, subject,
600: cxRequestInfo);
601: }
602:
603: public void setLogWriter(java.io.PrintWriter out)
604: throws ResourceException {
605: mcf.setLogWriter(out);
606: }
607: }
|