001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019
020package org.nuxeo.ecm.core.storage.sql.ra;
021
022import java.util.Calendar;
023
024import javax.naming.Reference;
025import javax.resource.ResourceException;
026import javax.resource.cci.ConnectionSpec;
027import javax.resource.cci.RecordFactory;
028import javax.resource.cci.ResourceAdapterMetaData;
029import javax.resource.spi.ConnectionManager;
030
031import org.apache.commons.logging.LogFactory;
032import org.nuxeo.ecm.core.api.NuxeoException;
033import org.nuxeo.ecm.core.storage.sql.Repository;
034import org.nuxeo.ecm.core.storage.sql.Session;
035import org.nuxeo.ecm.core.storage.sql.coremodel.SQLSession;
036import org.nuxeo.runtime.jtajca.NuxeoConnectionManagerConfiguration;
037import org.nuxeo.runtime.jtajca.NuxeoContainer;
038import org.nuxeo.runtime.jtajca.NuxeoContainer.ConnectionManagerWrapper;
039
040/**
041 * The connection factory delegates connection requests to the application server {@link ConnectionManager}.
042 * <p>
043 * An instance of this class is returned to the application when a JNDI lookup is done.
044 *
045 * @author Florent Guillaume
046 */
047public class ConnectionFactoryImpl implements Repository, org.nuxeo.ecm.core.model.Repository {
048
049    private static final long serialVersionUID = 1L;
050
051    private final ManagedConnectionFactoryImpl managedConnectionFactory;
052
053    private final ConnectionManager connectionManager;
054
055    private final String name;
056
057    private Reference reference;
058
059    /**
060     * This is {@code true} if the connectionManager comes from an application server, or {@code false} if the
061     * {@link ConnectionFactoryImpl} was constructed by application code and passed our manual
062     * {@link ConnectionManagerImpl}.
063     */
064    @SuppressWarnings("unused")
065    private final boolean managed;
066
067    public ConnectionFactoryImpl(ManagedConnectionFactoryImpl managedConnectionFactory,
068            ConnectionManager connectionManager) {
069        this.managedConnectionFactory = managedConnectionFactory;
070        this.connectionManager = connectionManager;
071        managed = !(connectionManager instanceof ConnectionManagerImpl);
072        name = managedConnectionFactory.getName();
073    }
074
075    // NXP 3992 -- exposed this for clean shutdown on cluster
076    public ManagedConnectionFactoryImpl getManagedConnectionFactory() {
077        return managedConnectionFactory;
078    }
079
080    /*
081     * ----- javax.resource.cci.ConnectionFactory -----
082     */
083
084    /**
085     * Gets a new connection.
086     *
087     * @param connectionSpec the connection spec (unused)
088     * @return the connection
089     */
090    @Override
091    public Session getConnection(ConnectionSpec connectionSpec) {
092        return getConnection();
093    }
094
095    /**
096     * Gets a new connection.
097     *
098     * @return the connection
099     */
100    @Override
101    public Session getConnection() {
102        try {
103            return (Session) connectionManager.allocateConnection(managedConnectionFactory, null);
104        } catch (ResourceException e) {
105            String msg = e.getMessage();
106            if (msg != null && msg.startsWith("No ManagedConnections available")) {
107                String err = "Connection pool is fully used";
108                if (connectionManager instanceof ConnectionManagerWrapper) {
109                    ConnectionManagerWrapper cmw = (ConnectionManagerWrapper) connectionManager;
110                    NuxeoConnectionManagerConfiguration config = cmw.getConfiguration();
111                    err = err + ", consider increasing " + "nuxeo.vcs.blocking-timeout-millis (currently "
112                            + config.getBlockingTimeoutMillis() + ") or " + "nuxeo.vcs.max-pool-size (currently "
113                            + config.getMaxPoolSize() + ")";
114                }
115                throw new NuxeoException(err, e);
116            }
117            throw new NuxeoException(e);
118        }
119    }
120
121    @Override
122    public ResourceAdapterMetaData getMetaData() throws ResourceException {
123        // TODO Auto-generated method stub
124        throw new UnsupportedOperationException("Not implemented");
125    }
126
127    @Override
128    public RecordFactory getRecordFactory() throws ResourceException {
129        throw new UnsupportedOperationException("Not implemented");
130    }
131
132    /*
133     * ----- javax.naming.Referenceable -----
134     */
135
136    @Override
137    public Reference getReference() {
138        return reference;
139    }
140
141    @Override
142    public void setReference(Reference reference) {
143        this.reference = reference;
144    }
145
146    /*
147     * ----- Repository -----
148     */
149
150    @Override
151    public void close() {
152        throw new UnsupportedOperationException("Not implemented");
153    }
154
155    /*
156     * ----- org.nuxeo.ecm.core.model.Repository -----
157     */
158
159    @Override
160    public String getName() {
161        return name;
162    }
163
164    @Override
165    public org.nuxeo.ecm.core.model.Session getSession() {
166        return new SQLSession(getConnection(), this);
167    }
168
169    @Override
170    public void shutdown() {
171        try {
172            NuxeoContainer.disposeConnectionManager(connectionManager);
173        } catch (RuntimeException e) {
174            LogFactory.getLog(ConnectionFactoryImpl.class).warn("cannot dispose connection manager of " + name);
175        }
176        try {
177            managedConnectionFactory.shutdown();
178        } catch (NuxeoException e) {
179            LogFactory.getLog(ConnectionFactoryImpl.class).warn("cannot shutdown connection factory  " + name);
180        }
181    }
182
183    /*
184     * ----- org.nuxeo.ecm.core.model.RepositoryManagement -----
185     */
186
187    @Override
188    public int getActiveSessionsCount() {
189        return managedConnectionFactory.getActiveSessionsCount();
190    }
191
192    @Override
193    public long getCacheSize() {
194        return managedConnectionFactory.getCacheSize();
195    }
196
197    @Override
198    public long getCachePristineSize() {
199        return managedConnectionFactory.getCachePristineSize();
200    }
201
202    @Override
203    public long getCacheSelectionSize() {
204        return managedConnectionFactory.getCacheSelectionSize();
205    }
206
207    @Override
208    public int clearCaches() {
209        return managedConnectionFactory.clearCaches();
210    }
211
212    @Override
213    public void processClusterInvalidationsNext() {
214        managedConnectionFactory.processClusterInvalidationsNext();
215    }
216
217    @Override
218    public void markReferencedBinaries() {
219        managedConnectionFactory.markReferencedBinaries();
220    }
221
222    @Override
223    public int cleanupDeletedDocuments(int max, Calendar beforeTime) {
224        return managedConnectionFactory.cleanupDeletedDocuments(max, beforeTime);
225    }
226
227}