001    /*
002     * JBoss DNA (http://www.jboss.org/dna)
003     * See the COPYRIGHT.txt file distributed with this work for information
004     * regarding copyright ownership.  Some portions may be licensed
005     * to Red Hat, Inc. under one or more contributor license agreements.
006     * See the AUTHORS.txt file in the distribution for a full listing of 
007     * individual contributors. 
008     *
009     * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
010     * is licensed to you under the terms of the GNU Lesser General Public License as
011     * published by the Free Software Foundation; either version 2.1 of
012     * the License, or (at your option) any later version.
013     *
014     * JBoss DNA is distributed in the hope that it will be useful,
015     * but WITHOUT ANY WARRANTY; without even the implied warranty of
016     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017     * Lesser General Public License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this software; if not, write to the Free
021     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
022     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
023     */
024    package org.jboss.dna.connector.jdbc;
025    
026    import java.sql.Connection;
027    import java.sql.SQLException;
028    import java.util.UUID;
029    import java.util.concurrent.CopyOnWriteArrayList;
030    import java.util.concurrent.TimeUnit;
031    import javax.transaction.xa.XAResource;
032    import javax.sql.XAConnection;
033    
034    import org.jboss.dna.common.util.Logger;
035    import org.jboss.dna.graph.ExecutionContext;
036    import org.jboss.dna.graph.cache.CachePolicy;
037    import org.jboss.dna.graph.connector.RepositoryConnection;
038    import org.jboss.dna.graph.connector.RepositorySourceException;
039    import org.jboss.dna.graph.connector.RepositorySourceListener;
040    import org.jboss.dna.graph.request.Request;
041    import org.jboss.dna.graph.request.processor.RequestProcessor;
042    
043    /**
044     * JDBC connection wrapper
045     * 
046     * @author <a href="mailto:litsenko_sergey@yahoo.com">Sergiy Litsenko</a>
047     */
048    public class JdbcConnection implements RepositoryConnection {
049        /**
050         * Logging for this instance
051         */
052        protected Logger log = Logger.getLogger(getClass());
053    
054        private final String name;
055        private final CachePolicy cachePolicy;
056        private final CopyOnWriteArrayList<RepositorySourceListener> listeners = new CopyOnWriteArrayList<RepositorySourceListener>();
057        private final Connection connection;
058        private final UUID rootNodeUuid;
059    
060        /*package*/JdbcConnection( String sourceName,
061                                   CachePolicy cachePolicy,
062                                   Connection connection,
063                                   UUID rootNodeUuid) {
064            assert sourceName != null;
065            assert connection != null;
066            assert rootNodeUuid != null;
067            this.name = sourceName;
068            this.cachePolicy = cachePolicy; // may be null
069            this.connection = connection;
070            this.rootNodeUuid = rootNodeUuid;
071        }
072    
073        /**
074         * {@inheritDoc}
075         * 
076         * @see org.jboss.dna.graph.connector.RepositoryConnection#getSourceName()
077         */
078        public String getSourceName() {
079            return name;
080        }
081    
082        /**
083         * {@inheritDoc}
084         * 
085         * @see org.jboss.dna.graph.connector.RepositoryConnection#setListener(org.jboss.dna.graph.connector.RepositorySourceListener)
086         */
087        public void setListener( RepositorySourceListener listener ) {
088            if (listener != null) {
089                listeners.addIfAbsent(listener);
090            }
091        }
092    
093        /**
094         * {@inheritDoc}
095         * 
096         * @see org.jboss.dna.graph.connector.RepositoryConnection#getDefaultCachePolicy()
097         */
098        public CachePolicy getDefaultCachePolicy() {
099            return cachePolicy;
100        }
101    
102        /**
103         * {@inheritDoc}
104         * 
105         * @see org.jboss.dna.graph.connector.RepositoryConnection#getXAResource()
106         */
107        public XAResource getXAResource() {
108            // if implemented by JDBC driver
109            if (connection instanceof XAConnection) {
110                try {
111                    return ((XAConnection)connection).getXAResource();
112                } catch (SQLException e) {
113                    // handle an exception silently so far and write it to the log 
114                    log.error(e, JdbcMetadataI18n.unableToGetXAResource, getSourceName());
115                    return null;
116                }
117            }
118            // default
119            return null;    
120        }
121    
122        /**
123         * {@inheritDoc}
124         * 
125         * @see org.jboss.dna.graph.connector.RepositoryConnection#ping(long, java.util.concurrent.TimeUnit)
126         */
127        public boolean ping( long time,
128                             TimeUnit unit ) {
129            try {
130                // JDBC 4 has a method to check validity of a connection (connection.isValid(timeout))
131                // but many drivers didn't get updated with latest spec
132                return connection != null && ! connection.isClosed();
133            } catch (SQLException e) {
134                // debug
135                if (log.isDebugEnabled()) {
136                    log.debug(e, "{0}: Unable to check database connection due to error.", getSourceName());
137                }
138                return false;
139            }
140        }
141    
142        /**
143         * {@inheritDoc}
144         * 
145         * @see org.jboss.dna.graph.connector.RepositoryConnection#execute(org.jboss.dna.graph.ExecutionContext,
146         *      org.jboss.dna.graph.request.Request)
147         */
148        public void execute( ExecutionContext context,
149                             Request request ) throws RepositorySourceException {
150            // create processor and delegate handling 
151            RequestProcessor proc = new JdbcRequestProcesor(getSourceName(),context, connection, rootNodeUuid);
152            try {
153                proc.process(request);
154            } finally {
155                proc.close();
156            }
157        }
158    
159        /**
160         * {@inheritDoc}
161         * 
162         * @see org.jboss.dna.graph.connector.RepositoryConnection#close()
163         */
164        public void close() {
165            try {
166                // release the JDBC connection resource
167                if (connection != null && ! connection.isClosed()) {
168                    connection.close();
169                }
170            } catch (Exception e) {
171                // handle exception silently so far
172                if (log.isDebugEnabled()) {
173                    log.debug(e, "{0}: Unable to close database connection due to error.", getSourceName());
174                }
175            }
176        }
177    
178    }