/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.jca.ra; import com.caucho.config.Config; import com.caucho.config.ConfigException; import com.caucho.config.Names; import com.caucho.config.inject.BeanBuilder; import com.caucho.config.inject.InjectManager; import com.caucho.config.inject.CurrentLiteral; import com.caucho.config.program.ContainerProgram; import com.caucho.config.type.TypeFactory; import com.caucho.env.dbpool.ConnectionPool; import com.caucho.lifecycle.Lifecycle; import com.caucho.loader.Environment; import com.caucho.loader.EnvironmentClassLoader; import com.caucho.loader.EnvironmentListener; import com.caucho.naming.Jndi; import com.caucho.util.L10N; import javax.annotation.PostConstruct; import javax.resource.spi.*; import javax.resource.spi.endpoint.MessageEndpointFactory; import java.util.ArrayList; import java.util.logging.Level; import java.util.logging.Logger; /** * Configuration for the <connector> pattern. */ public class ConnectorConfig implements EnvironmentListener { private static L10N L = new L10N(ConnectorConfig.class); private static Logger log = Logger.getLogger(ConnectorConfig.class.getName()); private static int _idGen; private String _url; private String _name; private String _jndiName; private String _type; private ResourceArchive _rar; private ResourceAdapterConfig _resourceAdapter = new ResourceAdapterConfig(); private ContainerProgram _init; private ArrayList<ConnectionFactory> _outboundList = new ArrayList<ConnectionFactory>(); private ArrayList<ConnectionListener> _inboundList = new ArrayList<ConnectionListener>(); private ArrayList<ConnectorBean> _beanList = new ArrayList<ConnectorBean>(); private ResourceAdapter _ra; private boolean _isInitRA; private final Lifecycle _lifecycle = new Lifecycle(); /** * Sets the name */ public void setName(String name) { _name = name; } /** * Sets the name */ public void setJndiName(String name) { _jndiName = name; } /** * Gets the name */ public String getName() { return _name; } /** * Sets the type of the connector. */ public void setType(String type) throws Exception { setClass(type); } /** * Sets the type of the connector using known types. */ public void setURI(String url) throws Exception { TypeFactory factory = TypeFactory.create(); Class type = factory.getDriverClassByUrl(ResourceAdapter.class, url); setClass(type.getName()); ContainerProgram program = factory.getUrlProgram(url); if (program == null) { } else if (_init == null) _init = program; else _init.addProgram(program); } /** * Sets the type of the connector. */ public void setClass(String type) throws Exception { _type = type; _rar = ResourceArchiveManager.findResourceArchive(_type); ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (_rar != null) { ObjectConfig raConfig = _rar.getResourceAdapter(); if (raConfig.getType() != null) _ra = (ResourceAdapter) raConfig.instantiate(); } else { try { Class raClass = Class.forName(_type, false, loader); _ra = (ResourceAdapter) raClass.newInstance(); } catch (Exception e) { throw new ConfigException(L.l("'{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.", _type), e); } } } /** * Gets the type */ public String getType() { return _type; } public void addInit(ContainerProgram init) { _init = init; } /** * Configures the resource adapter. */ public ResourceAdapterConfig createResourceAdapter() throws ConfigException { if (_ra == null) throw new ConfigException(L.l("'{0}' may not have a <resource-adapter> section. Old-style connectors must use <connection-factory>, but not <resource-adapter>.", _type)); return _resourceAdapter; } /** * Sets the configured resource adapter. */ public void setResourceAdapter(ResourceAdapterConfig raConfig) throws Exception { } /** * Configures a connection-factory */ public ConnectionFactory createConnectionFactory() throws Exception { initRA(); return new ConnectionFactory(); } /** * Configures a connection-factory */ public void addConnectionFactory(ConnectionFactory factory) throws Exception { _outboundList.add(factory); } /** * Configures a connection-listener */ public ConnectionListener createMessageListener() throws Exception { initRA(); return new ConnectionListener(); } /** * Adds the configured connection-listener */ public void addMessageListener(ConnectionListener listener) throws Throwable { _inboundList.add(listener); String listenerType = listener.getType(); if (_ra == null) throw new ConfigException(L.l("message-listener requires a resource-adapter.")); ActivationSpec activationSpec; if (_rar != null) { ObjectConfig objectCfg = _rar.getMessageListener(listenerType); if (objectCfg == null) throw new ConfigException(L.l("'{0}' is an unknown type of <connection-listener> for '{1}'. The connector has no matching inbound connection-listener.", listenerType, _type)); activationSpec = (ActivationSpec) objectCfg.instantiate(); } else { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class listenerClass = null; try { listenerClass = Class.forName(listenerType, false, loader); } catch (Throwable e) { throw new ConfigException(L.l("'{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.", listenerType), e); } activationSpec = (ActivationSpec) listenerClass.newInstance(); } if (listener.getInit() != null) listener.getInit().configure(activationSpec); /* TypeBuilderFactory.init(activationSpec); */ activationSpec.setResourceAdapter(_ra); // activationSpec.validate(); EndpointFactory endpointFactoryCfg = listener.getEndpointFactory(); if (endpointFactoryCfg == null) throw new ConfigException(L.l("connection-listener needs endpoint factory.")); Class endpointClass = endpointFactoryCfg.getType(); MessageEndpointFactory endpointFactory; endpointFactory = (MessageEndpointFactory) endpointClass.newInstance(); if (endpointFactoryCfg.getInit() != null) endpointFactoryCfg.getInit().configure(endpointFactory); Config.init(endpointFactory); listener.setEndpoint(endpointFactory); listener.setActivation(activationSpec); } /** * Configures a connection-resource */ public ConnectorBean createBean() { return new ConnectorBean(); } /** * Configures a connection-resource */ public ConnectorBean createResource() { return createBean(); } /** * Initialize the resource. */ @PostConstruct public void init() throws Exception { if (_type == null) throw new ConfigException(L.l("<connector> requires a <type>.")); if (_name == null) _name = _jndiName; if (_name == null && _rar != null) _name = _rar.getDisplayName() + "-" + _idGen++; if (_ra == null) throw new ConfigException(L.l("<connector> does not have a resource adapter.")); if (_resourceAdapter.getInit() != null) _resourceAdapter.getInit().configure(_ra); if (_init != null) _init.configure(_ra); ResourceManagerImpl.addResource(_ra); InjectManager beanManager = InjectManager.create(); BeanBuilder factory = beanManager.createBeanFactory(_ra.getClass()); if (_resourceAdapter.getName() != null) { Jndi.bindDeepShort(_resourceAdapter.getName(), _ra); beanManager.addBean(factory.name(_resourceAdapter.getName()) .singleton(_ra)); } else { beanManager.addBean(factory.name(_name).singleton(_ra)); } // create a default outbound factory if (_outboundList.size() == 0 && _jndiName != null && _rar != null) { ObjectConfig factoryConfig = _rar.getConnectionDefinition(null); if (factoryConfig != null) { ConnectionFactory connFactory = createConnectionFactory(); connFactory.setJndiName(_jndiName); connFactory.init(); addConnectionFactory(connFactory); } } /* if (close != null && ! (obj instanceof ResourceAdapter)) Environment.addEnvironmentListener(new CloseListener(obj, close)); */ initRA(); Environment.addEnvironmentListener(this); start(); log.fine("Connector[" + _type + "] active"); } /** * Start the resource. */ public void start() throws Exception { if (! _lifecycle.toActive()) return; initRA(); for (int i = 0; i < _outboundList.size(); i++) { ConnectionFactory factory = _outboundList.get(i); factory.start(); } for (int i = 0; i < _inboundList.size(); i++) { ConnectionListener listener = _inboundList.get(i); _ra.endpointActivation(listener.getEndpoint(), listener.getActivation()); } } /** * Initializes the ra. */ public void initRA() throws Exception { /* if (! _isInitRA) { _isInitRA = true; if (_ra != null) { // TypeBuilderFactory.init(_ra); ResourceManagerImpl.addResource(_ra); } } */ } /** * Stops the connector. */ public void stop() { if (! _lifecycle.toStop()) return; for (int i = 0; i < _inboundList.size(); i++) { ConnectionListener listener = _inboundList.get(i); MessageEndpointFactory endpointFactory = listener.getEndpoint(); ActivationSpec activation = listener.getActivation(); if (_ra != null) _ra.endpointDeactivation(endpointFactory, activation); } } /** * Handles the configure phase. */ public void environmentConfigure(EnvironmentClassLoader loader) { } /** * Handles the bind phase. */ public void environmentBind(EnvironmentClassLoader loader) { } /** * Handles the case where the environment is starting (after init). */ public void environmentStart(EnvironmentClassLoader loader) { try { start(); } catch (Exception e) { log.log(Level.WARNING, e.toString(), e); } } /** * Handles the case where the environment is stopping */ public void environmentStop(EnvironmentClassLoader loader) { stop(); } @Override public String toString() { return "ConnectorResource[" + _name + "]"; } public class ResourceAdapterConfig { private String _name; private ContainerProgram _init; public void setJndiName(String name) { _name = name; } public String getName() { return _name; } public void setInit(ContainerProgram init) { _init = init; } public ContainerProgram getInit() { return _init; } } public class ConnectionFactory { private String _name; private String _type; private ManagedConnectionFactory _factory; private boolean _localTransactionOptimization = true; private boolean _shareable = true; private ContainerProgram _init; public void setJndiName(String name) { _name = name; } public void setName(String name) { _name = name; } public String getName() { return _name; } public void setType(String type) throws Exception { setClass(type); } public void setClass(String type) throws Exception { _type = type; if (_rar != null) { ObjectConfig factoryConfig = _rar.getConnectionDefinition(type); if (factoryConfig == null) throw new ConfigException(L.l("'{0}' is an unknown type of <connection-factory> for '{1}'. The connector has no matching outbound connection-factory.", type, ConnectorConfig.this._type)); _factory = (ManagedConnectionFactory) factoryConfig.instantiate(); } else if (type != null) { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class factoryClass = null; try { factoryClass = Class.forName(type, false, loader); } catch (Exception e) { throw new ConfigException(L.l("'{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.", type)); } if (! ManagedConnectionFactory.class.isAssignableFrom(factoryClass)) { throw new ConfigException(L.l("'{0}' does not implement javax.resource.spi.ManagedConnectionFactory. <connection-factory> classes must implement ManagedConnectionFactory.", factoryClass.getName())); } _factory = (ManagedConnectionFactory) factoryClass.newInstance(); } } public String getType() { return _type; } /** * Enables the local transaction optimization. */ public void setLocalTransactionOptimization(boolean enable) { _localTransactionOptimization = enable; } /** * Enables the local transaction optimization. */ public boolean getLocalTransactionOptimization() { return _localTransactionOptimization; } /** * Enables the shareable property */ public void setShareable(boolean enable) { _shareable = enable; } /** * Enables the shareable property */ public boolean getShareable() { return _shareable; } public ManagedConnectionFactory getFactory() { return _factory; } public void setInit(ContainerProgram init) { _init = init; } public ContainerProgram getInit() { return _init; } @PostConstruct public void init() throws Exception { if (_factory == null && _rar != null) { ObjectConfig factoryConfig = _rar.getConnectionDefinition(null); _factory = (ManagedConnectionFactory) factoryConfig.instantiate(); } if (_factory == null) throw new ConfigException(L.l("connection-factory requires a valid type.")); } /** * Configures a connection-factory */ public void start() throws Exception { ManagedConnectionFactory managedFactory = getFactory(); if (getInit() != null) getInit().configure(managedFactory); if (_ra != null && managedFactory instanceof ResourceAdapterAssociation) { ((ResourceAdapterAssociation) managedFactory).setResourceAdapter(_ra); } ResourceManagerImpl rm = ResourceManagerImpl.createLocalManager(); ConnectionPool cm = rm.createConnectionPool(); if (_name != null) cm.setName(_name); if (_rar != null) { String trans = _rar.getTransactionSupport(); if (trans == null) { // guess XA cm.setXATransaction(true); cm.setLocalTransaction(true); } else if (trans.equals("XATransaction")) { cm.setXATransaction(true); cm.setLocalTransaction(true); } else if (trans.equals("NoTransaction")) { cm.setXATransaction(false); cm.setLocalTransaction(false); } else if (trans.equals("LocalTransaction")) { cm.setXATransaction(false); cm.setLocalTransaction(true); } } cm.setLocalTransactionOptimization(getLocalTransactionOptimization()); cm.setShareable(getShareable()); Object connectionFactory = cm.init(managedFactory); cm.start(); InjectManager manager = InjectManager.create(); BeanBuilder factory = manager.createBeanFactory(connectionFactory.getClass()); if (getName() != null) { Jndi.bindDeepShort(getName(), connectionFactory); factory.name(getName()); // server/30b4 factory.qualifier(Names.create(getName())); factory.qualifier(CurrentLiteral.CURRENT); } manager.addBean(factory.singleton(connectionFactory)); } } public class ConnectionListener { private String _name; private String _type; private ContainerProgram _init; private EndpointFactory _endpointFactory; private MessageEndpointFactory _endpoint; private ActivationSpec _activation; public void setJndiName(String name) { _name = name; } public String getName() { return _name; } public void setType(String type) { _type = type; } public String getType() { return _type; } public void setInit(ContainerProgram init) { _init = init; } public ContainerProgram getInit() { return _init; } public EndpointFactory getEndpointFactory() { return _endpointFactory; } public EndpointFactory createEndpointFactory() { _endpointFactory = new EndpointFactory(); return _endpointFactory; } @PostConstruct public void init() throws ConfigException { if (_endpointFactory == null) throw new ConfigException(L.l("connection-listener needs an endpoint-factory")); } public void setEndpoint(MessageEndpointFactory endpoint) { _endpoint = endpoint; } public MessageEndpointFactory getEndpoint() { return _endpoint; } public void setActivation(ActivationSpec activation) { _activation = activation; } public ActivationSpec getActivation() { return _activation; } } public class EndpointFactory { private String _name; private Class _type; private ContainerProgram _init; public void setJndiName(String name) { _name = name; } public String getName() { return _name; } public void setType(Class type) throws ConfigException { _type = type; Config.checkCanInstantiate(type); } public Class getType() { return _type; } public void setInit(ContainerProgram init) { _init = init; } public ContainerProgram getInit() { return _init; } } public class ConnectorBean { private String _name; private String _type; private ContainerProgram _init; private ObjectConfig _objectConfig; private Object _object; public void setJndiName(String name) { _name = name; } public void setName(String name) { _name = name; } public String getName() { return _name; } public void setType(String type) throws Exception { setClass(type); } public void setClass(String type) throws Exception { _type = type; Object resourceObject = null; if (_rar != null) { _objectConfig = _rar.getAdminObject(type); if (_objectConfig == null) throw new ConfigException(L.l("'{0}' may not have a <resource> section. The connector has no matching <adminobject> defined.", _type)); _object = _objectConfig.instantiate(); } else { ClassLoader loader = Thread.currentThread().getContextClassLoader(); try { Class resourceClass = Class.forName(type, false, loader); _object = resourceClass.newInstance(); } catch (Exception e) { throw new ConfigException(L.l("'{0}' is not a known resource. The type must match the adminobject of one of the installed *.rar files.", _type), e); } } } public String getType() { return _type; } public void setInit(ContainerProgram init) { _init = init; } public ContainerProgram getInit() { return _init; } public Object getObject() { return _object; } @PostConstruct public void init() throws Exception { if (_object == null) throw new ConfigException(L.l("<class> must be set for a bean.")); Object resourceObject = getObject(); if (getInit() != null) getInit().configure(resourceObject); if (_ra != null && resourceObject instanceof ResourceAdapterAssociation) ((ResourceAdapterAssociation) resourceObject).setResourceAdapter(_ra); InjectManager manager = InjectManager.create(); BeanBuilder factory = manager.createBeanFactory(resourceObject.getClass()); if (getName() != null) { Jndi.bindDeepShort(getName(), resourceObject); manager.addBean(factory.name(getName()).singleton(resourceObject)); } else manager.addBean(factory.singleton(resourceObject)); } } }