@Override public void onApplicationStart() { if (JPA.entityManagerFactory == null) { List<Class> classes = Play.classloader.getAnnotatedClasses(Entity.class); if (classes.isEmpty() && Play.configuration.getProperty("jpa.entities", "").equals("")) { return; } final String dataSource = Play.configuration.getProperty("hibernate.connection.datasource"); if (StringUtils.isEmpty(dataSource) && DB.datasource == null) { throw new JPAException( "Cannot start a JPA manager without a properly configured database", new NullPointerException("No datasource configured")); } Ejb3Configuration cfg = new Ejb3Configuration(); if (DB.datasource != null) { cfg.setDataSource(DB.datasource); } if (!Play.configuration .getProperty("jpa.ddl", Play.mode.isDev() ? "update" : "none") .equals("none")) { cfg.setProperty( "hibernate.hbm2ddl.auto", Play.configuration.getProperty("jpa.ddl", "update")); } cfg.setProperty( "hibernate.dialect", getDefaultDialect(Play.configuration.getProperty("db.driver"))); cfg.setProperty("javax.persistence.transaction", "RESOURCE_LOCAL"); // Explicit SAVE for JPABase is implemented here // ~~~~~~ // We've hacked the org.hibernate.event.def.AbstractFlushingEventListener line 271, to flush // collection update,remove,recreation // only if the owner will be saved. // As is: // if (session.getInterceptor().onCollectionUpdate(coll, ce.getLoadedKey())) { // actionQueue.addAction(...); // } // // This is really hacky. We should move to something better than Hibernate like EBEAN cfg.setInterceptor( new EmptyInterceptor() { @Override public int[] findDirty( Object o, Serializable id, Object[] arg2, Object[] arg3, String[] arg4, Type[] arg5) { if (o instanceof JPABase && !((JPABase) o).willBeSaved) { return new int[0]; } return null; } @Override public boolean onCollectionUpdate(Object collection, Serializable key) throws CallbackException { if (collection instanceof PersistentCollection) { Object o = ((PersistentCollection) collection).getOwner(); if (o instanceof JPABase) { return ((JPABase) o).willBeSaved; } } else { System.out.println("HOO: Case not handled !!!"); } return super.onCollectionUpdate(collection, key); } @Override public boolean onCollectionRecreate(Object collection, Serializable key) throws CallbackException { if (collection instanceof PersistentCollection) { Object o = ((PersistentCollection) collection).getOwner(); if (o instanceof JPABase) { return ((JPABase) o).willBeSaved; } } else { System.out.println("HOO: Case not handled !!!"); } return super.onCollectionRecreate(collection, key); } @Override public boolean onCollectionRemove(Object collection, Serializable key) throws CallbackException { if (collection instanceof PersistentCollection) { Object o = ((PersistentCollection) collection).getOwner(); if (o instanceof JPABase) { return ((JPABase) o).willBeSaved; } } else { System.out.println("HOO: Case not handled !!!"); } return super.onCollectionRemove(collection, key); } }); if (Play.configuration.getProperty("jpa.debugSQL", "false").equals("true")) { org.apache.log4j.Logger.getLogger("org.hibernate.SQL").setLevel(Level.ALL); } else { org.apache.log4j.Logger.getLogger("org.hibernate.SQL").setLevel(Level.OFF); } // inject additional hibernate.* settings declared in Play! configuration cfg.addProperties((Properties) Utils.Maps.filterMap(Play.configuration, "^hibernate\\..*")); try { Field field = cfg.getClass().getDeclaredField("overridenClassLoader"); field.setAccessible(true); field.set(cfg, Play.classloader); } catch (Exception e) { Logger.error( e, "Error trying to override the hibernate classLoader (new hibernate version ???)"); } for (Class<?> clazz : classes) { if (clazz.isAnnotationPresent(Entity.class)) { cfg.addAnnotatedClass(clazz); Logger.trace("JPA Model : %s", clazz); } } String[] moreEntities = Play.configuration.getProperty("jpa.entities", "").split(", "); for (String entity : moreEntities) { if (entity.trim().equals("")) { continue; } try { cfg.addAnnotatedClass(Play.classloader.loadClass(entity)); } catch (Exception e) { Logger.warn("JPA -> Entity not found: %s", entity); } } for (ApplicationClass applicationClass : Play.classes.all()) { if (applicationClass.isClass() || applicationClass.javaPackage == null) { continue; } Package p = applicationClass.javaPackage; Logger.info("JPA -> Adding package: %s", p.getName()); cfg.addPackage(p.getName()); } String mappingFile = Play.configuration.getProperty("jpa.mapping-file", ""); if (mappingFile != null && mappingFile.length() > 0) { cfg.addResource(mappingFile); } Logger.trace("Initializing JPA ..."); try { JPA.entityManagerFactory = cfg.buildEntityManagerFactory(); } catch (PersistenceException e) { throw new JPAException(e.getMessage(), e.getCause() != null ? e.getCause() : e); } JPQL.instance = new JPQL(); } }
@Override public void onApplicationStart() { // must check and configure JPA for each DBConfig for (DBConfig dbConfig : DB.getDBConfigs()) { // check and enable JPA on this config // is JPA already configured? String configName = dbConfig.getDBConfigName(); if (JPA.getJPAConfig(configName, true) == null) { // must configure it // resolve prefix for hibernate config.. // should be nothing for default, and db_<name> for others String propPrefix = ""; if (!DBConfig.defaultDbConfigName.equalsIgnoreCase(configName)) { propPrefix = "db_" + configName + "."; } List<Class> classes = findEntityClassesForThisConfig(configName, propPrefix); if (classes == null) continue; // we're ready to configure this instance of JPA final String hibernateDataSource = Play.configuration.getProperty(propPrefix + "hibernate.connection.datasource"); if (StringUtils.isEmpty(hibernateDataSource) && dbConfig == null) { throw new JPAException( "Cannot start a JPA manager without a properly configured database" + getConfigInfoString(configName), new NullPointerException("No datasource configured")); } Ejb3Configuration cfg = new Ejb3Configuration(); if (dbConfig.getDatasource() != null) { cfg.setDataSource(dbConfig.getDatasource()); } if (!Play.configuration .getProperty(propPrefix + "jpa.ddl", Play.mode.isDev() ? "update" : "none") .equals("none")) { cfg.setProperty( "hibernate.hbm2ddl.auto", Play.configuration.getProperty(propPrefix + "jpa.ddl", "update")); } String driver = null; if (StringUtils.isEmpty(propPrefix)) { driver = Play.configuration.getProperty("db.driver"); } else { driver = Play.configuration.getProperty(propPrefix + "driver"); } cfg.setProperty("hibernate.dialect", getDefaultDialect(propPrefix, driver)); cfg.setProperty("javax.persistence.transaction", "RESOURCE_LOCAL"); cfg.setInterceptor(new PlayInterceptor()); // This setting is global for all JPAs - only configure if configuring default JPA if (StringUtils.isEmpty(propPrefix)) { if (Play.configuration.getProperty(propPrefix + "jpa.debugSQL", "false").equals("true")) { org.apache.log4j.Logger.getLogger("org.hibernate.SQL").setLevel(Level.ALL); } else { org.apache.log4j.Logger.getLogger("org.hibernate.SQL").setLevel(Level.OFF); } } // inject additional hibernate.* settings declared in Play! configuration Properties additionalProperties = (Properties) Utils.Maps.filterMap(Play.configuration, "^" + propPrefix + "hibernate\\..*"); // We must remove prefix from names Properties transformedAdditionalProperties = new Properties(); for (Map.Entry<Object, Object> entry : additionalProperties.entrySet()) { Object key = entry.getKey(); if (!StringUtils.isEmpty(propPrefix)) { key = ((String) key).substring(propPrefix.length()); // chop off the prefix } transformedAdditionalProperties.put(key, entry.getValue()); } cfg.addProperties(transformedAdditionalProperties); try { // nice hacking :) I like it.. Field field = cfg.getClass().getDeclaredField("overridenClassLoader"); field.setAccessible(true); field.set(cfg, Play.classloader); } catch (Exception e) { Logger.error( e, "Error trying to override the hibernate classLoader (new hibernate version ???)"); } for (Class<?> clazz : classes) { cfg.addAnnotatedClass(clazz); if (Logger.isTraceEnabled()) { Logger.trace("JPA Model : %s", clazz); } } String[] moreEntities = Play.configuration.getProperty(propPrefix + "jpa.entities", "").split(", "); for (String entity : moreEntities) { if (entity.trim().equals("")) { continue; } try { cfg.addAnnotatedClass(Play.classloader.loadClass(entity)); } catch (Exception e) { Logger.warn("JPA -> Entity not found: %s", entity); } } for (ApplicationClass applicationClass : Play.classes.all()) { if (applicationClass.isClass() || applicationClass.javaPackage == null) { continue; } Package p = applicationClass.javaPackage; Logger.info("JPA -> Adding package: %s", p.getName()); cfg.addPackage(p.getName()); } String mappingFile = Play.configuration.getProperty(propPrefix + "jpa.mapping-file", ""); if (mappingFile != null && mappingFile.length() > 0) { cfg.addResource(mappingFile); } if (Logger.isTraceEnabled()) { Logger.trace("Initializing JPA" + getConfigInfoString(configName) + " ..."); } try { JPA.addConfiguration(configName, cfg); } catch (PersistenceException e) { throw new JPAException( e.getMessage() + getConfigInfoString(configName), e.getCause() != null ? e.getCause() : e); } } } // must look for Entity-objects referring to none-existing JPAConfig List<Class> allEntityClasses = Play.classloader.getAnnotatedClasses(Entity.class); for (Class clazz : allEntityClasses) { String configName = Entity2JPAConfigResolver.getJPAConfigNameForEntityClass(clazz); if (JPA.getJPAConfig(configName, true) == null) { throw new JPAException( "Found Entity-class (" + clazz.getName() + ") referring to none-existing JPAConfig" + getConfigInfoString(configName) + ". " + "Is JPA properly configured?"); } } }
/** * @param classes * @param datasource * @return */ @SuppressWarnings("unchecked") public static Ejb3Configuration buildEjbConfiguration( List<Class> classes, ComboPooledDataSource datasource) { Ejb3Configuration cfg = new Ejb3Configuration(); cfg.setDataSource(datasource); if (!Play.configuration.getProperty("jpa.ddl", "update").equals("none")) { cfg.setProperty( "hibernate.hbm2ddl.auto", Play.configuration.getProperty("jpa.ddl", "update")); } cfg.setProperty("hibernate.dialect", getDefaultDialect(datasource.getDriverClass())); cfg.setProperty("javax.persistence.transaction", "RESOURCE_LOCAL"); // Explicit SAVE for JPASupport is implemented here // ~~~~~~ // We've hacked the org.hibernate.event.def.AbstractFlushingEventListener line // 271, to flush collection update,remove,recreation // only if the owner will be saved. // As is: // if (session.getInterceptor().onCollectionUpdate(coll, ce.getLoadedKey())) { // actionQueue.addAction(...); // } // // This is really hacky. We should move to something better than Hibernate // like EBEAN cfg.setInterceptor( new EmptyInterceptor() { /** Generated GUID for serialization support. */ private static final long serialVersionUID = -8670026536584880961L; @Override public int[] findDirty( Object o, Serializable id, Object[] arg2, Object[] arg3, String[] arg4, Type[] arg5) { if (o instanceof JPASupport && !((JPASupport) o).willBeSaved) { return new int[0]; } return null; } @Override public boolean onCollectionUpdate(Object collection, Serializable key) throws CallbackException { if (collection instanceof PersistentCollection) { Object o = ((PersistentCollection) collection).getOwner(); if (o instanceof JPASupport) { return ((JPASupport) o).willBeSaved; } } else { System.out.println("HOO: Case not handled !!!"); } return super.onCollectionUpdate(collection, key); } @Override public boolean onCollectionRecreate(Object collection, Serializable key) throws CallbackException { if (collection instanceof PersistentCollection) { Object o = ((PersistentCollection) collection).getOwner(); if (o instanceof JPASupport) { return ((JPASupport) o).willBeSaved; } } else { System.out.println("HOO: Case not handled !!!"); } return super.onCollectionRecreate(collection, key); } @Override public boolean onCollectionRemove(Object collection, Serializable key) throws CallbackException { if (collection instanceof PersistentCollection) { Object o = ((PersistentCollection) collection).getOwner(); if (o instanceof JPASupport) { return ((JPASupport) o).willBeSaved; } } else { System.out.println("HOO: Case not handled !!!"); } return super.onCollectionRemove(collection, key); } }); if (Play.configuration.getProperty("jpa.debugSQL", "false").equals("true")) { org.apache.log4j.Logger.getLogger("org.hibernate.SQL").setLevel(Level.ALL); } else { org.apache.log4j.Logger.getLogger("org.hibernate.SQL").setLevel(Level.OFF); } // inject additional hibernate.* settings declared in Play! configuration cfg.addProperties((Properties) Utils.Maps.filterMap(Play.configuration, "^hibernate\\..*")); try { Field field = cfg.getClass().getDeclaredField("overridenClassLoader"); field.setAccessible(true); field.set(cfg, Play.classloader); } catch (Exception e) { Logger.error( e, "Error trying to override the hibernate classLoader (new hibernate version ???)"); } for (Class<? extends Annotation> clazz : classes) { if (clazz.isAnnotationPresent(Entity.class)) { cfg.addAnnotatedClass(clazz); Logger.trace("JPA Model : %s", clazz); } } String[] moreEntities = Play.configuration.getProperty("jpa.entities", "").split(", "); for (String entity : moreEntities) { if (entity.trim().equals("")) continue; try { if (Play.classes.getApplicationClass(entity) == null) { cfg.addAnnotatedClass(Play.classloader.loadClass(entity)); } else { cfg.addAnnotatedClass(Play.classes.getApplicationClass(entity).javaClass); } } catch (Exception e) { Logger.warn("JPA -> Entity not found: %s", entity); } } return cfg; }