001/*
002 * (C) Copyright 2016 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
017package org.nuxeo.runtime.jtajca;
018
019import javax.transaction.TransactionManager;
020
021import org.apache.geronimo.connector.outbound.AbstractConnectionManager;
022import org.apache.geronimo.connector.outbound.ConnectionHandleInterceptor;
023import org.apache.geronimo.connector.outbound.ConnectionInterceptor;
024import org.apache.geronimo.connector.outbound.ConnectionTrackingInterceptor;
025import org.apache.geronimo.connector.outbound.GenericConnectionManager;
026import org.apache.geronimo.connector.outbound.MCFConnectionInterceptor;
027import org.apache.geronimo.connector.outbound.SubjectInterceptor;
028import org.apache.geronimo.connector.outbound.SubjectSource;
029import org.apache.geronimo.connector.outbound.TCCLInterceptor;
030import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PartitionedPool;
031import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PoolingSupport;
032import org.apache.geronimo.connector.outbound.connectionmanagerconfig.TransactionSupport;
033import org.apache.geronimo.connector.outbound.connectiontracking.ConnectionTracker;
034import org.apache.geronimo.transaction.manager.RecoverableTransactionManager;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038/**
039 * Setups a connection according to the pooling attributes, mainly duplicated
040 * from {@link GenericConnectionManager} for injecting a connection validation
041 * interceptor.
042 *
043 * @since 8.3
044 */
045public class NuxeoConnectionManager extends AbstractConnectionManager {
046    private static final long serialVersionUID = 1L;
047    protected static final Logger log = LoggerFactory.getLogger(NuxeoConnectionManager.class);
048
049    public NuxeoConnectionManager(NuxeoValidationSupport validationSupport,
050            TransactionSupport transactionSupport,
051            PoolingSupport pooling,
052            SubjectSource subjectSource,
053            ConnectionTracker connectionTracker,
054            RecoverableTransactionManager transactionManager,
055            String name,
056            ClassLoader classLoader) {
057        super(new InterceptorsImpl(validationSupport, transactionSupport, pooling, subjectSource, name, connectionTracker, transactionManager,
058                classLoader),
059                transactionManager, name);
060    }
061
062    static class InterceptorsImpl implements AbstractConnectionManager.Interceptors {
063
064        private final ConnectionInterceptor stack;
065        private final ConnectionInterceptor recoveryStack;
066        private final PoolingSupport poolingSupport;
067
068        /**
069         * Order of constructed interceptors:
070         * <p/>
071         * ConnectionTrackingInterceptor (connectionTracker != null)
072         * TCCLInterceptor ConnectionHandleInterceptor
073         * ValidationHandleInterceptor TransactionCachingInterceptor
074         * (useTransactions & useTransactionCaching)
075         * TransactionEnlistingInterceptor (useTransactions) SubjectInterceptor
076         * (realmBridge != null) SinglePoolConnectionInterceptor or
077         * MultiPoolConnectionInterceptor LocalXAResourceInsertionInterceptor or
078         * XAResourceInsertionInterceptor (useTransactions (&localTransactions))
079         * MCFConnectionInterceptor
080         */
081        public InterceptorsImpl(NuxeoValidationSupport validationSupport, TransactionSupport transactionSupport,
082                PoolingSupport pooling,
083                SubjectSource subjectSource,
084                String name,
085                ConnectionTracker connectionTracker,
086                TransactionManager transactionManager,
087                ClassLoader classLoader) {
088            // check for consistency between attributes
089            if (subjectSource == null && pooling instanceof PartitionedPool && ((PartitionedPool) pooling).isPartitionBySubject()) {
090                throw new IllegalStateException("To use Subject in pooling, you need a SecurityDomain");
091            }
092
093            // Set up the interceptor stack
094            MCFConnectionInterceptor tail = new MCFConnectionInterceptor();
095            ConnectionInterceptor stack = tail;
096
097            stack = transactionSupport.addXAResourceInsertionInterceptor(stack, name);
098            stack = pooling.addPoolingInterceptors(stack);
099            if (log.isTraceEnabled()) {
100                log.trace("Connection Manager " + name + " installed pool " + stack);
101            }
102
103            poolingSupport = pooling;
104            stack = transactionSupport.addTransactionInterceptors(stack, transactionManager);
105
106            if (subjectSource != null) {
107                stack = new SubjectInterceptor(stack, subjectSource);
108            }
109
110            if (transactionSupport.isRecoverable()) {
111                recoveryStack = new TCCLInterceptor(stack, classLoader);
112            } else {
113                recoveryStack = null;
114            }
115
116            stack = new ConnectionHandleInterceptor(stack);
117            stack = validationSupport.addTransactionInterceptor(stack);
118            stack = new TCCLInterceptor(stack, classLoader);
119            if (connectionTracker != null) {
120                stack = new ConnectionTrackingInterceptor(stack,
121                        name,
122                        connectionTracker);
123            }
124            tail.setStack(stack);
125            this.stack = stack;
126            if (log.isDebugEnabled()) {
127                StringBuilder s = new StringBuilder("ConnectionManager Interceptor stack;\n");
128                stack.info(s);
129                log.debug(s.toString());
130            }
131        }
132
133        @Override
134        public ConnectionInterceptor getStack() {
135            return stack;
136        }
137
138        @Override
139        public ConnectionInterceptor getRecoveryStack() {
140            return recoveryStack;
141        }
142
143        @Override
144        public PoolingSupport getPoolingAttributes() {
145            return poolingSupport;
146        }
147
148    }
149
150    @Override
151    public void doStop() throws Exception {
152        if (getConnectionCount() < getPartitionMinSize()) {
153            Thread.sleep(10); // wait for filling tasks completion
154        }
155        super.doStop();
156    }
157
158}