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;
036import org.slf4j.LoggerFactory;
037
038/**
039 * @version $Revisio n$ TODO: Must override equals and hashCode (JCA spec 16.4)
040 * @org.apache.xbean.XBean element="managedConnectionFactory"
041 */
042public class ActiveMQManagedConnectionFactory extends ActiveMQConnectionSupport
043        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    public void setResourceAdapter(ResourceAdapter adapter) throws ResourceException {
052        if (!(adapter instanceof MessageResourceAdapter)) {
053            throw new ResourceException("ResourceAdapter is not of type: " + MessageResourceAdapter.class.getName());
054        }
055        else
056        {
057            if ( log.isDebugEnabled() ) {
058                log.debug(this + ", copying standard ResourceAdapter configuration properties");
059            }
060
061            ActiveMQConnectionRequestInfo baseInfo = ((MessageResourceAdapter) adapter).getInfo().copy();
062            if (getClientid() == null) {
063                setClientid(baseInfo.getClientid());
064            }
065            if (getPassword() == null) {
066                setPassword(baseInfo.getPassword());
067            }
068            if (getServerUrl() == null) {
069                setServerUrl(baseInfo.getServerUrl());
070            }
071            if (getUseInboundSession() == null) {
072                setUseInboundSession(baseInfo.getUseInboundSession());
073            }
074            if (getUseSessionArgs() == null) {
075                setUseSessionArgs(baseInfo.isUseSessionArgs());
076            }
077            if (getUserName() == null) {
078                setUserName(baseInfo.getUserName());
079            }
080            if (getDurableTopicPrefetch() != null) {
081                setDurableTopicPrefetch(baseInfo.getDurableTopicPrefetch());
082            }
083            if (getOptimizeDurableTopicPrefetch() != null) {
084                setOptimizeDurableTopicPrefetch(baseInfo.getOptimizeDurableTopicPrefetch());
085            }
086            if (getQueuePrefetch() != null) {
087                setQueuePrefetch(baseInfo.getQueuePrefetch());
088            }
089            if (getQueueBrowserPrefetch() != null) {
090                setQueueBrowserPrefetch(baseInfo.getQueueBrowserPrefetch());
091            }
092            if (getTopicPrefetch() != null) {
093                setTopicPrefetch(baseInfo.getTopicPrefetch());
094            }
095            if (getInputStreamPrefetch() != null) {
096                setInputStreamPrefetch(baseInfo.getInputStreamPrefetch());
097            }
098        }
099    }
100
101    /**
102     * @see javax.resource.spi.ResourceAdapterAssociation#getResourceAdapter()
103     */
104    public ResourceAdapter getResourceAdapter() {
105        return null;
106    }
107
108    /**
109     * @see java.lang.Object#equals(java.lang.Object)
110     */
111    @Override
112    public boolean equals(Object object) {
113        if (object == null || object.getClass() != ActiveMQManagedConnectionFactory.class) {
114            return false;
115        }
116        return ((ActiveMQManagedConnectionFactory)object).getInfo().equals(getInfo());
117    }
118
119    /**
120     * @see java.lang.Object#hashCode()
121     */
122    @Override
123    public int hashCode() {
124        return getInfo().hashCode();
125    }
126
127    /**
128     * Writes this factory during serialization along with the superclass' <i>info</i> property.
129     * This needs to be done manually since the superclass is not serializable itself.
130     * 
131     * @param out the stream to write object state to
132     * @throws java.io.IOException if the object cannot be serialized
133     */
134    private void writeObject(ObjectOutputStream out) throws IOException {
135        if ( logWriter != null && !(logWriter instanceof Serializable) ) {
136            // if the PrintWriter injected by the application server is not
137            // serializable we just drop the reference and let the application
138            // server re-inject a PrintWriter later (after this factory has been
139            // deserialized again) using the standard setLogWriter() method
140            logWriter = null;
141    }
142        out.defaultWriteObject();
143        out.writeObject(getInfo());
144    }
145
146    /**
147     * Restores this factory along with the superclass' <i>info</i> property.
148     * This needs to be done manually since the superclass is not serializable itself.
149     * 
150     * @param in the stream to read object state from
151     * @throws java.io.IOException if the object state could not be restored
152     * @throws java.lang.ClassNotFoundException if the object state could not be restored
153     */
154    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
155        in.defaultReadObject();
156        setInfo((ActiveMQConnectionRequestInfo) in.readObject());
157        log = LoggerFactory.getLogger(getClass());
158    }
159    
160    /**
161     * @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory(javax.resource.spi.ConnectionManager)
162     */
163    public Object createConnectionFactory(ConnectionManager manager) throws ResourceException {
164        return new ActiveMQConnectionFactory(this, manager, getInfo());
165    }
166
167    /**
168     * This is used when not running in an app server. For now we are creating a
169     * ConnectionFactory that has our SimpleConnectionManager implementation but
170     * it may be a better idea to not support this. The JMS api will have many
171     * quirks the user may not expect when running through the resource adapter.
172     * 
173     * @see javax.resource.spi.ManagedConnectionFactory#createConnectionFactory()
174     */
175    public Object createConnectionFactory() throws ResourceException {
176        return new ActiveMQConnectionFactory(this, new SimpleConnectionManager(), getInfo());
177    }
178
179    /**
180     * @see javax.resource.spi.ManagedConnectionFactory#createManagedConnection(javax.security.auth.Subject,
181     *      javax.resource.spi.ConnectionRequestInfo)
182     */
183    public ManagedConnection createManagedConnection(
184            Subject subject, 
185            ConnectionRequestInfo connectionRequestInfo) throws ResourceException {
186        ActiveMQConnectionRequestInfo amqInfo = getInfo();
187        if ( connectionRequestInfo instanceof ActiveMQConnectionRequestInfo ) {
188            amqInfo = (ActiveMQConnectionRequestInfo) connectionRequestInfo;
189            }
190        try {
191            return new ActiveMQManagedConnection(subject, makeConnection(amqInfo), amqInfo);
192        } catch (JMSException e) {
193            throw new ResourceException("Could not create connection.", e);
194        }
195    }
196
197    /**
198     * @see javax.resource.spi.ManagedConnectionFactory#matchManagedConnections(java.util.Set,
199     *      javax.security.auth.Subject,
200     *      javax.resource.spi.ConnectionRequestInfo)
201     */
202    public ManagedConnection matchManagedConnections(
203            Set connections, 
204            Subject subject, 
205            ConnectionRequestInfo connectionRequestInfo) throws ResourceException {
206        Iterator iterator = connections.iterator();
207        while (iterator.hasNext()) {
208            ActiveMQManagedConnection c = (ActiveMQManagedConnection)iterator.next();
209            if (c.matches(subject, connectionRequestInfo)) {
210                try {
211                    c.associate(subject, (ActiveMQConnectionRequestInfo) connectionRequestInfo);
212                    return c;
213                } catch (JMSException e) {
214                    throw new ResourceException(e);
215                }
216            }
217        }
218        return null;
219    }
220
221    /**
222     * @see javax.resource.spi.ManagedConnectionFactory#setLogWriter(java.io.PrintWriter)
223     */
224    public void setLogWriter(PrintWriter aLogWriter) throws ResourceException {
225        if ( log.isTraceEnabled() ) {
226            log.trace("setting log writer [" + aLogWriter + "]");
227    }
228        this.logWriter = aLogWriter;
229    }
230
231    /**
232     * @see javax.resource.spi.ManagedConnectionFactory#getLogWriter()
233     */
234    public PrintWriter getLogWriter() throws ResourceException {
235        if ( log.isTraceEnabled() ) {
236            log.trace("getting log writer [" + logWriter + "]");
237        }
238        return logWriter;
239    }
240
241    }