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