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