/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI licenses this file to you 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.openengsb.core.edbi.jdbc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.openengsb.core.api.model.OpenEngSBModel;
import org.openengsb.core.edbi.api.Index;
import org.openengsb.core.edbi.api.IndexField;
import org.openengsb.core.edbi.api.NameTranslator;
import org.openengsb.core.edbi.jdbc.api.NoSuchTableException;
import org.openengsb.core.edbi.jdbc.api.TableEngine;
import org.openengsb.core.edbi.jdbc.api.TableExistsException;
import org.openengsb.core.edbi.jdbc.api.TableFactory;
import org.openengsb.core.edbi.jdbc.api.TypeMap;
import org.openengsb.core.edbi.jdbc.operation.DeleteOperation;
import org.openengsb.core.edbi.jdbc.operation.IndexOperation;
import org.openengsb.core.edbi.jdbc.operation.InsertOperation;
import org.openengsb.core.edbi.jdbc.operation.Operation;
import org.openengsb.core.edbi.jdbc.operation.OperationExecutor;
import org.openengsb.core.edbi.jdbc.operation.UpdateOperation;
import org.openengsb.core.edbi.jdbc.sql.Table;
import org.openengsb.core.edbi.jdbc.sql.TableElementCompiler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* AbstractTableEngine
*/
public abstract class AbstractTableEngine extends JdbcService implements TableEngine, OperationExecutor {
private static final Logger LOG = LoggerFactory.getLogger(AbstractTableEngine.class);
private TypeMap typeMap;
private NameTranslator<Index<?>> tableNameTranslator;
private NameTranslator<IndexField<?>> columnNameTranslator;
private Map<JdbcIndex<?>, Table> registry;
protected AbstractTableEngine(DataSource dataSource, TypeMap typeMap, NameTranslator<Index<?>> tableNameTranslator,
NameTranslator<IndexField<?>> columnNameTranslator) {
super(dataSource);
this.typeMap = typeMap;
this.tableNameTranslator = tableNameTranslator;
this.columnNameTranslator = columnNameTranslator;
this.registry = new HashMap<>();
}
@Override
public boolean exists(JdbcIndex<?> index) {
if (registry.containsKey(index)) {
return true;
}
String tableName = getTableNameTranslator().translate(index);
// TODO: sql independence
return count("`INFORMATION_SCHEMA`.`TABLES`", "TABLE_SCHEMA = 'PUBLIC' AND TABLE_NAME = ?", tableName) > 0;
}
@Override
public Table get(JdbcIndex<?> index) {
if (!exists(index)) {
throw new NoSuchTableException("Table for index " + index.getName() + " does not exist");
}
Table table = registry.get(index);
if (table == null) {
table = getTableFactory().create(index); // TODO: proper load function
registry.put(index, table);
}
return table;
}
@Override
public Table create(JdbcIndex<?> index) {
Table table = getTableFactory().create(index);
if (exists(index)) {
throw new TableExistsException("Table for index " + index.getName() + " exists");
}
// TODO: sql independence
String sql =
String.format("CREATE TABLE `%s` ( %s );", table.getName(), new TableElementCompiler(table).toSql());
LOG.info("Creating table for Index {}. SQL is: {}", index.getName(), sql);
jdbc().execute(sql);
registry.put(index, table);
return table;
}
@Override
public void drop(JdbcIndex<?> index) {
if (!exists(index)) {
throw new NoSuchTableException("Table for index " + index.getName() + " does not exist");
}
String tableName = getTableNameTranslator().translate(index);
if (tableName == null || tableName.isEmpty()) {
throw new NoSuchTableException("Table name for index " + index + " could not be resolved. Can not drop.");
}
jdbc().update("DROP TABLE " + tableName);
registry.remove(index);
}
@Override
public void execute(Operation operation) {
operation.executeWith(this);
}
@Override
public void execute(InsertOperation operation) {
throw new UnsupportedOperationException();
}
@Override
public void execute(UpdateOperation operation) {
throw new UnsupportedOperationException();
}
@Override
public void execute(DeleteOperation operation) {
throw new UnsupportedOperationException();
}
protected void execute(InsertOperation operation, IndexRecordCallback callback) {
Table table = get(operation.getIndex());
insert(table, collectRecords(operation, callback));
}
protected void execute(UpdateOperation operation, IndexRecordCallback callback) {
Table table = get(operation.getIndex());
update(table, collectRecords(operation, callback));
}
protected List<IndexRecord> collectRecords(IndexOperation operation, IndexRecordCallback callback) {
JdbcIndex<?> index = operation.getIndex();
List<OpenEngSBModel> models = operation.getModels();
List<IndexRecord> records = new ArrayList<>(models.size());
for (OpenEngSBModel model : models) {
IndexRecord record = new IndexRecord(index, model);
if (callback != null) {
callback.call(record);
}
records.add(record);
}
return records;
}
protected abstract TableFactory getTableFactory();
protected Map<JdbcIndex<?>, Table> getRegistry() {
return registry;
}
public TypeMap getTypeMap() {
return typeMap;
}
public void setTypeMap(TypeMap typeMap) {
this.typeMap = typeMap;
}
public NameTranslator<Index<?>> getTableNameTranslator() {
return tableNameTranslator;
}
public void setTableNameTranslator(NameTranslator<Index<?>> tableNameTranslator) {
this.tableNameTranslator = tableNameTranslator;
}
public NameTranslator<IndexField<?>> getColumnNameTranslator() {
return columnNameTranslator;
}
public void setColumnNameTranslator(NameTranslator<IndexField<?>> columnNameTranslator) {
this.columnNameTranslator = columnNameTranslator;
}
}