001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.activemq.ra;
018
019import java.io.IOException;
020import java.io.ObjectInputStream;
021import java.io.ObjectOutputStream;
022import java.io.PrintWriter;
023import java.io.Serializable;
024import java.util.Iterator;
025import java.util.Set;
026
027import javax.jms.JMSException;
028import javax.resource.ResourceException;
029import javax.resource.spi.ConnectionManager;
030import javax.resource.spi.ConnectionRequestInfo;
031import javax.resource.spi.ManagedConnection;
032import javax.resource.spi.ManagedConnectionFactory;
033import javax.resource.spi.ResourceAdapter;
034import javax.resource.spi.ResourceAdapterAssociation;
035import javax.security.auth.Subject;
036
037import org.slf4j.LoggerFactory;
038
039/**
040 * @version $Revisio n$ TODO: Must override equals and hashCode (JCA spec 16.4)
041 * @org.apache.xbean.XBean element="managedConnectionFactory"
042 */
043public class ActiveMQManagedConnectionFactory extends ActiveMQConnectionSupport implements ManagedConnectionFactory, ResourceAdapterAssociation {
044
045    private static final long serialVersionUID = 6196921962230582875L;
046    private PrintWriter logWriter;
047
048    /**
049     * @see javax.resource.spi.ResourceAdapterAssociation#setResourceAdapter(javax.resource.spi.ResourceAdapter)
050     */
051    @Override
052    public void setResourceAdapter(ResourceAdapter adapter) throws ResourceException {
053        if (!(adapter instanceof MessageResourceAdapter)) {
054            throw new ResourceException("ResourceAdapter is not of type: " + MessageResourceAdapter.class.getName());
055        } else {
056            if (log.isDebugEnabled()) {
057                log.debug(this + ", copying standard ResourceAdapter configuration properties");
058            }
059
060            ActiveMQConnectionRequestInfo baseInfo = ((MessageResourceAdapter) adapter).getInfo().copy();
061            if (getClientid() == null) {
062                setClientid(baseInfo.getClientid());
063            }
064            if (getPassword() == null) {
065                setPassword(baseInfo.getPassword());
066            }
067            if (getServerUrl() == null) {
068                setServerUrl(baseInfo.getServerUrl());
069            }
070            if (getUseInboundSession() == null) {
071                setUseInboundSession(baseInfo.getUseInboundSession());
072            }
073            if (getUseSessionArgs() == null) {
074                setUseSessionArgs(baseInfo.isUseSessionArgs());
075            }
076            if (getUserName() == null) {
077                setUserName(baseInfo.getUserName());
078            }
079            if (getDurableTopicPrefetch() == null) {
080                setDurableTopicPrefetch(baseInfo.getDurableTopicPrefetch());
081            }
082            if (getOptimizeDurableTopicPrefetch() == null) {
083                setOptimizeDurableTopicPrefetch(baseInfo.getOptimizeDurableTopicPrefetch());
084            }
085            if (getQueuePrefetch() == null) {
086                setQueuePrefetch(baseInfo.getQueuePrefetch());
087            }
088            if (getQueueBrowserPrefetch() == null) {
089                setQueueBrowserPrefetch(baseInfo.getQueueBrowserPrefetch());
090            }
091            if (getTopicPrefetch() == null) {
092                setTopicPrefetch(baseInfo.getTopicPrefetch());
093            }
094            if (getKeyStore() == null) {
095                setKeyStore(baseInfo.getKeyStore());
096            }
097            if (getKeyStorePassword() == null) {
098                setKeyStorePassword(baseInfo.getKeyStorePassword());
099            }
100            if (getTrustStore() == null) {
101                setTrustStore(baseInfo.getTrustStore());
102            }
103            if (getTrustStorePassword() == null) {
104                setTrustStorePassword(baseInfo.getTrustStorePassword());
105            }
106        }
107    }
108
109    /**
110     * @see javax.resource.spi.ResourceAdapterAssociation#getResourceAdapter()
111     */
112    @Override
113    public ResourceAdapter getResourceAdapter() {
114        return null;
115    }
116
117    /**
118     * @see java.lang.Object#equals(java.lang.Object)
119     */
120    @Override
121    public boolean equals(Object object) {
122        if (object == null || object.getClass() != ActiveMQManagedConnectionFactory.class) {
123            return false;
124        }
125        return ((ActiveMQManagedConnectionFactory) object).getInfo().equals(getInfo());
126    }
127
128    /**
129     * @see java.lang.Object#hashCode()
130     */
131    @Override
132    public int hashCode() {
133        return getInfo().hashCode();
134    }
135
136    /**
137     * Writes this factory during serialization along with the superclass'
138     * <i>info</i> property. This needs to be done manually since the superclass
139     * is not serializable itself.
140     *
141     * @param out
142     *        the stream to write object state to
143     * @throws java.io.IOException
144     *         if the object cannot be serialized
145     */
146    private void writeObject(ObjectOutputStream out) throws IOException {
147        if (logWriter != null && !(logWriter instanceof Serializable)) {
148            // if the PrintWriter injected by the application server is not
149            // serializable we just drop the reference and let the application
150            // server re-inject a PrintWriter later (after this factory has been
151            // deserialized again) using the standard setLogWriter() method
152            logWriter = null;
153        }
154        out.defaultWriteObject();
155        out.writeObject(getInfo());
156    }
157
158    /**
159     * Restores this factory along with the superclass' <i>info</i> property.
160     * This needs to be done manually since the superclass is not serializable
161     * itself.
162     *
163     * @param in
164     *        the stream to read object state from
165     * @throws java.io.IOException
166     *         if the object state could not be restored
167     * @throws java.lang.ClassNotFoundException
168     *         if the object state could not be restored
169     */
170    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
171        in.defaultReadObject();
172        setInfo((ActiveMQConnectionRequestInfo) in.readObject());
173        log = LoggerFactory.getLogger(getClass());
174    }
175
176    /**
177     * @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory(javax.resource.spi.ConnectionManager)
178     */
179    @Override
180    public Object createConnectionFactory(ConnectionManager manager) throws ResourceException {
181        return new ActiveMQConnectionFactory(this, manager, getInfo());
182    }
183
184    /**
185     * This is used when not running in an app server. For now we are creating a
186     * ConnectionFactory that has our SimpleConnectionManager implementation but
187     * it may be a better idea to not support this. The JMS api will have many
188     * quirks the user may not expect when running through the resource adapter.
189     *
190     * @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory()
191     */
192    @Override
193    public Object createConnectionFactory() throws ResourceException {
194        return new ActiveMQConnectionFactory(this, new SimpleConnectionManager(), getInfo());
195    }
196
197    /**
198     * @see javax.resource.spi.ManagedConnectionFactory#createManagedConnection(javax.security.auth.Subject,
199     *      javax.resource.spi.ConnectionRequestInfo)
200     */
201    @Override
202    public ManagedConnection createManagedConnection(Subject subject, ConnectionRequestInfo connectionRequestInfo) throws ResourceException {
203        ActiveMQConnectionRequestInfo amqInfo = getInfo();
204        if (connectionRequestInfo instanceof ActiveMQConnectionRequestInfo) {
205            amqInfo = (ActiveMQConnectionRequestInfo) connectionRequestInfo;
206        }
207        try {
208            return new ActiveMQManagedConnection(subject, makeConnection(amqInfo), amqInfo);
209        } catch (JMSException e) {
210            throw new ResourceException("Could not create connection.", e);
211        }
212    }
213
214    /**
215     * @see javax.resource.spi.ManagedConnectionFactory#matchManagedConnections(java.util.Set,
216     *      javax.security.auth.Subject,
217     *      javax.resource.spi.ConnectionRequestInfo)
218     */
219    @Override
220    public ManagedConnection matchManagedConnections(Set connections, Subject subject, ConnectionRequestInfo connectionRequestInfo) throws ResourceException {
221        Iterator iterator = connections.iterator();
222        while (iterator.hasNext()) {
223            ActiveMQManagedConnection c = (ActiveMQManagedConnection) iterator.next();
224            if (c.matches(subject, connectionRequestInfo)) {
225                try {
226                    c.associate(subject, (ActiveMQConnectionRequestInfo) connectionRequestInfo);
227                    return c;
228                } catch (JMSException e) {
229                    throw new ResourceException(e);
230                }
231            }
232        }
233        return null;
234    }
235
236    /**
237     * @see javax.resource.spi.ManagedConnectionFactory#setLogWriter(java.io.PrintWriter)
238     */
239    @Override
240    public void setLogWriter(PrintWriter aLogWriter) throws ResourceException {
241        if (log.isTraceEnabled()) {
242            log.trace("setting log writer [" + aLogWriter + "]");
243        }
244        this.logWriter = aLogWriter;
245    }
246
247    /**
248     * @see javax.resource.spi.ManagedConnectionFactory#getLogWriter()
249     */
250    @Override
251    public PrintWriter getLogWriter() throws ResourceException {
252        if (log.isTraceEnabled()) {
253            log.trace("getting log writer [" + logWriter + "]");
254        }
255        return logWriter;
256    }
257}