package org.aplikator.server.persistence.empiredb;
import javax.imageio.ImageIO;
import javax.sql.DataSource;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.StringReader;
import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.empire.data.DataMode;
import org.apache.empire.data.DataType;
import org.apache.empire.db.*;
import org.apache.empire.db.exceptions.EmpireSQLException;
import org.apache.empire.db.expr.column.DBAliasExpr;
import org.apache.empire.db.expr.compare.DBCompareAndOrExpr;
import org.apache.empire.db.expr.compare.DBCompareColExpr;
import org.apache.empire.db.expr.compare.DBCompareExpr;
import org.apache.empire.db.expr.join.DBJoinExpr;
import org.apache.empire.db.h2.DBDatabaseDriverH2;
import org.apache.empire.db.hsql.DBDatabaseDriverHSql;
import org.apache.empire.db.mysql.DBDatabaseDriverMySQL;
import org.apache.empire.db.postgresql.DBDatabaseDriverPostgreSQL;
import org.apache.empire.db.sqlserver.DBDatabaseDriverMSSQL;
import org.apache.empire.exceptions.NotImplementedException;
import org.apache.jackrabbit.core.data.DataIdentifier;
import org.apache.jackrabbit.core.data.DataRecord;
import org.apache.jackrabbit.core.data.DataStoreException;
import org.apache.jackrabbit.core.data.FileDataStore;
import org.aplikator.client.local.widgets.BinaryFieldWidget;
import org.aplikator.client.shared.data.PrimaryKey;
import org.aplikator.client.shared.data.RecordDTO;
import org.aplikator.server.Configurator;
import org.aplikator.server.DescriptorRegistry;
import org.aplikator.server.ImageResizer;
import org.aplikator.server.data.BinaryData;
import org.aplikator.server.data.Context;
import org.aplikator.server.data.PersisterTriggers;
import org.aplikator.server.data.Record;
import org.aplikator.server.descriptor.BinaryProperty;
import org.aplikator.server.descriptor.Collection;
import org.aplikator.server.descriptor.Entity;
import org.aplikator.server.descriptor.JoinableProperty;
import org.aplikator.server.descriptor.Property;
import org.aplikator.server.descriptor.Reference;
import org.aplikator.server.descriptor.SortItem;
import org.aplikator.server.descriptor.View;
import org.aplikator.server.persistence.Persister;
import org.aplikator.server.persistence.Transaction;
import org.aplikator.server.persistence.empiredb.oracle.EmpireDriverOracle;
import org.aplikator.server.persistence.tempstore.TempstoreFactory;
import org.aplikator.server.query.BooleanQueryExpression;
import org.aplikator.server.query.BooleanQueryOperator;
import org.aplikator.server.query.QueryExpression;
import org.aplikator.server.query.TermQueryExpression;
import org.aplikator.server.query.TermQueryOperator;
import org.aplikator.utils.IOUtils;
import org.aplikator.utils.PDFLoader;
import com.google.common.io.ByteStreams;
import com.zaxxer.hikari.HikariDataSource;
public class EmpireDbPersister implements Persister {
private static final Logger LOG = Logger.getLogger(EmpireDbPersister.class.getName());
private static final String referenceIndexSuffix = "_REFIDX";
private final DBDatabase db = new EmpireDatabase();
private final Map<Entity, DBTable> tables = new HashMap<Entity, DBTable>();
private final Map<Property<? extends Serializable>, DBColumnExpr> columns = new HashMap<Property<? extends Serializable>, DBColumnExpr>();
private final Map<BinaryProperty, BlobColumns> blobs = new HashMap<BinaryProperty, BlobColumns>();
private DataSource dataSource = null;
private DBDatabaseDriver driver = null;
private boolean oracle_use_NLS_SORT = false;
private String oracle_NLS_SORT = null;
private FileDataStore dataStore = null;
private AtomicBoolean suspendedFlag = new AtomicBoolean();
public EmpireDbPersister() {
initDataSourceProps();
initBinaryDatastore();
initDatasourceAndDriver();
}
@SuppressWarnings("rawtypes")
private static List<Property> getSelectableProperties(Entity entity, View view, Context ctx) {
List<Property> retval = new ArrayList<Property>();
for (Property p : entity.getProperties()) {
if (!(p instanceof Collection)/* && !(p.getType().equals(BinaryData.class)) */ && !p.isVirtual()) {
retval.add(p);
}
}
if (view != null) {
for (Property p : view.getProperties()) {
if (!p.isVirtual()) {
retval.add(p);
}
}
for (Property p : view.getForm(ctx).getProperties()) {
if (!p.isVirtual()) {
retval.add(p);
}
}
}
return retval;
}
private static void checkDBCommand(DBCommand cmd) {
if (cmd.getDatabase() == null) {
LOG.severe("NULL DATABASE");
throw new RuntimeException("NULL DATABASE");
}
if (cmd.getDatabase().getDriver() == null) {
LOG.severe("NULL DRIVER" + cmd.getDatabase().getDriver());
throw new RuntimeException("NULL DRIVER" + cmd.getDatabase().getDriver());
}
}
private void initBinaryDatastore() {
if (Configurator.get().getConfig().getBoolean(Configurator.BINARY_DATASTORE)) {
dataStore = new FileDataStore();
String dsPath = Configurator.get().getConfig().getString(Configurator.BINARY_DATASTORE_HOME);
dataStore.setPath(dsPath);
dataStore.init(null);
}
}
private void initDataSourceProps() {
oracle_use_NLS_SORT = Configurator.get().getConfig().getBoolean(Configurator.USE_ORACLE_NLS_SORT);
oracle_NLS_SORT = Configurator.get().getConfig().getString(Configurator.ORACLE_NLS_SORT);
}
public void registerEntity(Entity entity, String tableName) {
if (tables.containsKey(entity)) {
throw new IllegalStateException("Duplicate entity registration:" + entity + ", " + tableName);
}
DBTable table = new DBTable(tableName, db);
tables.put(entity, table);
}
public void registerPrimaryKey(Entity entity, Property<Integer> property, String primaryKeyName, String sequenceName) {
DBTable table = tables.get(entity);
if (table == null) {
throw new IllegalStateException("Cannot register primaryKey " + property + " - entity " + entity + " is not yet registered.");
}
DBTableColumn primaryKeycolumn = table.addColumn(primaryKeyName, DataType.AUTOINC, 0, true, sequenceName);
table.setPrimaryKey(primaryKeycolumn);
columns.put(property, primaryKeycolumn);
}
public void registerTimestamp(Entity entity, Property<Date> property, String timestampName) {
DBTable table = tables.get(entity);
if (table == null) {
throw new IllegalStateException("Cannot register timestamp " + property + " - entity " + entity + " is not yet registered.");
}
DBTableColumn timestampColumn = table.addColumn(timestampName, DataType.DATETIME, 0, DataMode.AutoGenerated);
timestampColumn.setAttribute(DBColumn.DBCOLATTR_DATETIMEPATTERN, "yyyy-MM-dd HH:mm:ss.SSS");
table.setTimestampColumn(timestampColumn);
columns.put(property, timestampColumn);
}
@SuppressWarnings("unchecked")
public <T extends Serializable> void registerProperty(Entity entity, Property<T> property, String columnName) {
DBTableColumn column = null;
Class<T> type = property.getType();
DBTable table = tables.get(entity);
if (table == null) {
throw new IllegalStateException("Cannot register property " + property + " - entity " + entity + " is not yet registered.");
}
if (type.equals(Boolean.class)) {
column = table.addColumn(columnName, mapType(property), property.getSize(), property.isRequired(), false);
} else if (type.equals(BinaryData.class)) {// TODO check if it should
// use addBlob?
BlobColumns blob = new BlobColumns();
if (dataStore == null) {//store binary data as database blobs
blob.column = table.addColumn(columnName, DataType.BLOB, 0, false);
blob.fullColumn = table.addColumn(columnName + "_FULL", DataType.BLOB, 0, false);
blob.mediumColumn = table.addColumn(columnName + "_MEDIUM", DataType.BLOB, 0, false);
} else {//store binary data in jackrabbit datastore
blob.column = table.addColumn(columnName, DataType.TEXT, 255, false);
blob.fullColumn = table.addColumn(columnName + "_FULL", DataType.TEXT, 255, false);
blob.mediumColumn = table.addColumn(columnName + "_MEDIUM", DataType.TEXT, 255, false);
}
blob.propsColumn = table.addColumn(columnName + "_PROPS", DataType.CLOB, 0, false);
blobs.put((BinaryProperty) property, blob);
// column = blob.propsColumn;
} else {
column = table.addColumn(columnName, mapType(property), property.getSize(), property.isRequired());
if (type.equals(Date.class)) {
if (property.getFormatPattern() != null) {
column.setAttribute(DBColumn.DBCOLATTR_DATETIMEPATTERN, property.getFormatPattern());
}
}
}
if (column != null) {
columns.put(property, column);
}
}
public void registerReference(Entity entity, Property<Integer> property, String columnName, Entity referredEntity) {
registerReference(entity, property, columnName, referredEntity, null);
}
@SuppressWarnings("unchecked")
public void registerReference(Entity entity, Property<Integer> property, String columnName, Entity referredEntity, String indexName) {
DBTable table = tables.get(entity);
if (table == null) {
throw new IllegalStateException("Cannot register property " + property + " - entity " + entity + " is not yet registered.");
}
DBTableColumn columnMany = table.addColumn(columnName, DataType.INTEGER, 0, false);
DBTableColumn columnOne = (DBTableColumn) columns.get(referredEntity.getPrimaryKey());
if (columnOne == null) {
throw new IllegalStateException("Cannot register reference " + property + " - target entity " + referredEntity + " is not yet registered.");
}
db.addRelation(columnMany.referenceOn(columnOne));
columns.put(property, columnMany);
if (indexName == null) {
indexName = table.getName() + "_" + columnName + referenceIndexSuffix;
}
registerIndex(entity, indexName, false, property);
}
public void registerReverseCollection(Collection<? extends Entity> many, Reference<? extends Entity> one) {
DBTableColumn columnOne = (DBTableColumn) columns.get(one);
if (columnOne == null) {
throw new IllegalStateException("Cannot register reverse collection " + many + " - reference " + one + " is not yet registered.");
}
columns.put(many, columnOne);
}
@SafeVarargs
public final void registerIndex(Entity entity, String name, boolean unique, Property<? extends Serializable>... properties) {
DBTable table = tables.get(entity);
if (table == null) {
throw new IllegalStateException("Cannot register index " + name + " - entity " + entity + " is not yet registered.");
}
DBColumn[] cols = new DBColumn[properties.length];
for (int i = 0; i < properties.length; i++) {
DBTableColumn col = (DBTableColumn) columns.get(properties[i]);
if (col == null) {
throw new IllegalStateException("Cannot register index " + name + " - property " + properties[i] + " is not yet registered.");
}
cols[i] = col;
}
table.addIndex(name, unique, cols);
}
/* (non-Javadoc)
* @see org.aplikator.server.persistence.Persister#addInheritanceIndex(org.aplikator.server.descriptor.Entity, org.aplikator.server.descriptor.Property)
*
* Adds a discriminator column to the indexes
*
*/
@Override
public void addInheritanceIndex(Entity entity, Property<String> discriminator) {
DBTable table = tables.get(entity);
if (table == null) {
throw new IllegalStateException("Cannot re-register index for entity:" + entity + " is not yet registered.");
}
List<DBIndex> dbIndexNewList = new ArrayList<DBIndex>();
List<DBIndex> removedIndexes = new ArrayList<DBIndex>();
// default discriminator name
String defaultDiscriminatorIndex = table.getName() + "_" + columns.get(discriminator).getName() + "_DISIDX";
boolean containsDefaultDiscriminatorIndex = false;
// go through all the indexes and check if discriminator is already part of all indexes
// except for PK and REFID indexes
for (DBIndex dbIndex : table.getIndexes()) {
if (dbIndex.getName().equals(defaultDiscriminatorIndex)) {
containsDefaultDiscriminatorIndex = true;
}
if (DBIndex.PRIMARYKEY == dbIndex.getType()) {
continue;
}
if (dbIndex.getName().endsWith(referenceIndexSuffix)) {
continue;
}
boolean containsDiscriminator = false;
for (int i = 0; i < dbIndex.getColumns().length; i++) {
DBColumn dbColumn = dbIndex.getColumns()[i];
if (dbColumn.equals(columns.get(discriminator))) {
containsDiscriminator = true;
break;
}
}
// if discriminator is not part of the index, the index gets recreated
if (!containsDiscriminator) {
// new index contains all the columns from the old one plus the discriminator
DBColumn[] cols = new DBColumn[dbIndex.getColumns().length + 1];
for (int i = 0; i < dbIndex.getColumns().length; i++) {
cols[i] = dbIndex.getColumns()[i];
}
cols[dbIndex.getColumns().length] = (DBTableColumn) columns.get(discriminator);
// old index is put to the list for future deletion
removedIndexes.add(dbIndex);
// new index is created and added to the list for future add
DBIndex dbIndexNew = new DBIndex(dbIndex.getName(), dbIndex.getType(), cols);
dbIndexNewList.add(dbIndexNew);
}
}
// old index is removed
for (DBIndex removedIndex : removedIndexes) {
table.getIndexes().remove(removedIndex);
}
// new index is added
for (DBIndex dbIndexNew : dbIndexNewList) {
table.addIndex(dbIndexNew);
}
// if table does not contain a separate index for discriminator column it's created
if (!containsDefaultDiscriminatorIndex) {
DBColumn[] cols = new DBColumn[1];
cols[0] = (DBTableColumn) columns.get(discriminator);
DBIndex dbIndex = new DBIndex(defaultDiscriminatorIndex, DBIndex.STANDARD, cols);
table.addIndex(dbIndex);
}
}
public <T extends Serializable> void registerReferencedProperty(Property<T> original, Property<T> clone) {
DBColumnExpr dbc = columns.get(original);
DBColumn refColumn = null;
if (dbc instanceof DBTableColumn) {
refColumn = (DBTableColumn) dbc;
} else if (dbc instanceof DBAliasExpr) {
refColumn = ((DBAliasExpr) dbc).getUpdateColumn();
} else {
throw new RuntimeException("Unexpected referenced column:" + dbc);
}
if (clone.getRefferedThrough() != null) {
Entity referredEntity = clone.getRefferedThrough().referredEntity;
DBTable refTable = (DBTable) (tables.get(referredEntity));
String alias = refTable.getName() + "_" + refColumn.getName();
DBColumnExpr existing = columns.put(clone, dbc.as(alias));
if (existing != null) {
if (existing instanceof DBAliasExpr) {
DBAliasExpr existingAlias = (DBAliasExpr) existing;
if (existingAlias.getExpr().equals(refColumn) && existingAlias.getName().equals(alias)) {
return;
}
}
throw new RuntimeException("Duplicate clone:" + existing);
}
} else {
columns.put(clone, dbc);
}
}
private <T extends Serializable> DataType mapType(Property<T> property) {
Class<T> aplikatorType = property.getType();
if (aplikatorType.equals(String.class)) {
if (property.getSize() > 0) {
return DataType.TEXT;
} else {
return DataType.CLOB;
}
}
if (aplikatorType.equals(Boolean.class)) {
return DataType.BOOL;
}
if (aplikatorType.equals(BigDecimal.class)) {
return DataType.DECIMAL;
}
if (aplikatorType.equals(Integer.class)) {
return DataType.INTEGER;
}
if (aplikatorType.equals(Date.class)) {
return DataType.DATETIME;
}
throw new IllegalStateException("Unsupported property type:" + aplikatorType);
}
/*
* (non-Javadoc)
*
* @see org.aplikator.server.Persister#getJDBCConnection()
*/
@SuppressWarnings("serial")
@Override
public Connection getJDBCConnection() {
Connection conn = null;
try {
conn = dataSource.getConnection();
conn.setAutoCommit(false);
if (oracle_use_NLS_SORT) {
String dbName = conn.getMetaData().getDatabaseProductName();
if (dbName.contains("Oracle")) {
CallableStatement st = conn.prepareCall("ALTER SESSION SET NLS_SORT='" + oracle_NLS_SORT + "'");
st.execute();
st.close();
st = conn.prepareCall("ALTER SESSION SET NLS_COMP='LINGUISTIC'");
st.execute();
st.close();
}
}
if (driver == null) {
LOG.severe("NULL DRIVER");
throw new RuntimeException("NULL DRIVER");
}
} catch (SQLException e) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e1) {
throw new RuntimeException(e1);
}
}
throw new RuntimeException(e);
}
return conn;
}
private void initDatasourceAndDriver() {
if (dataSource == null) {// lazy setup of datasource
HikariDataSource ds = new HikariDataSource();
ds.setDriverClassName(Configurator.get().getConfig().getString(Configurator.JDBC_DRIVER));
ds.setJdbcUrl(Configurator.get().getConfig().getString(Configurator.JDBC_URL));
ds.setUsername(Configurator.get().getConfig().getString(Configurator.JDBC_USERNAME));
ds.setPassword(Configurator.get().getConfig().getString(Configurator.JDBC_PASSWORD));
ds.setAutoCommit(false);
dataSource = ds;
}
if (driver == null) {
Connection conn = null;
try {
conn = dataSource.getConnection();
String dbName = conn.getMetaData().getDatabaseProductName();
if (dbName.contains("PostgreSQL")) {
driver = new DBDatabaseDriverPostgreSQL() {
//fix of empire-db blob bug
@Override
public Object getResultValue(ResultSet rset, int columnIndex, DataType dataType) throws SQLException {
if (dataType == DataType.BLOB) {
InputStream is = rset.getBinaryStream(columnIndex);
if (is == null) {
return new byte[]{};
}
try {
return ByteStreams.toByteArray(is);
} catch (Exception e) {
LOG.log(Level.SEVERE, "", e);
return new byte[]{};
} finally {
if (is != null)
try {
is.close();
} catch (Exception e) {
}
}
} else {
return super.getResultValue(rset, columnIndex, dataType);
}
}
//fix for milliseconds support
@Override
public String getSQLPhrase(int phrase) {
if (phrase == SQL_DATETIME_PATTERN) {
return "yyyy-MM-dd HH:mm:ss.SSS";
} else if (phrase == SQL_FUNC_LOWER) {
return "lower(?)";
} else {
return super.getSQLPhrase(phrase);
}
}
};
} else if (dbName.contains("Oracle")) {
driver = new EmpireDriverOracle();
} else if (dbName.contains("MySQL")) {
driver = new DBDatabaseDriverMySQL() {
//fix for milliseconds support
@Override
public String getSQLPhrase(int phrase) {
if (phrase == SQL_DATETIME_PATTERN) {
return "yyyy-MM-dd HH:mm:ss.SSS";
} else {
return super.getSQLPhrase(phrase);
}
}
};
} else if (dbName.contains("MS-SQL")) {
driver = new DBDatabaseDriverMSSQL() {
//fix for milliseconds support
@Override
public String getSQLPhrase(int phrase) {
if (phrase == SQL_DATETIME_PATTERN) {
return "yyyy-MM-dd HH:mm:ss.SSS";
} else {
return super.getSQLPhrase(phrase);
}
}
};
} else if (dbName.contains("HSQL")) {
driver = new DBDatabaseDriverHSql() {
//fix for milliseconds support
@Override
public String getSQLPhrase(int phrase) {
if (phrase == SQL_DATETIME_PATTERN) {
return "yyyy-MM-dd HH:mm:ss.SSS";
} else {
return super.getSQLPhrase(phrase);
}
}
};
} else if (dbName.contains("H2")) {
driver = new DBDatabaseDriverH2() {
//fix for milliseconds support
@Override
public String getSQLPhrase(int phrase) {
if (phrase == SQL_DATETIME_PATTERN) {
return "yyyy-MM-dd HH:mm:ss.SSS";
} else {
return super.getSQLPhrase(phrase);
}
}
};
} else {
throw new IllegalStateException("Unsupported database:" + dbName);
}
db.open(driver, conn);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
}
}
}
}
}
public Transaction beginTransaction() {
return new EmpireDbTransaction(getJDBCConnection());
}
public void commitTransaction(Transaction tx) {
db.commit(((EmpireDbTransaction) tx).conn);
}
public void rollbackTransaction(Transaction tx) {
LOG.log(Level.INFO, "rollback transaction");
db.rollback(((EmpireDbTransaction) tx).conn);
}
public void close(Transaction tx) {
Connection conn = ((EmpireDbTransaction) tx).conn;
if (conn != null) {
try {
conn.commit();
conn.close();
} catch (SQLException e) {
LOG.log(Level.SEVERE, "Error in close connection", e);
throw new RuntimeException("Error in close connection", e);
}
}
}
/*
*
* Creates a script for localized indexes in Oracle using NLS_SORT defined in appliaction properties
*
*/
public String createLocalizedIndex(boolean updateDB) {
Connection conn = getJDBCConnection();
try {
StringBuilder retval = new StringBuilder();
DBSQLScript script = new DBSQLScript();
if (db.getDriver() instanceof EmpireDriverOracle) {
try {
if ((oracle_NLS_SORT == null) || (oracle_NLS_SORT.trim().length() == 0)) {
throw new IllegalStateException("Property:" + Configurator.ORACLE_NLS_SORT + " is not set");
}
((EmpireDriverOracle) db.getDriver()).createLocalizedIndexes(db, conn, oracle_NLS_SORT, script);
retval.append(script.toString());
} catch (SQLException e) {
throw new EmpireSQLException(driver, e);
}
if (updateDB) {
script.executeAll(driver, conn);
db.commit(conn);
retval.append("Create localized script executed sccessfuly");
}
return retval.toString();
} else {
throw new IllegalStateException("Create localized index implemented only for Oracle driver!");
}
} finally {
try {
conn.commit();
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public String generateDDL(boolean updateDB, boolean checkDB) {
Connection conn = getJDBCConnection();
StringBuilder retval = new StringBuilder();
DBSQLScript script = new DBSQLScript();
try {
if (checkDB) {
if (db.getDriver() instanceof EmpireDriverOracle) {
try {
((EmpireDriverOracle) db.getDriver()).checkDatabase(db, conn.getMetaData().getUserName(), conn, script);
} catch (SQLException e) {
throw new EmpireSQLException(driver, e);
}
} else {
throw new NotImplementedException(this, "checkDatabase");
}
} else {
db.getCreateDDLScript(driver, script);
}
if (updateDB) {
try {
script.executeAll(driver, conn, false);
db.commit(conn);
retval.append("Script executed sucessfuly.");
retval.append("\n\n");
} catch (Exception e) {
retval.append("Script not executed:" + e);
retval.append("\n\n");
} finally {
try {
if (conn != null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
} finally {
try {
if (conn != null) {
conn.commit();
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
// return DDL script
retval.append(script.toString());
return retval.toString();
}
@SuppressWarnings({"rawtypes", "unchecked"})
public List<Record> getRecords(View view, QueryExpression queryExpression, SortItem[] sortItems, String searchString, Collection ownerProperty, PrimaryKey ownerPrimaryKey, int pageOffset, int pageSize, Context ctx) {
DBReader reader = null;
List<Record> retval = new ArrayList<Record>();
if (ownerProperty != null && (ownerPrimaryKey == null || ownerPrimaryKey.getId() == -1)) {//do not return any records for uninitialized nested collections
return retval;
}
try {
// Define the query
PersisterTriggers trigger = view.getPersisterTriggers();
DBCommand cmd = db.createCommand();
// Select required columns, primary key first
List<DBColumnExpr> tableColumns = new ArrayList<DBColumnExpr>(view.getProperties().size() + 1);
tableColumns.add(columns.get(view.getEntity().getPrimaryKey()));
for (Property<? extends Serializable> property : view.getProperties()) {
if (!property.isVirtual()) {
if (!property.getType().equals(BinaryData.class)) {
tableColumns.add(columns.get(property));
} else {
tableColumns.add(blobs.get(property).propsColumn);
}
resolveJoins(cmd, property);
}
}
cmd.select(tableColumns);
if (ownerProperty != null && ownerPrimaryKey != null) {
DBColumnExpr ownerColumn = columns.get(DescriptorRegistry.get().getDescriptionItem(ownerProperty.getId()));
cmd.where(ownerColumn.is(ownerPrimaryKey.getId()));
}
if (queryExpression != null) {
DBCompareExpr where = convertQueryExpression(cmd, queryExpression);
addWhere(cmd, where);
}
if (sortItems != null && sortItems.length > 0) {
SortItem firstSort = sortItems[0];
Property<? extends Serializable> sortProp = firstSort.getSortProperty();
DBColumnExpr sortCol = columns.get(sortProp);
resolveJoins(cmd, sortProp);
// If oracle database is used, then the search query needs to be modified manually, new instance of DBCommand is created (EmpireDBCommandExplicit)
// If the USE_ORACLE_NLS_SORT property is set to true, then normal search is used
//if ((oracle)&&(!useOracleNLS_SORT)) {
// cmd = adjustSearchGetRecordCountForOracle(cmd, sortCol, searchString, firstSort);
//} else {
if (searchString != null && !searchString.trim().equals("")) {
if (firstSort.isSortAscending()) {
if (sortProp.getType().equals(String.class)) {
addWhere(cmd, sortCol.upper().isMoreOrEqual(searchString.trim().toUpperCase()));
} else {
addWhere(cmd, sortCol.isMoreOrEqual(searchString.trim()));
}
} else {
if (sortProp.getType().equals(String.class)) {
addWhere(cmd, sortCol.upper().isLessOrEqual(searchString.trim().toUpperCase()));
} else {
addWhere(cmd, sortCol.isLessOrEqual(searchString.trim()));
}
}
}
//}
for (SortItem sortItem : sortItems) {
cmd.orderBy(columns.get(sortItem.getSortProperty()), !sortItem.isSortAscending());
}
cmd.orderBy(columns.get(view.getEntity().getPrimaryKey()));
} else {
cmd.orderBy(columns.get(view.getEntity().getPrimaryKey()));
}
if (pageSize > 0) {
cmd.limitRows(pageSize);
cmd.skipRows(pageOffset);
}
// Query Records and print output
reader = new DBReader();
// Open Reader
long start = System.currentTimeMillis();
if (pageSize > 0) {
LOG.info("GETPAGE Query: " + cmd.getSelect());
}
checkDBCommand(cmd);
reader.open(cmd, ctx.getTransaction().getConnection());
if (pageSize > 0) {
LOG.info("executed in " + (System.currentTimeMillis() - start) + " ms");
}
int recCounter = 0;
while (reader.moveNext()) {
Record rec = new Record(new RecordDTO(new PrimaryKey(view.getEntity().getId(), reader.getInt(columns.get(view.getEntity().getPrimaryKey())))));
rec.setOwnerPrimaryKey(ownerPrimaryKey);
rec.setOwnerProperty(ownerProperty);
for (Property p : view.getProperties()) {
if (!p.isVirtual()) {
if (Integer.class.equals(p.getType())) {
if (reader.getValue(columns.get(p)) != null) {
rec.setValue(p, reader.getInt(columns.get(p)));
} else {
rec.setValue(p, null);
}
} else if (!p.getType().equals(BinaryData.class)) {
rec.setValue(p, (Serializable) reader.getValue(columns.get(p)));
} else {
rec.setValue(p, (Serializable) reader.getValue(blobs.get(p).propsColumn));
}
}
}
trigger.onLoad(rec, view, ctx);
rec.resetDirtyFlags();
retval.add(rec);
recCounter++;
if (pageSize > 0 && recCounter >= pageSize) {
break;
}
}
} catch (Throwable th) {
LOG.log(Level.SEVERE, "Error in GET PAGE", th);
throw new RuntimeException("Error in GET PAGE", th);
} finally {
if (reader != null) {
reader.close();
}
}
return retval;
}
/*
* (non-Javadoc)
*
* @see
* org.aplikator.server.Persister#getRecordCount(org.aplikator.client.descriptor
* .ViewDTO, org.aplikator.client.descriptor.PropertyDTO,
* org.aplikator.client.data.PrimaryKeyDTO, boolean)
*/
@Override
public int getRecordCount(View view, QueryExpression queryExpression, SortItem[] sortItems, String searchString, Collection ownerProperty, PrimaryKey ownerPrimaryKey, Context ctx) {
DBReader reader = null;
if (ownerProperty != null && (ownerPrimaryKey == null || ownerPrimaryKey.getId() == -1)) {//do not return any records for uninitialized nested collections
return 0;
}
try {
// Define the query
DBCommand cmd = db.createCommand();
cmd.select(tables.get(view.getEntity()).count());
if (ownerProperty != null) {
// TODO Doplnit sloupce kvuli join a where
DBColumnExpr ownerColumn = columns.get(DescriptorRegistry.get().getDescriptionItem(ownerProperty.getId()));
cmd.where(ownerColumn.is(ownerPrimaryKey.getId()));
}
if (queryExpression != null) {
addWhere(cmd, convertQueryExpression(cmd, queryExpression));
}
if (sortItems != null && sortItems.length > 0) {
SortItem firstSort = sortItems[0];
Property<? extends Serializable> sortProp = firstSort.getSortProperty();
resolveJoins(cmd, sortProp);
DBColumnExpr sortCol = columns.get(sortProp);
// If oracle database is used, then the search query needs to be modified manually, new instance of DBCommand is created (EmpireDBCommandExplicit)
// If the USE_ORACLE_NLS_SORT property is set to ture, then normal search is used
//if ((oracle)&&(!useOracleNLS_SORT)) {
// cmd = adjustSearchGetRecordCountForOracle(cmd, sortCol, searchString, firstSort);
//} else {
if (searchString != null && !searchString.equals("")) {
if (firstSort.isSortAscending()) {
addWhere(cmd, sortCol.isMoreOrEqual(searchString));
} else {
addWhere(cmd, sortCol.isLessOrEqual(searchString));
}
}
//}
}
// Query Records and print output
reader = new DBReader();
LOG.fine("getRecord Count Query: " + cmd.getSelect());
// Open Reader
checkDBCommand(cmd);
reader.open(cmd, ctx.getTransaction().getConnection());
if (reader.moveNext()) {
return reader.getInt(0);
}
} catch (Throwable th) {
LOG.log(Level.SEVERE, "Error in getRecordCount", th);
throw new RuntimeException("Error in getRecordCount", th);
} finally {
if (reader != null) {
reader.close();
}
}
return 0;
}
private void addWhere(DBCommand cmd, DBCompareExpr where) {
List<DBCompareExpr> templist = Arrays.asList(where);
cmd.addWhereConstraints(templist);
}
/**
* getEntityPKs - creates a list of PrimaryKeys in the entity
* - if an ownerPrimaryKey is supplied, then it returns the collection records, otherwise all records are processed
*
* @param entity
* @param ownerPrimaryKey
* @param ownerProperty
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public List<PrimaryKey> getEntityPKs(Entity entity, PrimaryKey ownerPrimaryKey, Property ownerProperty, Context ctx) {
DBReader reader = null;
List<PrimaryKey> collectionKeys = new ArrayList<PrimaryKey>();
try {
DBCommand cmd = db.createCommand();
DBColumnExpr[] tableColumns = new DBColumnExpr[1];
tableColumns[0] = columns.get(entity.getPrimaryKey());
cmd.select(tableColumns);
if (ownerProperty != null) {
DBColumnExpr ownerColumn = columns.get(((Property<Integer>) DescriptorRegistry.get().getDescriptionItem(ownerProperty.getId())));
cmd.where(ownerColumn.is(ownerPrimaryKey.getId()));
}
reader = new DBReader();
reader.open(cmd, ctx.getTransaction().getConnection());
while (reader.moveNext()) {
PrimaryKey pk = new PrimaryKey(entity.getId(), reader.getInt(columns.get(entity.getPrimaryKey())));
collectionKeys.add(pk);
}
} catch (Throwable ex) {
LOG.log(Level.SEVERE, "Error in getEntityPKs", ex);
throw new RuntimeException("Error in getEntityPKs", ex);
} finally {
if (reader != null) {
reader.close();
}
}
return collectionKeys;
}
/* (non-Javadoc)
*
* Method creates an instance of CompleteRecord, which contains the record with primaryKey and also records which are binded to the record (references, collections)
* property traverseLevel controls how deep the structure will be
*
* @see org.aplikator.server.persistence.Persister#getCompleteRecord(org.aplikator.client.shared.data.PrimaryKey, int, boolean)
*/
@Override
public Record getCompleteRecord(PrimaryKey primaryKey, int traverseLevel, boolean includeCollections, Context ctx) {
return getRawRecord(primaryKey, traverseLevel, includeCollections, ctx);
}
/**
* Creates an instance of a Complete record also the property referencedRecords is filled with records (collections, references) which belong to the record
*
* @param primaryKey
* @param traverseLevel
* @param includeCollections
* @param ctx
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private Record getRawRecord(PrimaryKey primaryKey, int traverseLevel, boolean includeCollections, Context ctx) {
Record retval = null;
//Connection conn = ((EmpireDbTransaction) tx).conn;
DBReader reader = null;
try {
Entity entity = (Entity) DescriptorRegistry.get().getDescriptionItem(primaryKey.getEntityId());
retval = new Record(new RecordDTO(primaryKey));
DBCommand cmd = db.createCommand();
// Select required columns
ArrayList<DBColumnExpr> tableColumnList = new ArrayList<DBColumnExpr>();
tableColumnList.add(columns.get(entity.getPrimaryKey()));
for (int i = 1; i <= entity.getProperties().size(); i++) {
Property<? extends Serializable> property = entity.getProperties().get(i - 1);
if (traverseLevel > 0) {
// if a property is collection, then traverse through the collection and add records to the referrenced records list
if ((property instanceof Collection) && (includeCollections)) {
Collection colProperty = (Collection) property;
ArrayList<Record> collectionList = new ArrayList<Record>();
Entity refEntity = colProperty.referredEntity;
List<PrimaryKey> listPK = getEntityPKs(refEntity, primaryKey, property, ctx);
for (PrimaryKey colPK : listPK) {
Record rec = getRawRecord(colPK, traverseLevel - 1, includeCollections, ctx);
if (rec != null) {
collectionList.add(rec);
}
}
retval.setValue(colProperty, collectionList);
continue;
}
// if a property is a reference, then inject the reference record primary key
if (property instanceof Reference) {
tableColumnList.add(columns.get(property));
continue;
}
} else {
if (property instanceof Collection || property instanceof Reference) {
continue;
}
}
if (!property.isVirtual()) {
tableColumnList.add(columns.get(property));
}
/*if (property.getRefferedThrough() != null) {
cmd.join(columns.get(property.getRefferedThrough()), columns.get(property.getRefferedThrough().referredEntity.getPrimaryKey()), DBJoinType.LEFT);
} */ //not necessary - joins are defined only in views
}
DBColumnExpr[] tableColumns = new DBColumnExpr[tableColumnList.size()];
int counter = 0;
for (DBColumnExpr tableCol : tableColumnList) {
tableColumns[counter] = tableCol;
counter++;
}
cmd.select(tableColumns);
cmd.where(columns.get(entity.getPrimaryKey()).is(primaryKey.getId()));
reader = new DBReader();
LOG.info("GET raw RECORD Query: " + cmd.getSelect());
reader.open(cmd, ctx.getTransaction().getConnection());
if (reader.moveNext()) {
for (Property p : entity.getProperties()) {
if (p instanceof Collection) {
continue;
}
// insert referenced record into the list
if (p instanceof Reference) {
if (traverseLevel < 1) {
continue;
}
Entity refEntity = ((Reference) p).referredEntity;
Integer refPK = reader.getInt(columns.get(p));
if (refPK > 0) {
Record rec = getRawRecord(new PrimaryKey(refEntity.getId(), refPK), traverseLevel - 1, includeCollections, ctx);
if (rec != null) {
retval.setValue(p, rec);
}
}
continue;
}
if (!p.isVirtual()) {
if (Integer.class.equals(p.getType())) {
if (reader.getValue(columns.get(p)) != null) {
retval.setValue(p, reader.getInt(columns.get(p)));
} else {
retval.setValue(p, null);
}
} else {
if (p.getType().equals(BinaryData.class)) {
// skipping binary fields
} else {
retval.setValue(p, (Serializable) reader.getValue(columns.get(p)));
}
}
}
}
} else {
throw new IllegalStateException("Record not found:" + primaryKey);
}
} catch (Throwable th) {
LOG.log(Level.SEVERE, "Error in getRawRecord ", th);
throw new RuntimeException("Error in getRawRecord ", th);
} finally {
if (reader != null) {
reader.close();
}
}
retval.resetDirtyFlags();
return retval;
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Record getRecord(View view, PrimaryKey primaryKey, Context ctx) {
Record retval = null;
DBReader reader = null;
try {
PersisterTriggers trigger = view.getPersisterTriggers();
Entity entity = (Entity) DescriptorRegistry.get().getDescriptionItem(primaryKey.getEntityId());
DBCommand cmd = db.createCommand();
// Select required columns
List<Property> selectableProperties = getSelectableProperties(entity, view, ctx);
DBColumnExpr[] tableColumns = new DBColumnExpr[selectableProperties.size() + 1];
tableColumns[0] = columns.get(entity.getPrimaryKey());
for (int i = 1; i <= selectableProperties.size(); i++) {
Property<? extends Serializable> property = selectableProperties.get(i - 1);
if (!property.getType().equals(BinaryData.class)) {
tableColumns[i] = columns.get(property);
} else {
tableColumns[i] = blobs.get(property).propsColumn;
}
resolveJoins(cmd, property);
}
cmd.select(tableColumns);
cmd.where(columns.get(entity.getPrimaryKey()).is(primaryKey.getId()));
reader = new DBReader();
LOG.info("GET RECORD Query: " + cmd.getSelect());
checkDBCommand(cmd);
reader.open(cmd, ctx.getTransaction().getConnection());
if (reader.moveNext()) {
retval = new Record(new RecordDTO(new PrimaryKey(entity.getId(), reader.getInt(columns.get(entity.getPrimaryKey())))));
for (int i = 0; i < selectableProperties.size(); i++) {
Property p = selectableProperties.get(i);
if (Integer.class.equals(p.getType())) {
if (reader.getValue(columns.get(p)) != null) {
retval.setValue(p, reader.getInt(columns.get(p)));
} else {
retval.setValue(p, null);
}
} else if (!p.getType().equals(BinaryData.class)) {
retval.setValue(p, (Serializable) reader.getValue(columns.get(p)));
} else {
retval.setValue(p, (Serializable) reader.getValue(blobs.get(p).propsColumn));
}
}
trigger.onLoad(retval, view, ctx);
retval.resetDirtyFlags();
} else {
throw new IllegalStateException("Record not found:" + primaryKey);
}
} catch (Throwable th) {
LOG.log(Level.SEVERE, "Error in getRecord ", th);
throw new RuntimeException("Error in getRecord ", th);
} finally {
if (reader != null) {
reader.close();
}
}
return retval;
}
private void resolveJoins(DBCommand cmd, Property<? extends Serializable> property) {
JoinableProperty<?> joinProperty = property.getRefferedThrough();
if (joinProperty == null)
return;
List<DBJoinExpr> joins = new ArrayList<DBJoinExpr>();
while (joinProperty != null) {
if (joinProperty instanceof Reference) {
joins.add(new DBJoinExpr(columns.get(joinProperty), columns.get(joinProperty.referredEntity.getPrimaryKey()), DBJoinType.LEFT));
} else if (joinProperty instanceof Collection) {
DBColumnExpr masterPK = columns.get(joinProperty.getEntity().getPrimaryKey());
DBColumnExpr detailPK = columns.get(joinProperty.referredEntity.getPrimaryKey());
DBColumnExpr detailFK = columns.get(joinProperty);
DBCommand subCmd = db.createCommand();
DBColumnExpr MIN_ID = detailPK.min().as((DBColumn) detailPK);
subCmd.select(detailFK, MIN_ID);
subCmd.groupBy(detailFK);
DBQuery Q_MIN_ID = new DBQuery(subCmd);
joins.add(new DBJoinExpr(masterPK, detailFK, DBJoinType.LEFT));
DBJoinExpr joinExpr = new DBJoinExpr(detailFK, Q_MIN_ID.findQueryColumn(detailFK), DBJoinType.INNER);
joinExpr.where(detailPK.is(Q_MIN_ID.findQueryColumn(MIN_ID)));
joins.add(joinExpr);
/*DBCommand subCmd = db.createCommand();
DBColumnExpr MIN_ID = detailPK.min().as((DBColumn) detailPK);
subCmd.select(MIN_ID);
subCmd.groupBy(detailFK);
DBQuery Q_MIN_ID = new DBQuery(subCmd);
DBJoinExpr joinExpr =new DBJoinExpr( masterPK,detailFK, DBJoinType.LEFT);
joinExpr.where(detailPK.is(Q_MIN_ID.findQueryColumn(MIN_ID)));
joins.add(joinExpr);*/
}
joinProperty = joinProperty.getRefferedThrough();
}
for (int j = joins.size(); j > 0; j--) {
cmd.join(joins.get(j - 1));
}
}
/*
* (non-Javadoc)
*
* @see
* org.aplikator.server.Persister#updateRecord(org.aplikator.client.descriptor
* .ViewDTO, org.aplikator.client.data.RecordDTO, java.sql.Connection)
*/
@SuppressWarnings("unchecked")
@Override
public Record updateRecord(Record record, Context ctx) {
Entity entity = (Entity) DescriptorRegistry.get().getDescriptionItem(record.getPrimaryKey().getEntityId());
DBRecord rec = new DBRecord();
if (record.getPrimaryKey().getId() == -1) {
rec.create(tables.get(entity), ctx.getTransaction().getConnection());
if (record.getOwnerPropertyId() != null && !"".equals(record.getOwnerPropertyId())) {
DBTableColumn ownerColumn = (DBTableColumn) columns.get(DescriptorRegistry.get().getDescriptionItem(record.getOwnerPropertyId()));
/*if (record.getOwnerPrimaryKey().getId() == -1) {
if (ctx.getResolvedPrimaryKeys().containsKey(record.getOwnerPrimaryKey().getTempId())) {
record.getOwnerPrimaryKey().setId(ctx.getResolvedPrimaryKeys().get(record.getOwnerPrimaryKey().getTempId()));
} else {
throw new IllegalStateException("Unresolved owner primary key in record: " + record.getPrimaryKey());
}
}*/
rec.setValue(ownerColumn, record.getOwnerPrimaryKey().getId());
}
} else {
rec.read(tables.get(entity), record.getPrimaryKey().getId(), ctx.getTransaction().getConnection());
}
for (String id : record.getRecordDTO().getProperties()) {
Property<? extends Serializable> p = (Property<? extends Serializable>) DescriptorRegistry.get().getDescriptionItem(id);
if (p == null || p.getRefferedThrough() != null || p.isVirtual()) {
continue;
}
if (record.isDirty(p)) {
if (p.getType().equals(BinaryData.class)) {
updateBlobColumns((BinaryData) record.getValue(p), (BinaryProperty) p, rec);
} else if ((p instanceof Reference) && (Integer.valueOf(-1).equals(record.getValue(p)))) {
rec.setValue((DBTableColumn) columns.get(p), null);//special case for unsetting the existing reference
} else if (p.getType().equals(Date.class)) {
Date clientDate = (Date) record.getValue(p);
if (p.getFormatPattern() != null && p.getFormatPattern().contains(" ")) {
java.sql.Timestamp dbTimestamp = clientDate != null ? new java.sql.Timestamp(clientDate.getTime()) : null;
rec.setValue((DBTableColumn) columns.get(p), dbTimestamp);
} else {
java.sql.Date dbDate = clientDate != null ? new java.sql.Date(clientDate.getTime()) : null;
rec.setValue((DBTableColumn) columns.get(p), dbDate);
}
} else {
rec.setValue((DBTableColumn) columns.get(p), record.getValue(p));
}
}
}
rec.update(ctx.getTransaction().getConnection());
if (record.getPrimaryKey().getId() == -1) {
record.getPrimaryKey().setId(rec.getInt(columns.get(entity.getPrimaryKey())));
ctx.getRecordContainer().updateTemporaryOwnerPK(record.getPrimaryKey());
//ctx.getResolvedPrimaryKeys().put(record.getPrimaryKey().getTempId(), record.getPrimaryKey().getId());
}
return record;
}
/*
* (non-Javadoc)
*
* @see
* org.aplikator.server.Persister#deleteRecord(org.aplikator.client.descriptor
* .ViewDTO, int, java.sql.Connection)
*/
@SuppressWarnings("rawtypes")
@Override
public void deleteRecord(Record record, Context ctx) {
Entity entity = (Entity) DescriptorRegistry.get().getDescriptionItem(record.getPrimaryKey().getEntityId());
int primaryKey = record.getPrimaryKey().getId();
//find and delete any nested collections
// TODO: delete through command API, to call triggers on collections and
// to propagate further nesting...
//or change to EmpireDB ON DELETE CASCADE (Empiredb issue 79)
for (Property p : entity.getProperties()) {
if (p instanceof Collection) {
Collection c = (Collection) p;
Entity nestedEntity = c.referredEntity;
DBCommand cmd = db.createCommand();
// Select pk column of the items to delete
DBColumnExpr[] tableColumns = new DBColumnExpr[1];
tableColumns[0] = columns.get(nestedEntity.getPrimaryKey());
cmd.select(tableColumns);
cmd.where(columns.get(c).is(primaryKey));//where many column = ownerPK
DBReader reader = new DBReader();
List<Integer> subpks = new ArrayList<Integer>();
try {
LOG.fine("GET SUBRECORD for delete Query: " + cmd.getSelect());
checkDBCommand(cmd);
reader.open(cmd, ctx.getTransaction().getConnection());
while (reader.moveNext()) {
subpks.add(reader.getInt(columns.get(nestedEntity.getPrimaryKey())));//read the list of pks to delete
}
} finally {
reader.close();
}
for (Integer subpk : subpks) {
tables.get(nestedEntity).deleteRecord(subpk, ctx.getTransaction().getConnection());//delete the list
}
}
}
tables.get(entity).deleteRecord(primaryKey, ctx.getTransaction().getConnection());
}
@Override
public BinaryData getBlob(Entity entity, BinaryProperty property, int primaryKey, int maxSize) {
Connection conn = null;
BlobColumns blob = blobs.get(property);
BinaryData retval = new BinaryData(property);
DBReaderExt reader = null;
try {
conn = getJDBCConnection();
DBCommand cmd = db.createCommand();
// Select required columns
DBColumnExpr[] tableColumns = new DBColumnExpr[2];
tableColumns[0] = blob.propsColumn;
if (maxSize == BinaryFieldWidget.THUMBNAIL_SIZE_CODE) {// thumbnail
tableColumns[1] = blob.column;
} else if (maxSize == BinaryFieldWidget.PREVIEW_SIZE_CODE) {// mediumSize
tableColumns[1] = blob.mediumColumn;
} else if (maxSize == BinaryFieldWidget.FULL_SIZE_ATTACHMENT_CODE || maxSize == BinaryFieldWidget.FULL_SIZE_IMAGE_CODE) {// fullSize
tableColumns[1] = blob.fullColumn;
} else {// scaled preview
tableColumns[1] = blob.fullColumn;
}
cmd.select(tableColumns);
cmd.where(columns.get(entity.getPrimaryKey()).is(primaryKey));
reader = new DBReaderExt();
LOG.info("GET BLOB Query: " + cmd.getSelect());
checkDBCommand(cmd);
reader.open(cmd, conn);
if (reader.moveNext()) {
Properties loaderProps = new Properties();
ResultSet rs = reader.getResultset();
String propstr = rs.getString(1);
if (propstr != null) {
loaderProps.load(new StringReader(propstr));
for (Object key : loaderProps.keySet()) {
retval.properties.put(key.toString(), loaderProps.getProperty(key.toString()));
}
}
if (maxSize <= 0) {// thumbnail, medium, full
if (dataStore == null) {
retval.inputStream = rs.getBinaryStream(2);
} else {
String blobId = rs.getString(2);
if (blobId != null) {
retval.inputStream = dataStore.getRecord(new DataIdentifier(blobId)).getStream();
}
}
} else {// scaled preview
BufferedImage fullImage = null;
try {
if (dataStore == null) {
fullImage = ImageIO.read(rs.getBinaryStream(2));
} else {
String blobId = rs.getString(2);
if (blobId != null) {
InputStream fullStream = dataStore.getRecord(new DataIdentifier(blobId)).getStream();
fullImage = ImageIO.read(fullStream);
}
}
fullImage = ImageResizer.removeAlphaChannel(fullImage);
byte[] tempArray = ImageResizer.resize(fullImage, maxSize);
if (tempArray != null) {
retval.inputStream = new ByteArrayInputStream(tempArray);
retval.dataLength = tempArray.length;
}
} finally {
if (fullImage != null) {
fullImage.flush();
}
}
}
} else {
throw new IllegalStateException("Record for blob not found:" + primaryKey);
}
} catch (Throwable th) {
LOG.log(Level.SEVERE, "Error in getBlob ", th);
throw new RuntimeException("Error in getBlob ", th);
} finally {
try {
if (reader != null) {
reader.close();
}
if (conn != null) {
conn.commit();
conn.close();
}
} catch (SQLException ex) {
}
}
return retval;
}
private void updateBlobColumns(BinaryData value, BinaryProperty property, DBRecord rec) {
if (value == null || value.inputStream == null)
return;
BlobColumns blob = blobs.get(property);
String filename = value.properties.get(BinaryData.FILENAME_KEY);
if (ImageResizer.isResizeable(property, filename)) {
byte[] icon = value.icon;
byte[] preview = value.preview;
byte[] data = value.data;
if (data == null) {
data = new byte[0];
BufferedImage imageIcon = null;
try {
data = ByteStreams.toByteArray(value.inputStream);
InputStream dataByteStream = new ByteArrayInputStream(data);
if (ImageResizer.isPdf(filename)) {
imageIcon = PDFLoader.load(dataByteStream);
} else {
imageIcon = ImageIO.read(dataByteStream);
}
IOUtils.tryClose(dataByteStream);
value.properties.put(BinaryData.IMG_HEIGHT, String.valueOf(imageIcon.getHeight()));
value.properties.put(BinaryData.IMG_WIDTH, String.valueOf(imageIcon.getWidth()));
String[] s = property.getFormatPattern().split(",");
int thumbnailSize = Integer.parseInt(s[0]);
int previewSize = Integer.parseInt(s[1]);
imageIcon = ImageResizer.removeAlphaChannel(imageIcon);
icon = ImageResizer.resize(imageIcon, thumbnailSize);
preview = ImageResizer.resize(imageIcon, previewSize);
} catch (IOException e) {
LOG.log(Level.SEVERE, "Error while copying image data:", e);
throw new RuntimeException("Error while copying image data:", e);
} finally {
if (imageIcon != null) {
imageIcon.flush();
}
}
}
if (dataStore == null) {
rec.setValue(blob.fullColumn, new DBBlobData(data));
if (icon != null) {
rec.setValue(blob.column, new DBBlobData(icon));
}
if (preview != null) {
rec.setValue(blob.mediumColumn, new DBBlobData(preview));
}
} else {
try {
DataRecord fullRecord = dataStore.addRecord(new ByteArrayInputStream(data));
rec.setValue(blob.fullColumn, fullRecord.getIdentifier().toString());
} catch (DataStoreException e) {
LOG.log(Level.SEVERE, "Error while storing full image data:", e);
throw new RuntimeException("Error while storing full image data:", e);
}
if (icon != null) {
try {
DataRecord iconRecord = dataStore.addRecord(new ByteArrayInputStream(icon));
rec.setValue(blob.column, iconRecord.getIdentifier().toString());
} catch (DataStoreException e) {
LOG.log(Level.SEVERE, "Error while storing icon image data:", e);
throw new RuntimeException("Error while storing icon image data:", e);
}
}
if (preview != null) {
try {
DataRecord previewRecord = dataStore.addRecord(new ByteArrayInputStream(preview));
rec.setValue(blob.mediumColumn, previewRecord.getIdentifier().toString());
} catch (DataStoreException e) {
LOG.log(Level.SEVERE, "Error while storing preview image data:", e);
throw new RuntimeException("Error while storing preview image data:", e);
}
}
}
} else {
if (dataStore == null) {
rec.setValue(blob.fullColumn, new DBBlobData(value.inputStream, (int) value.dataLength));
} else {
try {
DataRecord fullRecord = dataStore.addRecord(value.inputStream);
rec.setValue(blob.fullColumn, fullRecord.getIdentifier().toString());
} catch (DataStoreException e) {
LOG.log(Level.SEVERE, "Error while storing binary data:", e);
throw new RuntimeException("Error while storing binary data:", e);
}
}
}
StringBuilder propertiesBuilder = new StringBuilder();
for (String key : value.properties.keySet()) {
propertiesBuilder.append(key).append("=").append(value.properties.get(key)).append("\n");
}
rec.setValue(blob.propsColumn, propertiesBuilder.toString());
if (value.getTempFileId() != null && !"".equals(value.getTempFileId())) {//cleanup tempfile store
TempstoreFactory.getTempstore().remove(value.getTempFileId());
}
}
private DBCompareExpr convertQueryExpression(DBCommand cmd, QueryExpression sourceExpression) {
if (sourceExpression instanceof BooleanQueryExpression) {
BooleanQueryExpression srcExp = (BooleanQueryExpression) sourceExpression;
return new DBCompareAndOrExpr(convertQueryExpression(cmd, srcExp.getLeft()), convertQueryExpression(cmd, srcExp.getRight()), srcExp.getOperator().equals(BooleanQueryOperator.OR));
}
if (sourceExpression instanceof TermQueryExpression<?>) {
TermQueryExpression<? extends Serializable> srcExp = (TermQueryExpression<?>) sourceExpression;
if (srcExp.getValue() == null || srcExp.getValue().equals("")) {
return new DBCompareExpr() {
@Override
public boolean isMutuallyExclusive(DBCompareExpr other) {
return false;
}
@Override
public void addSQL(StringBuilder buf, long context) {
buf.append(" 1=1 ");
}
@Override
public void addReferencedColumns(Set<DBColumn> list) {
}
@Override
public DBDatabase getDatabase() {
return db;
}
};
}
resolveJoins(cmd, srcExp.getProperty());
DBOperatorTuple op = convertCompareOperator(srcExp.getOperator());
if (op.ignoreCase) {
return new DBCompareColExpr(columns.get(srcExp.getProperty()).lower(), op.operator, checkValueForOperator(srcExp.getProperty(), srcExp.getOperator(), srcExp.getValue()).toString().toLowerCase());
} else {
return new DBCompareColExpr(columns.get(srcExp.getProperty()), op.operator, checkValueForOperator(srcExp.getProperty(), srcExp.getOperator(), srcExp.getValue()));
}
}
return null;
}
private DBOperatorTuple convertCompareOperator(TermQueryOperator operator) {
switch (operator) {
case EQUAL:
return new DBOperatorTuple(DBCmpType.EQUAL, false);
case NOTEQUAL:
return new DBOperatorTuple(DBCmpType.NOTEQUAL, false);
case LESSTHAN:
return new DBOperatorTuple(DBCmpType.LESSTHAN, false);
case MOREOREQUAL:
return new DBOperatorTuple(DBCmpType.MOREOREQUAL, false);
case GREATERTHAN:
return new DBOperatorTuple(DBCmpType.GREATERTHAN, false);
case LESSOREQUAL:
return new DBOperatorTuple(DBCmpType.LESSOREQUAL, false);
case LIKE:
case STARTSWITH:
return new DBOperatorTuple(DBCmpType.LIKE, false);
case LIKE_IGNORECASE:
case STARTSWITH_IGNORECASE:
return new DBOperatorTuple(DBCmpType.LIKE, true);
case NOTLIKE:
case NOTSTARTSWITH:
return new DBOperatorTuple(DBCmpType.NOTLIKE, false);
case NOTLIKE_IGNORECASE:
case NOTSTARTSWITH_IGNORECASE:
return new DBOperatorTuple(DBCmpType.NOTLIKE, true);
case NULL:
return new DBOperatorTuple(DBCmpType.NULL, false);
case NOTNULL:
return new DBOperatorTuple(DBCmpType.NOTNULL, false);
case BETWEEN:
return new DBOperatorTuple(DBCmpType.BETWEEN, false);
case NOTBETWEEN:
return new DBOperatorTuple(DBCmpType.NOTBETWEEN, false);
case IN:
return new DBOperatorTuple(DBCmpType.IN, false);
case NOTIN:
return new DBOperatorTuple(DBCmpType.NOTIN, false);
default:
return null;
}
}
private Serializable checkValueForOperator(Property p, TermQueryOperator operator, Serializable value) {
if (p.getType().equals(Date.class)) {
Date clientDate = (Date) value;
if (p.getFormatPattern() != null && p.getFormatPattern().contains(" ")) {
java.sql.Timestamp dbTimestamp = clientDate != null ? new java.sql.Timestamp(clientDate.getTime()) : null;
return dbTimestamp;
} else {
java.sql.Date dbDate = clientDate != null ? new java.sql.Date(clientDate.getTime()) : null;
return dbDate;
}
} else {
if (TermQueryOperator.LIKE.equals(operator) || TermQueryOperator.NOTLIKE.equals(operator)) {
if (value instanceof String) {
String strval = (String) value;
if (!strval.startsWith("%")) {
strval = "%".concat(strval);
}
if (!strval.endsWith("%")) {
strval = strval.concat("%");
}
return strval;
}
}
if (TermQueryOperator.STARTSWITH.equals(operator) || TermQueryOperator.NOTSTARTSWITH.equals(operator) || TermQueryOperator.STARTSWITH_IGNORECASE.equals(operator)) {
if (value instanceof String) {
String strval = (String) value;
if (!strval.endsWith("%")) {
strval = strval.concat("%");
}
return strval;
}
}
}
return value;
}
@Override
public boolean isSuspended() {
return suspendedFlag.get();
}
@Override
public boolean setSuspended(boolean suspended) {
return suspendedFlag.compareAndSet(!suspended, suspended);
}
private static class DBOperatorTuple {
final DBCmpType operator;
final boolean ignoreCase;
DBOperatorTuple(DBCmpType operator, boolean ignoreCase) {
this.operator = operator;
this.ignoreCase = ignoreCase;
}
}
private static class DBReaderExt extends DBReader {
/**
*
*/
private static final long serialVersionUID = 1L;
private ResultSet getResultset() {
return rset;
}
}
private static class BlobColumns {
private DBTableColumn column;
private DBTableColumn fullColumn;
private DBTableColumn mediumColumn;
private DBTableColumn propsColumn;
}
private class EmpireDbTransaction implements Transaction {
private final Connection conn;
private EmpireDbTransaction(Connection conn) {
this.conn = conn;
}
@Override
public Connection getConnection() {
return conn;
}
}
}