/* * Copyright (c) 2010, Stanislav Muhametsin. All Rights Reserved. * Copyright (c) 2010, Paul Merlin. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.qi4j.entitystore.sql.internal; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import org.qi4j.api.configuration.Configuration; import org.qi4j.api.injection.scope.Service; import org.qi4j.api.injection.scope.Structure; import org.qi4j.api.injection.scope.This; import org.qi4j.api.service.ServiceComposite; import org.qi4j.api.structure.Application; import org.qi4j.api.structure.Application.Mode; import org.qi4j.api.util.NullArgumentException; import org.qi4j.library.sql.common.SQLConfiguration; import org.qi4j.library.sql.common.SQLUtil; import org.qi4j.library.sql.ds.DataSourceService; import org.qi4j.spi.entitystore.EntityStoreException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sql.generation.api.vendor.SQLVendor; @SuppressWarnings("ProtectedField") public abstract class DatabaseSQLServiceCoreMixin implements DatabaseSQLService { private static final Logger LOGGER = LoggerFactory.getLogger( DatabaseSQLServiceCoreMixin.class ); @Structure private Application application; @Service private DataSourceService dataSourceService; @This private DatabaseSQLServiceState state; @This protected DatabaseSQLServiceSpi spi; @This private DatabaseSQLStringsBuilder sqlStrings; @This private ServiceComposite meAsService; @This private Configuration<SQLConfiguration> configuration; public Connection getConnection() throws SQLException { return dataSourceService.getDataSource().getConnection(); } protected String getConfiguredSchemaName( String defaultSchemaName ) { String result = this.configuration.configuration().schemaName().get(); if( result == null ) { NullArgumentException.validateNotNull( "default schema name", defaultSchemaName ); result = defaultSchemaName; } return result; } public void startDatabase() throws Exception { Connection connection = getConnection(); String schema = this.getConfiguredSchemaName( SQLs.DEFAULT_SCHEMA_NAME ); if( schema == null ) { throw new EntityStoreException( "Schema name must not be null." ); } else { state.schemaName().set( schema ); state.vendor().set( this.meAsService.metaInfo( SQLVendor.class ) ); this.sqlStrings.init(); if( !spi.schemaExists( connection ) ) { Statement stmt = null; try { stmt = connection.createStatement(); for( String sql : sqlStrings.buildSQLForSchemaCreation() ) { stmt.execute( sql ); } } finally { SQLUtil.closeQuietly( stmt ); } LOGGER.trace( "Schema {} created", schema ); } if( !spi.tableExists( connection ) ) { Statement stmt = null; try { stmt = connection.createStatement(); for( String sql : sqlStrings.buildSQLForTableCreation() ) { stmt.execute( sql ); } for( String sql : sqlStrings.buildSQLForIndexCreation() ) { stmt.execute( sql ); } } finally { SQLUtil.closeQuietly( stmt ); } LOGGER.trace( "Table {} created", SQLs.TABLE_NAME ); } connection.setAutoCommit( false ); state.pkLock().set( new Object() ); synchronized( state.pkLock().get() ) { state.nextEntityPK().set( spi.readNextEntityPK( connection ) ); } } SQLUtil.closeQuietly( connection ); } public void stopDatabase() throws Exception { if( Mode.production == application.mode() ) { // NOOP } } public Long newPKForEntity() { if( state.pkLock().get() == null || state.nextEntityPK().get() == null ) { throw new EntityStoreException( "New PK asked for entity, but database service has not been initialized properly." ); } synchronized( state.pkLock().get() ) { Long result = state.nextEntityPK().get(); Long next = result + 1; state.nextEntityPK().set( next ); return result; } } }