package org.jblooming.persistence.hibernate; import org.hibernate.cfg.Configuration; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.mapping.*; import org.hibernate.mapping.Collection; import org.hibernate.tool.hbm2ddl.DatabaseMetadata; import org.hibernate.type.*; import org.hibernate.SessionFactory; import org.jblooming.ontology.Identifiable; import org.jblooming.ontology.IdentifiableSupport; import org.jblooming.persistence.PersistenceHome; import org.jblooming.persistence.exceptions.*; import org.jblooming.utilities.*; import org.jblooming.utilities.file.FileUtilities; import org.jblooming.PlatformRuntimeException; import org.jblooming.waf.constants.Fields; import org.jblooming.waf.settings.ApplicationState; import org.jblooming.waf.settings.PersistenceConfiguration; import org.jblooming.tracer.Tracer; import org.jblooming.uidgen.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.sql.*; import java.util.*; import java.util.Set; import java.util.Date; import java.util.List; import java.lang.reflect.Method; /** * @author Pietro Polsinelli ppolsinelli@open-lab.com */ public class HibernateUtilities { /*public static String generateSchema(boolean analyze, boolean catchExceptions, boolean recreateSchema, HttpServletRequest request) { try { return generateSchema(analyze, catchExceptions, recreateSchema, null, null, false, request); } catch (Exception e) { throw new PlatformRuntimeException(e); } }*/ public static String generateSchema(boolean analyze, boolean catchExceptions, boolean recreateSchema, String filterPrefix, HttpServletRequest request, HttpServletResponse response, PersistenceContext pc) { try { return generateSchema(analyze, catchExceptions, recreateSchema, null, filterPrefix, false, request, pc); } catch (Exception e) { throw new PlatformRuntimeException(e); } } public static String generateSchema(boolean analyze, boolean catchExceptions, boolean recreateSchema, Method tableNameValidator, boolean feedBackOnInvalid, HttpServletRequest request, PersistenceContext pc ) throws Exception { return generateSchema(analyze, catchExceptions, recreateSchema, tableNameValidator, null, feedBackOnInvalid, request, pc); } public static String generateSchema(boolean analyze, boolean catchExceptions, boolean recreateSchema, String filterPrefix, boolean feedBackOnInvalid, HttpServletRequest request, PersistenceContext pc) throws Exception { return generateSchema(analyze, catchExceptions, recreateSchema, null, filterPrefix, feedBackOnInvalid, request, pc); } public static String generateSchema( boolean analyze, boolean catchExceptions, boolean recreateSchema, Method tableNameValidator, String filterPrefix, boolean feedBackOnInvalid, HttpServletRequest request, PersistenceContext pc ) throws Exception { return generateSchema(analyze, catchExceptions, recreateSchema, tableNameValidator, filterPrefix, feedBackOnInvalid, HttpUtilities.getFileSystemRootPathForRequest(request), pc); } public static String generateSchema(boolean analyze, boolean catchExceptions, boolean recreateSchema, Method tableNameValidator, String filterPrefixes, boolean feedBackOnInvalid, String rootPath, PersistenceContext pc) throws Exception { StringBuffer hist = new StringBuffer(); hist.append("----------------------------------------------------------------------------------------------------------------\n"); hist.append("Schema evolution: " + new Date() + "\n\n"); String feedback = "feedback:<br>"; Configuration store = pc.persistenceConfiguration.getHibernateConfiguration(); Connection connection = pc.session.connection(); String[] createSQL; Dialect dialect = Dialect.getDialect(store.getProperties()); if (recreateSchema) createSQL = store.generateSchemaCreationScript(dialect); else { DatabaseMetadata info = new DatabaseMetadata(connection, dialect); createSQL = store.generateSchemaUpdateScript(dialect, info); } Set<String> launchedUpdates = new HashSet(); boolean isMySql = dialect instanceof MySQLDialect; boolean isPostgreSQL83 = dialect instanceof PostgreSQLDialect && Fields.TRUE.equals(ApplicationState.getApplicationSetting("ISPOSTGRESQL83")); for (int i = 0; i < createSQL.length; i++) { String sql = createSQL[i]; if (launchedUpdates.contains(sql.toLowerCase())) { feedback = feedback + "operation cancelled as already done:<br><font color='orange'><small >" + sql + "</small></font><br>"; continue; } if (tableNameValidator != null && !((Boolean) tableNameValidator.invoke(tableNameValidator.getDeclaringClass().newInstance(), sql))) { if (feedBackOnInvalid) feedback = feedback + "operation cancelled:<br><font color='gray'><small >" + sql + "</small></font><br>"; continue; } if (filterPrefixes != null) { List<String> filterPrefixesL = StringUtilities.splitToList(filterPrefixes, ","); boolean skip = false; for (String filterPrefix : filterPrefixesL) { if (filterPrefix != null && filterPrefix.trim().length() > 0 && (sql.toUpperCase().indexOf(" " + filterPrefix.toUpperCase()) > -1 || sql.toUpperCase().indexOf("." + filterPrefix.toUpperCase()) > -1)) { if (feedBackOnInvalid) feedback = feedback + "operation cancelled:<br><font color='gray'><small >" + sql + "</small></font><br>"; skip = true; break; } } if (skip) continue; } Tracer.platformLogger.debug(sql); feedback = feedback + sql + "<br>"; if (!analyze) { if (catchExceptions) { try { Statement stmt = connection.createStatement(); stmt.executeUpdate(sql); stmt.close(); pc.checkPoint(); } catch (SQLException e) { feedback = feedback + "<font color='red'>" + JSP.encode(e.getMessage()) + "</font><br>"; Tracer.platformLogger.error(e); } } else { //hack for indexes try { Statement stmt = connection.createStatement(); stmt.executeUpdate(sql); stmt.close(); } catch (SQLException e) { if (sql.toLowerCase().indexOf("create index") > -1 || sql.toLowerCase().indexOf("create unique index") > -1) Tracer.hibernateLogger.warn("On this database index could not be created: " + sql); else { Tracer.hibernateLogger.error(sql, e); throw e; } } } pc.checkPoint(); } launchedUpdates.add(sql.toLowerCase()); hist.append(sql + "\n"); } if (!analyze) { String logDirPath = rootPath + File.separator + "WEB-INF" + File.separator + "log"; String log = logDirPath + File.separator + "schemaHistory.log"; File logDir = new File(logDirPath); logDir.mkdirs(); File file = new File(log); file.createNewFile(); FileUtilities.appendToFile(log, hist.toString()); //todo: update script fro postgresql!!! } return feedback; } public static int getColumnLength(Class persClass, String property) { int length = 255; Column column = getColumn(persClass, property); if (column != null) length = column.getLength(); return length; } public static Column getColumn(Class persClass, String property) { Column column = null; PersistentClass pc = getClassMapping(persClass); Property prop = pc.getProperty(property.trim()); column = (Column) prop.getColumnIterator().next(); //column = pc.getTable().getColumn(new Column(property)); return column; } public static boolean isIdInteger(Class persClass) { PersistentClass pc = getClassMapping(persClass); //if (pc.getIdentifier() instanceof SimpleValue) { if (pc != null && pc.getIdentifier() instanceof SimpleValue) { SimpleValue sv = (SimpleValue) pc.getIdentifier(); if (sv.getType() instanceof IntegerType) return true; } return false; } public static PersistentClass getClassMapping(Class persClass) { PersistenceConfiguration pcf = PersistenceConfiguration.getInstance(persClass); PersistentClass pc = null; if (pcf != null) { PlatformAnnotationConfiguration hibConf = pcf.getHibernateConfiguration(); pc = hibConf.getClassMapping(persClass.getName()); if (pc == null) { //consider the entity name case Iterator i = hibConf.getClassMappings(); while (i.hasNext()) { PersistentClass classMapping = (PersistentClass) i.next(); if (persClass.getName().equalsIgnoreCase(classMapping.getClassName())) { pc = classMapping; break; } } } } return pc; } public static boolean isIdAssigned(Class persClass) { PersistentClass pc = getClassMapping(persClass); if (pc.getIdentifier() instanceof SimpleValue) { SimpleValue sv = (SimpleValue) pc.getIdentifier(); return "assigned".equalsIgnoreCase(sv.getIdentifierGeneratorStrategy()); } else return false; } public static String counterNameForIdAssigned(Class persClass) { String result = null; PersistentClass pc = getClassMapping(persClass); if (pc.getIdentifier() instanceof SimpleValue) { SimpleValue sv = (SimpleValue) pc.getIdentifier(); if ("assigned".equalsIgnoreCase(sv.getIdentifierGeneratorStrategy())) { result = pc.getTable().getName(); } } return result; } public static SimpleValue getIdentifierGenerator(Class persClass) { SimpleValue result = null; PersistentClass pc = getClassMapping(persClass); if (pc.getIdentifier() instanceof SimpleValue) { result = (SimpleValue) pc.getIdentifier(); } return result; } public static void incrementIdIfNew(Identifiable i) throws StoreException { if ((PersistenceHome.NEW_EMPTY_ID.equals(i.getId())) || i.getId() == null) { PersistentClass pc = getClassMapping(i.getClass()); if (pc.getIdentifier() instanceof SimpleValue) { SimpleValue sv = (SimpleValue) pc.getIdentifier(); if ("assigned".equalsIgnoreCase(sv.getIdentifierGeneratorStrategy())) { String counterName = pc.getTable().getName(); if (sv.getType() instanceof IntegerType) //case int assigned i.setId(CounterHome.next(counterName)); else if (sv.getType() instanceof LongType) //case int assigned i.setId((long) CounterHome.next(counterName)); else //case serializable i.setId(CounterHome.nextSer(counterName)); } } } } public static Type getIdType(Identifiable i) { return getIdType(i.getClass()); } public static Type getIdType(Class clazz) { return getClassMapping(clazz).getIdentifier().getType(); } public static java.util.Map<String, Collection> getAllInversesOnTarget(Object target) { Object realDelendo = ReflectionUtilities.getUnderlyingObjectAsObject(target); java.util.Map<String, Collection> inverses = new HashTable<String, Collection>(); Class realClass = realDelendo.getClass(); String targetTable = HibernateUtilities.getClassMapping(realClass).getTable().getName(); Iterator comMapsIt = HibernateFactory.getConfig().getCollectionMappings(); while (comMapsIt.hasNext()) { org.hibernate.mapping.Collection collection = (org.hibernate.mapping.Collection) comMapsIt.next(); if (collection.isInverse() && collection.getOwner().getTable().getName().equals(targetTable)) inverses.put(collection.getNodeName(), collection); } return inverses; } public static String getTableName(Class persistentClass) { PersistentClass classMapping = HibernateUtilities.getClassMapping(persistentClass); if (classMapping != null) return classMapping.getTable().getName(); else return null; } /** * Filters the src collection and puts the objects matching the * clazz into the dest collection. */ public static <T> void filterHibernateCollection(Class<T> clazz, java.util.Collection<?> src, java.util.Collection<T> dest) { for (Object o : src) { o = ReflectionUtilities.getUnderlyingObject(o); if (clazz.isInstance(o)) { dest.add(clazz.cast(o)); } } } /** * Filters the src collection and puts all matching objects into * an ArrayList, which is then returned. */ public static <T> java.util.Collection<T> filterHibernateCollection(Class<T> clazz, java.util.Collection<?> src) { java.util.Collection<T> result = new ArrayList<T>(); filterHibernateCollection(clazz, src, result); return result; } public static String generateDropInxed(Class classToDeindexed, String indexName) { String sql = null; try { // get PersitentClass PersistenceConfiguration configuration = PersistenceConfiguration.getDefaultPersistenceConfiguration(); PersistentClass pClass = configuration.getHibernateConfiguration().getClassMapping(classToDeindexed.getName()); Table table = pClass.getTable(); // this string is the same of Index.buildSqlDropIndexString, but they won't fix this damnd problem //sql = "drop index " + (d.qualifyIndexName() ? StringHelper.qualify(table.getQualifiedName(d, defaultCatalog, defaultSchema), indexName) : indexName); String dialectClassName = configuration.dialect.getName(); if (dialectClassName.indexOf("Oracle") >= 0) { sql = "drop index " + indexName; } else if (dialectClassName.indexOf("MySQLDialect") >= 0) { sql = "drop index " + indexName + " on " + table.getName(); } else { //String defaultCatalog = table.getCatalog() != null ? table.getCatalog() : Environment.DEFAULT_CATALOG; String defaultCatalog = table.getCatalog() != null ? table.getCatalog() : null; String defaultSchema = PersistenceConfiguration.getDefaultPersistenceConfiguration().schemaName != null ? PersistenceConfiguration.getDefaultPersistenceConfiguration().schemaName : table.getSchema(); // I've used this method: completly bugged! :( sql = Index.buildSqlDropIndexString((Dialect) configuration.dialect.newInstance(), table, indexName, defaultCatalog, defaultSchema); } if (sql == null || sql.equalsIgnoreCase("")) { sql = "drop index " + table.getName() + "." + indexName; } } catch (Throwable t) { Tracer.desperatelyLog("", true, t); } return sql; } }