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; } } }