001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.jca;
030:
031: import com.caucho.config.Config;
032: import com.caucho.config.ConfigException;
033: import com.caucho.config.program.ContainerProgram;
034: import com.caucho.config.type.TypeFactory;
035: import com.caucho.jca.cfg.ObjectConfig;
036: import com.caucho.lifecycle.Lifecycle;
037: import com.caucho.loader.Environment;
038: import com.caucho.loader.EnvironmentClassLoader;
039: import com.caucho.loader.EnvironmentListener;
040: import com.caucho.naming.Jndi;
041: import com.caucho.util.L10N;
042: import com.caucho.webbeans.manager.*;
043:
044: import javax.annotation.PostConstruct;
045: import javax.resource.spi.*;
046: import javax.resource.spi.endpoint.MessageEndpointFactory;
047: import java.util.ArrayList;
048: import java.util.logging.Level;
049: import java.util.logging.Logger;
050:
051: /**
052: * Configuration for the <connector> pattern.
053: */
054: public class ConnectorConfig implements EnvironmentListener {
055: private static L10N L = new L10N(ConnectorConfig.class);
056: private static Logger log = Logger.getLogger(ConnectorConfig.class
057: .getName());
058:
059: private static int _idGen;
060:
061: private String _url;
062: private String _name;
063: private String _jndiName;
064: private String _type;
065:
066: private ResourceArchive _rar;
067:
068: private ResourceAdapterConfig _resourceAdapter = new ResourceAdapterConfig();
069: private ContainerProgram _init;
070:
071: private ArrayList<ConnectionFactory> _outboundList = new ArrayList<ConnectionFactory>();
072:
073: private ArrayList<ConnectionListener> _inboundList = new ArrayList<ConnectionListener>();
074:
075: private ArrayList<ConnectorBean> _beanList = new ArrayList<ConnectorBean>();
076:
077: private ResourceAdapter _ra;
078: private boolean _isInitRA;
079:
080: private final Lifecycle _lifecycle = new Lifecycle();
081:
082: /**
083: * Sets the name
084: */
085: public void setName(String name) {
086: _name = name;
087: }
088:
089: /**
090: * Sets the name
091: */
092: public void setJndiName(String name) {
093: _jndiName = name;
094: }
095:
096: /**
097: * Gets the name
098: */
099: public String getName() {
100: return _name;
101: }
102:
103: /**
104: * Sets the type of the connector.
105: */
106: public void setType(String type) throws Exception {
107: setClass(type);
108: }
109:
110: /**
111: * Sets the type of the connector using known types.
112: */
113: public void setURI(String url) throws Exception {
114: TypeFactory factory = TypeFactory.create();
115:
116: Class type = factory.getDriverClassByUrl(ResourceAdapter.class,
117: url);
118:
119: setClass(type.getName());
120:
121: ContainerProgram program = factory.getUrlProgram(url);
122:
123: if (program == null) {
124: } else if (_init == null)
125: _init = program;
126: else
127: _init.addProgram(program);
128: }
129:
130: /**
131: * Sets the type of the connector.
132: */
133: public void setClass(String type) throws Exception {
134: _type = type;
135:
136: _rar = ResourceArchiveManager.findResourceArchive(_type);
137:
138: ClassLoader loader = Thread.currentThread()
139: .getContextClassLoader();
140:
141: if (_rar != null) {
142: ObjectConfig raConfig = _rar.getResourceAdapter();
143:
144: if (raConfig.getType() != null)
145: _ra = (ResourceAdapter) raConfig.instantiate();
146: } else {
147: try {
148: Class raClass = Class.forName(_type, false, loader);
149:
150: _ra = (ResourceAdapter) raClass.newInstance();
151: } catch (Exception e) {
152: throw new ConfigException(
153: L
154: .l(
155: "'{0}' is not a known connector. The type must match the resource adaptor or managed connection factory of one of the installed *.rar files or specify a ResourceAdapter implementation.",
156: _type), e);
157: }
158: }
159: }
160:
161: /**
162: * Gets the type
163: */
164: public String getType() {
165: return _type;
166: }
167:
168: public void addInit(ContainerProgram init) {
169: _init = init;
170: }
171:
172: /**
173: * Configures the resource adapter.
174: */
175: public ResourceAdapterConfig createResourceAdapter()
176: throws ConfigException {
177: if (_ra == null)
178: throw new ConfigException(
179: L
180: .l(
181: "'{0}' may not have a <resource-adapter> section. Old-style connectors must use <connection-factory>, but not <resource-adapter>.",
182: _type));
183: return _resourceAdapter;
184: }
185:
186: /**
187: * Sets the configured resource adapter.
188: */
189: public void setResourceAdapter(ResourceAdapterConfig raConfig)
190: throws Exception {
191: }
192:
193: /**
194: * Configures a connection-factory
195: */
196: public ConnectionFactory createConnectionFactory() throws Exception {
197: initRA();
198:
199: return new ConnectionFactory();
200: }
201:
202: /**
203: * Configures a connection-factory
204: */
205: public void addConnectionFactory(ConnectionFactory factory)
206: throws Exception {
207: _outboundList.add(factory);
208: }
209:
210: /**
211: * Configures a connection-listener
212: */
213: public ConnectionListener createMessageListener() throws Exception {
214: initRA();
215:
216: return new ConnectionListener();
217: }
218:
219: /**
220: * Adds the configured connection-listener
221: */
222: public void addMessageListener(ConnectionListener listener)
223: throws Throwable {
224: _inboundList.add(listener);
225:
226: String listenerType = listener.getType();
227:
228: if (_ra == null)
229: throw new ConfigException(L
230: .l("message-listener requires a resource-adapter."));
231:
232: ActivationSpec activationSpec;
233:
234: if (_rar != null) {
235: ObjectConfig objectCfg = _rar
236: .getMessageListener(listenerType);
237:
238: if (objectCfg == null)
239: throw new ConfigException(
240: L
241: .l(
242: "`{0}' is an unknown type of <connection-listener> for `{1}'. The connector has no matching inbound connection-listener.",
243: listenerType, _type));
244:
245: activationSpec = (ActivationSpec) objectCfg.instantiate();
246: } else {
247: ClassLoader loader = Thread.currentThread()
248: .getContextClassLoader();
249: Class listenerClass = null;
250:
251: try {
252: listenerClass = Class.forName(listenerType, false,
253: loader);
254: } catch (Throwable e) {
255: throw new ConfigException(
256: L
257: .l(
258: "`{0}' is not a known listener. The type must match the activation spec for an inbound connection of one of the installed *.rar files or specify an ActivationSpec implementation.",
259: listenerType), e);
260: }
261:
262: activationSpec = (ActivationSpec) listenerClass
263: .newInstance();
264: }
265:
266: if (listener.getInit() != null)
267: listener.getInit().configure(activationSpec);
268: /*
269: TypeBuilderFactory.init(activationSpec);
270: */
271:
272: activationSpec.setResourceAdapter(_ra);
273: // activationSpec.validate();
274:
275: EndpointFactory endpointFactoryCfg = listener
276: .getEndpointFactory();
277:
278: if (endpointFactoryCfg == null)
279: throw new ConfigException(L
280: .l("connection-listener needs endpoint factory."));
281:
282: Class endpointClass = endpointFactoryCfg.getType();
283:
284: MessageEndpointFactory endpointFactory;
285: endpointFactory = (MessageEndpointFactory) endpointClass
286: .newInstance();
287:
288: if (endpointFactoryCfg.getInit() != null)
289: endpointFactoryCfg.getInit().configure(endpointFactory);
290:
291: Config.init(endpointFactory);
292:
293: listener.setEndpoint(endpointFactory);
294: listener.setActivation(activationSpec);
295: }
296:
297: /**
298: * Configures a connection-resource
299: */
300: public ConnectorBean createBean() {
301: return new ConnectorBean();
302: }
303:
304: /**
305: * Configures a connection-resource
306: */
307: public ConnectorBean createResource() {
308: return createBean();
309: }
310:
311: /**
312: * Initialize the resource.
313: */
314: @PostConstruct
315: public void init() throws Exception {
316: if (_type == null)
317: throw new ConfigException(L
318: .l("<connector> requires a <type>."));
319:
320: if (_name == null)
321: _name = _jndiName;
322:
323: if (_name == null && _rar != null)
324: _name = _rar.getDisplayName() + "-" + _idGen++;
325:
326: if (_ra == null)
327: throw new ConfigException(L
328: .l("<connector> does not have a resource adapter."));
329:
330: if (_resourceAdapter.getInit() != null)
331: _resourceAdapter.getInit().configure(_ra);
332:
333: if (_init != null)
334: _init.configure(_ra);
335:
336: ResourceManagerImpl.addResource(_ra);
337:
338: WebBeansContainer webBeans = WebBeansContainer.create();
339:
340: if (_resourceAdapter.getName() != null) {
341: Jndi.bindDeepShort(_resourceAdapter.getName(), _ra);
342:
343: webBeans.addSingleton(_ra, _resourceAdapter.getName());
344: } else
345: webBeans.addSingleton(_ra, _name);
346:
347: // create a default outbound factory
348: if (_outboundList.size() == 0 && _jndiName != null
349: && _rar != null) {
350: ObjectConfig factoryConfig = _rar
351: .getConnectionDefinition(null);
352:
353: if (factoryConfig != null) {
354: ConnectionFactory factory = createConnectionFactory();
355: factory.setJndiName(_jndiName);
356: factory.init();
357:
358: addConnectionFactory(factory);
359: }
360: }
361:
362: /*
363: if (close != null && ! (obj instanceof ResourceAdapter))
364: Environment.addEnvironmentListener(new CloseListener(obj, close));
365: */
366: initRA();
367:
368: Environment.addEnvironmentListener(this );
369:
370: start();
371:
372: log.fine("Connector[" + _type + "] active");
373: }
374:
375: /**
376: * Start the resource.
377: */
378: public void start() throws Exception {
379: if (!_lifecycle.toActive())
380: return;
381:
382: initRA();
383:
384: for (int i = 0; i < _outboundList.size(); i++) {
385: ConnectionFactory factory = _outboundList.get(i);
386:
387: factory.start();
388: }
389:
390: for (int i = 0; i < _inboundList.size(); i++) {
391: ConnectionListener listener = _inboundList.get(i);
392:
393: _ra.endpointActivation(listener.getEndpoint(), listener
394: .getActivation());
395: }
396: }
397:
398: /**
399: * Initializes the ra.
400: */
401: public void initRA() throws Exception {
402: /*
403: if (! _isInitRA) {
404: _isInitRA = true;
405:
406: if (_ra != null) {
407: // TypeBuilderFactory.init(_ra);
408: ResourceManagerImpl.addResource(_ra);
409: }
410: }
411: */
412: }
413:
414: /**
415: * Stops the connector.
416: */
417: public void stop() {
418: if (!_lifecycle.toStop())
419: return;
420:
421: for (int i = 0; i < _inboundList.size(); i++) {
422: ConnectionListener listener = _inboundList.get(i);
423:
424: MessageEndpointFactory endpointFactory = listener
425: .getEndpoint();
426: ActivationSpec activation = listener.getActivation();
427:
428: if (_ra != null)
429: _ra.endpointDeactivation(endpointFactory, activation);
430: }
431: }
432:
433: /**
434: * Handles the configure phase.
435: */
436: public void environmentConfig(EnvironmentClassLoader loader) {
437: }
438:
439: /**
440: * Handles the case where the environment is starting (after init).
441: */
442: public void environmentStart(EnvironmentClassLoader loader) {
443: try {
444: start();
445: } catch (Exception e) {
446: log.log(Level.WARNING, e.toString(), e);
447: }
448: }
449:
450: /**
451: * Handles the case where the environment is stopping
452: */
453: public void environmentStop(EnvironmentClassLoader loader) {
454: stop();
455: }
456:
457: @Override
458: public String toString() {
459: return "ConnectorResource[" + _name + "]";
460: }
461:
462: public class ResourceAdapterConfig {
463: private String _name;
464: private ContainerProgram _init;
465:
466: public void setJndiName(String name) {
467: _name = name;
468: }
469:
470: public String getName() {
471: return _name;
472: }
473:
474: public void setInit(ContainerProgram init) {
475: _init = init;
476: }
477:
478: public ContainerProgram getInit() {
479: return _init;
480: }
481: }
482:
483: public class ConnectionFactory {
484: private String _name;
485: private String _type;
486: private ManagedConnectionFactory _factory;
487: private boolean _localTransactionOptimization = true;
488: private boolean _shareable = true;
489: private ContainerProgram _init;
490:
491: public void setJndiName(String name) {
492: _name = name;
493: }
494:
495: public void setName(String name) {
496: _name = name;
497: }
498:
499: public String getName() {
500: return _name;
501: }
502:
503: public void setType(String type) throws Exception {
504: setClass(type);
505: }
506:
507: public void setClass(String type) throws Exception {
508: _type = type;
509:
510: if (_rar != null) {
511: ObjectConfig factoryConfig = _rar
512: .getConnectionDefinition(type);
513:
514: if (factoryConfig == null)
515: throw new ConfigException(
516: L
517: .l(
518: "'{0}' is an unknown type of <connection-factory> for '{1}'. The connector has no matching outbound connection-factory.",
519: type,
520: ConnectorConfig.this ._type));
521:
522: _factory = (ManagedConnectionFactory) factoryConfig
523: .instantiate();
524: } else if (type != null) {
525: ClassLoader loader = Thread.currentThread()
526: .getContextClassLoader();
527: Class factoryClass = null;
528:
529: try {
530: factoryClass = Class.forName(type, false, loader);
531: } catch (Exception e) {
532: throw new ConfigException(
533: L
534: .l(
535: "'{0}' is not a known connection factory. The type must match the resource adaptor or managed connection factory of one of the installed *.rar files or specify a ManagedConnectionFactory implementation.",
536: type));
537: }
538:
539: if (!ManagedConnectionFactory.class
540: .isAssignableFrom(factoryClass)) {
541: throw new ConfigException(
542: L
543: .l(
544: "'{0}' does not implement javax.resource.spi.ManagedConnectionFactory. <connection-factory> classes must implement ManagedConnectionFactory.",
545: factoryClass.getName()));
546: }
547:
548: _factory = (ManagedConnectionFactory) factoryClass
549: .newInstance();
550: }
551:
552: }
553:
554: public String getType() {
555: return _type;
556: }
557:
558: /**
559: * Enables the local transaction optimization.
560: */
561: public void setLocalTransactionOptimization(boolean enable) {
562: _localTransactionOptimization = enable;
563: }
564:
565: /**
566: * Enables the local transaction optimization.
567: */
568: public boolean getLocalTransactionOptimization() {
569: return _localTransactionOptimization;
570: }
571:
572: /**
573: * Enables the shareable property
574: */
575: public void setShareable(boolean enable) {
576: _shareable = enable;
577: }
578:
579: /**
580: * Enables the shareable property
581: */
582: public boolean getShareable() {
583: return _shareable;
584: }
585:
586: public ManagedConnectionFactory getFactory() {
587: return _factory;
588: }
589:
590: public void setInit(ContainerProgram init) {
591: _init = init;
592: }
593:
594: public ContainerProgram getInit() {
595: return _init;
596: }
597:
598: @PostConstruct
599: public void init() throws Exception {
600: if (_factory == null && _rar != null) {
601: ObjectConfig factoryConfig = _rar
602: .getConnectionDefinition(null);
603:
604: _factory = (ManagedConnectionFactory) factoryConfig
605: .instantiate();
606: }
607:
608: if (_factory == null)
609: throw new ConfigException(L
610: .l("connection-factory requires a valid type."));
611: }
612:
613: /**
614: * Configures a connection-factory
615: */
616: public void start() throws Exception {
617: ManagedConnectionFactory managedFactory = getFactory();
618:
619: if (getInit() != null)
620: getInit().configure(managedFactory);
621:
622: if (_ra != null
623: && managedFactory instanceof ResourceAdapterAssociation) {
624: ((ResourceAdapterAssociation) managedFactory)
625: .setResourceAdapter(_ra);
626: }
627:
628: ResourceManagerImpl rm = ResourceManagerImpl
629: .createLocalManager();
630:
631: ConnectionPool cm = rm.createConnectionPool();
632:
633: if (_name != null)
634: cm.setName(_name);
635:
636: if (_rar != null) {
637: String trans = _rar.getTransactionSupport();
638:
639: if (trans == null) { // guess XA
640: cm.setXATransaction(true);
641: cm.setLocalTransaction(true);
642: } else if (trans.equals("XATransaction")) {
643: cm.setXATransaction(true);
644: cm.setLocalTransaction(true);
645: } else if (trans.equals("NoTransaction")) {
646: cm.setXATransaction(false);
647: cm.setLocalTransaction(false);
648: } else if (trans.equals("LocalTransaction")) {
649: cm.setXATransaction(false);
650: cm.setLocalTransaction(true);
651: }
652: }
653:
654: cm
655: .setLocalTransactionOptimization(getLocalTransactionOptimization());
656: cm.setShareable(getShareable());
657:
658: Object connectionFactory = cm.init(managedFactory);
659: cm.start();
660:
661: WebBeansContainer webBeans = WebBeansContainer.create();
662:
663: if (getName() != null) {
664: Jndi.bindDeepShort(getName(), connectionFactory);
665:
666: webBeans.addSingleton(connectionFactory, getName());
667: } else
668: webBeans.addSingleton(connectionFactory);
669: }
670: }
671:
672: public class ConnectionListener {
673: private String _name;
674: private String _type;
675: private ContainerProgram _init;
676: private EndpointFactory _endpointFactory;
677:
678: private MessageEndpointFactory _endpoint;
679: private ActivationSpec _activation;
680:
681: public void setJndiName(String name) {
682: _name = name;
683: }
684:
685: public String getName() {
686: return _name;
687: }
688:
689: public void setType(String type) {
690: _type = type;
691: }
692:
693: public String getType() {
694: return _type;
695: }
696:
697: public void setInit(ContainerProgram init) {
698: _init = init;
699: }
700:
701: public ContainerProgram getInit() {
702: return _init;
703: }
704:
705: public EndpointFactory getEndpointFactory() {
706: return _endpointFactory;
707: }
708:
709: public EndpointFactory createEndpointFactory() {
710: _endpointFactory = new EndpointFactory();
711:
712: return _endpointFactory;
713: }
714:
715: @PostConstruct
716: public void init() throws ConfigException {
717: if (_endpointFactory == null)
718: throw new ConfigException(
719: L
720: .l("connection-listener needs an endpoint-factory"));
721: }
722:
723: public void setEndpoint(MessageEndpointFactory endpoint) {
724: _endpoint = endpoint;
725: }
726:
727: public MessageEndpointFactory getEndpoint() {
728: return _endpoint;
729: }
730:
731: public void setActivation(ActivationSpec activation) {
732: _activation = activation;
733: }
734:
735: public ActivationSpec getActivation() {
736: return _activation;
737: }
738: }
739:
740: public class EndpointFactory {
741: private String _name;
742: private Class _type;
743: private ContainerProgram _init;
744:
745: public void setJndiName(String name) {
746: _name = name;
747: }
748:
749: public String getName() {
750: return _name;
751: }
752:
753: public void setType(Class type) throws ConfigException {
754: _type = type;
755:
756: Config.checkCanInstantiate(type);
757: }
758:
759: public Class getType() {
760: return _type;
761: }
762:
763: public void setInit(ContainerProgram init) {
764: _init = init;
765: }
766:
767: public ContainerProgram getInit() {
768: return _init;
769: }
770: }
771:
772: public class ConnectorBean {
773: private String _name;
774: private String _type;
775: private ContainerProgram _init;
776:
777: private ObjectConfig _objectConfig;
778: private Object _object;
779:
780: public void setJndiName(String name) {
781: _name = name;
782: }
783:
784: public void setName(String name) {
785: _name = name;
786: }
787:
788: public String getName() {
789: return _name;
790: }
791:
792: public void setType(String type) throws Exception {
793: setClass(type);
794: }
795:
796: public void setClass(String type) throws Exception {
797: _type = type;
798:
799: Object resourceObject = null;
800:
801: if (_rar != null) {
802: _objectConfig = _rar.getAdminObject(type);
803:
804: if (_objectConfig == null)
805: throw new ConfigException(
806: L
807: .l(
808: "`{0}' may not have a <resource> section. The connector has no matching <adminobject> defined.",
809: _type));
810:
811: _object = _objectConfig.instantiate();
812: } else {
813: ClassLoader loader = Thread.currentThread()
814: .getContextClassLoader();
815: try {
816: Class resourceClass = Class.forName(type, false,
817: loader);
818:
819: _object = resourceClass.newInstance();
820: } catch (Exception e) {
821: throw new ConfigException(
822: L
823: .l(
824: "`{0}' is not a known resource. The type must match the adminobject of one of the installed *.rar files.",
825: _type), e);
826: }
827:
828: }
829: }
830:
831: public String getType() {
832: return _type;
833: }
834:
835: public void setInit(ContainerProgram init) {
836: _init = init;
837: }
838:
839: public ContainerProgram getInit() {
840: return _init;
841: }
842:
843: public Object getObject() {
844: return _object;
845: }
846:
847: @PostConstruct
848: public void init() throws Exception {
849: if (_object == null)
850: throw new ConfigException(L
851: .l("<class> must be set for a bean."));
852:
853: Object resourceObject = getObject();
854:
855: if (getInit() != null)
856: getInit().configure(resourceObject);
857:
858: if (_ra != null
859: && resourceObject instanceof ResourceAdapterAssociation)
860: ((ResourceAdapterAssociation) resourceObject)
861: .setResourceAdapter(_ra);
862:
863: WebBeansContainer webBeans = WebBeansContainer.create();
864:
865: if (getName() != null) {
866: Jndi.bindDeepShort(getName(), resourceObject);
867:
868: webBeans.addSingleton(resourceObject, getName());
869: } else
870: webBeans.addSingleton(resourceObject);
871: }
872: }
873: }
|