001/* 002 * (C) Copyright 2006-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 * Contributors: 017 * Florent Guillaume 018 */ 019 020package org.nuxeo.ecm.core.storage.sql.jdbc; 021 022import java.sql.Connection; 023import java.sql.SQLException; 024 025import javax.naming.NamingException; 026import javax.sql.DataSource; 027 028import org.apache.commons.logging.Log; 029import org.apache.commons.logging.LogFactory; 030import org.nuxeo.ecm.core.api.NuxeoException; 031import org.nuxeo.ecm.core.storage.FulltextDescriptor; 032import org.nuxeo.ecm.core.storage.sql.ClusterInvalidator; 033import org.nuxeo.ecm.core.storage.sql.Mapper; 034import org.nuxeo.ecm.core.storage.sql.Model; 035import org.nuxeo.ecm.core.storage.sql.Model.IdType; 036import org.nuxeo.ecm.core.storage.sql.ModelSetup; 037import org.nuxeo.ecm.core.storage.sql.RepositoryBackend; 038import org.nuxeo.ecm.core.storage.sql.RepositoryDescriptor; 039import org.nuxeo.ecm.core.storage.sql.RepositoryImpl; 040import org.nuxeo.ecm.core.storage.sql.Session.PathResolver; 041import org.nuxeo.ecm.core.storage.sql.jdbc.dialect.Dialect; 042import org.nuxeo.runtime.datasource.ConnectionHelper; 043import org.nuxeo.runtime.datasource.DataSourceHelper; 044import org.nuxeo.runtime.datasource.PooledDataSourceRegistry.PooledDataSource; 045 046/** 047 * JDBC Backend for a repository. 048 */ 049public class JDBCBackend implements RepositoryBackend { 050 051 private static final Log log = LogFactory.getLog(JDBCBackend.class); 052 053 private RepositoryImpl repository; 054 055 private Model model; 056 057 private SQLInfo sqlInfo; 058 059 private ClusterInvalidator clusterInvalidator; 060 061 private boolean isPooledDataSource; 062 063 @Override 064 public Model initialize(RepositoryImpl repository) { 065 this.repository = repository; 066 RepositoryDescriptor repositoryDescriptor = repository.getRepositoryDescriptor(); 067 String dataSourceName = JDBCConnection.getDataSourceName(repositoryDescriptor.name); 068 069 // check datasource 070 try { 071 DataSource ds = DataSourceHelper.getDataSource(dataSourceName); 072 if (ds instanceof PooledDataSource) { 073 isPooledDataSource = true; 074 } 075 } catch (NamingException cause) { 076 throw new NuxeoException("Cannot acquire datasource: " + dataSourceName, cause); 077 } 078 079 // check connection and get dialect 080 Dialect dialect; 081 try (Connection connection = ConnectionHelper.getConnection(dataSourceName)) { 082 dialect = Dialect.createDialect(connection, repositoryDescriptor); 083 } catch (SQLException cause) { 084 throw new NuxeoException("Cannot get connection from datasource: " + dataSourceName, cause); 085 } 086 087 // model setup 088 ModelSetup modelSetup = new ModelSetup(); 089 modelSetup.materializeFulltextSyntheticColumn = dialect.getMaterializeFulltextSyntheticColumn(); 090 modelSetup.supportsArrayColumns = dialect.supportsArrayColumns(); 091 switch (dialect.getIdType()) { 092 case VARCHAR: 093 case UUID: 094 modelSetup.idType = IdType.STRING; 095 break; 096 case SEQUENCE: 097 modelSetup.idType = IdType.LONG; 098 break; 099 default: 100 throw new AssertionError(dialect.getIdType().toString()); 101 } 102 modelSetup.repositoryDescriptor = repositoryDescriptor; 103 104 // Model and SQLInfo 105 model = new Model(modelSetup); 106 sqlInfo = new SQLInfo(model, dialect); 107 108 // DDL mode 109 String ddlMode = repositoryDescriptor.getDDLMode(); 110 if (ddlMode == null) { 111 // compat 112 ddlMode = repositoryDescriptor.getNoDDL() ? RepositoryDescriptor.DDL_MODE_IGNORE 113 : RepositoryDescriptor.DDL_MODE_EXECUTE; 114 } 115 116 // create database 117 if (ddlMode.equals(RepositoryDescriptor.DDL_MODE_IGNORE)) { 118 log.info("Skipping database creation"); 119 } else { 120 Mapper mapper = newMapper(null, false); 121 try { 122 mapper.createDatabase(ddlMode); 123 } finally { 124 mapper.close(); 125 } 126 } 127 if (log.isDebugEnabled()) { 128 FulltextDescriptor fulltextDescriptor = repositoryDescriptor.getFulltextDescriptor(); 129 log.debug(String.format("Database ready, fulltext: disabled=%b searchDisabled=%b.", 130 fulltextDescriptor.getFulltextDisabled(), fulltextDescriptor.getFulltextSearchDisabled())); 131 } 132 133 return model; 134 } 135 136 @Override 137 public void setClusterInvalidator(ClusterInvalidator clusterInvalidator) { 138 this.clusterInvalidator = clusterInvalidator; 139 } 140 141 @Override 142 public Mapper newMapper(PathResolver pathResolver, boolean useInvalidations) { 143 boolean noSharing = !useInvalidations; 144 ClusterInvalidator cnh = useInvalidations ? clusterInvalidator : null; 145 Mapper mapper = new JDBCMapper(model, pathResolver, sqlInfo, cnh, repository); 146 if (isPooledDataSource) { 147 mapper = JDBCMapperConnector.newConnector(mapper, noSharing); 148 } else { 149 mapper.connect(false); 150 } 151 return mapper; 152 } 153 154 @Override 155 public void shutdown() { 156 if (clusterInvalidator != null) { 157 clusterInvalidator.close(); 158 } 159 } 160 161}