diff options
Diffstat (limited to 'feature-session-persistence/src/main')
8 files changed, 392 insertions, 386 deletions
diff --git a/feature-session-persistence/src/main/feature/config/feature-session-persistence.properties b/feature-session-persistence/src/main/feature/config/feature-session-persistence.properties index 6204b5ed..0f15e3aa 100644 --- a/feature-session-persistence/src/main/feature/config/feature-session-persistence.properties +++ b/feature-session-persistence/src/main/feature/config/feature-session-persistence.properties @@ -22,7 +22,8 @@ javax.persistence.jdbc.driver= org.mariadb.jdbc.Driver javax.persistence.jdbc.url=jdbc:mariadb://${{SQL_HOST}}:3306/sessionpersistence javax.persistence.jdbc.user=${{SQL_USER}} javax.persistence.jdbc.password=${{SQL_PASSWORD}} -hibernate.dataSource=org.mariadb.jdbc.MySQLDataSource #Seconds timeout - 15 minutes -persistence.sessioninfo.timeout=900
\ No newline at end of file +persistence.sessioninfo.timeout=900 + +persistence.objectstore.dir=features/session-persistence/jta diff --git a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/DroolsPersistenceProperties.java b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/DroolsPersistenceProperties.java index 1c935b0c..42a638a0 100644 --- a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/DroolsPersistenceProperties.java +++ b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/DroolsPersistenceProperties.java @@ -27,10 +27,9 @@ public class DroolsPersistenceProperties { * feature-session-persistence.properties parameter key values */ public static final String DB_DRIVER = "javax.persistence.jdbc.driver"; - public static final String DB_DATA_SOURCE = "hibernate.dataSource"; public static final String DB_URL = "javax.persistence.jdbc.url"; public static final String DB_USER = "javax.persistence.jdbc.user"; public static final String DB_PWD = "javax.persistence.jdbc.password"; - public static final String DB_SESSIONINFO_TIMEOUT = - "persistence.sessioninfo.timeout"; + public static final String DB_SESSIONINFO_TIMEOUT = "persistence.sessioninfo.timeout"; + public static final String JTA_OBJECTSTORE_DIR = "persistence.objectstore.dir"; } diff --git a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/DroolsSessionEntity.java b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/DroolsSessionEntity.java index e9c5b33b..b3616c43 100644 --- a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/DroolsSessionEntity.java +++ b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/DroolsSessionEntity.java @@ -35,53 +35,53 @@ import javax.persistence.TemporalType; public class DroolsSessionEntity implements Serializable, DroolsSession { private static final long serialVersionUID = -5495057038819948709L; - + @Id - @Column(name="sessionName", nullable=false) + @Column(name = "sessionName", nullable = false) private String sessionName = "-1"; - - @Column(name="sessionId", nullable=false) + + @Column(name = "sessionId", nullable = false) private long sessionId = -1L; - + @Temporal(TemporalType.TIMESTAMP) - @Column(name="createdDate", nullable=false) + @Column(name = "createdDate", nullable = false) private Date createdDate; - + @Temporal(TemporalType.TIMESTAMP) - @Column(name="updatedDate", nullable=false) + @Column(name = "updatedDate", nullable = false) private Date updatedDate; - - + public DroolsSessionEntity() { - + } - - public DroolsSessionEntity(String sessionName, - long sessionId) { + + public DroolsSessionEntity(String sessionName, long sessionId) { this.sessionName = sessionName; this.sessionId = sessionId; - + } - + @PrePersist - public void prePersist() { + public void prePersist() { this.createdDate = new Date(); this.updatedDate = new Date(); } - + @PreUpdate public void preUpdate() { this.updatedDate = new Date(); } - + @Override public String getSessionName() { return sessionName; } + @Override public void setSessionName(String sessionName) { this.sessionName = sessionName; } + @Override public long getSessionId() { return sessionId; @@ -92,7 +92,7 @@ public class DroolsSessionEntity implements Serializable, DroolsSession { this.sessionId = sessionId; } - @Override + @Override public Date getCreatedDate() { return createdDate; } @@ -112,17 +112,16 @@ public class DroolsSessionEntity implements Serializable, DroolsSession { this.updatedDate = updatedDate; } - @Override - public boolean equals(Object other){ - if(other instanceof DroolsSession){ + public boolean equals(Object other) { + if (other instanceof DroolsSession) { DroolsSession p = (DroolsSession) other; return this.getSessionName().equals(p.getSessionName()); - }else{ + } else { return false; } } - + @Override public int hashCode() { final int prime = 31; @@ -130,12 +129,10 @@ public class DroolsSessionEntity implements Serializable, DroolsSession { result = prime * result + getSessionName().hashCode(); return result; } - + @Override public String toString() { - return "{name=" + getSessionName() - + ", id=" + getSessionId() + "}"; + return "{name=" + getSessionName() + ", id=" + getSessionId() + "}"; } - } diff --git a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/EntityMgrCloser.java b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/EntityMgrCloser.java deleted file mode 100644 index 58292117..00000000 --- a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/EntityMgrCloser.java +++ /dev/null @@ -1,49 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * feature-session-persistence - * ================================================================================ - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.drools.persistence; - -import javax.persistence.EntityManager; - -/** - * Wrapper for an <i>EntityManager</i>, providing auto-close functionality. - */ -public class EntityMgrCloser implements AutoCloseable { - - /** - * The wrapper manager. - */ - private final EntityManager em; - - /** - * - * @param em - * manager to be auto-closed - */ - public EntityMgrCloser(EntityManager em) { - this.em = em; - } - - @Override - public void close() { - em.close(); - } - -} diff --git a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/EntityMgrTrans.java b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/EntityMgrTrans.java index 79b620d3..9bb26ac1 100644 --- a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/EntityMgrTrans.java +++ b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/EntityMgrTrans.java @@ -21,10 +21,18 @@ package org.onap.policy.drools.persistence; import javax.persistence.EntityManager; -import javax.persistence.EntityTransaction; +import javax.transaction.HeuristicMixedException; +import javax.transaction.HeuristicRollbackException; +import javax.transaction.NotSupportedException; +import javax.transaction.RollbackException; +import javax.transaction.Status; +import javax.transaction.SystemException; +import javax.transaction.UserTransaction; + +import org.onap.policy.common.utils.jpa.EntityMgrCloser; /** - * Wrapper for an <i>EntityManager</i> that creates a transaction that is + * Wrapper for an <i>EntityManager</i> that creates a JTA transaction that is * auto-rolled back when closed. */ public class EntityMgrTrans extends EntityMgrCloser { @@ -32,7 +40,7 @@ public class EntityMgrTrans extends EntityMgrCloser { /** * Transaction to be rolled back. */ - private EntityTransaction trans; + private static UserTransaction userTrans = com.arjuna.ats.jta.UserTransaction.userTransaction(); /** * @@ -43,39 +51,94 @@ public class EntityMgrTrans extends EntityMgrCloser { super(em); try { - trans = em.getTransaction(); - trans.begin(); + userTrans.begin(); + em.joinTransaction(); } catch (RuntimeException e) { em.close(); - throw e; + throw new EntityMgrException(e); + + } catch (NotSupportedException | SystemException e) { + em.close(); + throw new EntityMgrException(e); } } /** + * Gets the user transaction. For use by junit tests. + * + * @return the user transaction + */ + protected static UserTransaction getUserTrans() { + return userTrans; + } + + /** + * Sets the user transaction. For use by junit tests. + * + * @param userTrans + * the new user transaction + */ + protected static void setUserTrans(UserTransaction userTrans) { + EntityMgrTrans.userTrans = userTrans; + } + + /** * Commits the transaction. */ public void commit() { - trans.commit(); + try { + userTrans.commit(); + + } catch (SecurityException | IllegalStateException | RollbackException | HeuristicMixedException + | HeuristicRollbackException | SystemException e) { + + throw new EntityMgrException(e); + } } /** * Rolls back the transaction. */ public void rollback() { - trans.rollback(); + try { + userTrans.rollback(); + + } catch (IllegalStateException | SecurityException | SystemException e) { + throw new EntityMgrException(e); + } } @Override public void close() { try { - if (trans.isActive()) { - trans.rollback(); + if (userTrans.getStatus() == Status.STATUS_ACTIVE) { + userTrans.rollback(); } + } catch (IllegalStateException | SecurityException | SystemException e) { + throw new EntityMgrException(e); + } finally { super.close(); } } + /** + * Runtime exceptions generated by this class. Wraps exceptions generated by + * delegated operations, particularly when they are not, themselves, Runtime + * exceptions. + */ + public static class EntityMgrException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * + * @param e + * exception to be wrapped + */ + public EntityMgrException(Exception e) { + super(e); + } + } } diff --git a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/JpaDroolsSessionConnector.java b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/JpaDroolsSessionConnector.java index 76c09681..cd76ae8d 100644 --- a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/JpaDroolsSessionConnector.java +++ b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/JpaDroolsSessionConnector.java @@ -26,14 +26,12 @@ import javax.persistence.EntityManagerFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - public class JpaDroolsSessionConnector implements DroolsSessionConnector { private static Logger logger = LoggerFactory.getLogger(JpaDroolsSessionConnector.class); - + private final EntityManagerFactory emf; - - + public JpaDroolsSessionConnector(EntityManagerFactory emf) { this.emf = emf; } @@ -43,11 +41,11 @@ public class JpaDroolsSessionConnector implements DroolsSessionConnector { EntityManager em = emf.createEntityManager(); DroolsSessionEntity s = null; - - try(EntityMgrTrans trans = new EntityMgrTrans(em)) { - + + try (EntityMgrTrans trans = new EntityMgrTrans(em)) { + s = em.find(DroolsSessionEntity.class, sessName); - if(s != null) { + if (s != null) { em.refresh(s); } @@ -60,57 +58,59 @@ public class JpaDroolsSessionConnector implements DroolsSessionConnector { @Override public void replace(DroolsSession sess) { String sessName = sess.getSessionName(); - + logger.info("replace: Entering and manually updating session name= {}", sessName); - + EntityManager em = emf.createEntityManager(); - - try(EntityMgrTrans trans = new EntityMgrTrans(em)) { - - if( ! update(em, sess)) { + + try (EntityMgrTrans trans = new EntityMgrTrans(em)) { + + if (!update(em, sess)) { add(em, sess); } - + trans.commit(); } - + logger.info("replace: Exiting"); } /** * Adds a session to the persistent store. - * @param em entity manager - * @param sess session to be added + * + * @param em + * entity manager + * @param sess + * session to be added */ private void add(EntityManager em, DroolsSession sess) { logger.info("add: Inserting session id={}", sess.getSessionId()); - DroolsSessionEntity ent = - new DroolsSessionEntity( - sess.getSessionName(), - sess.getSessionId()); - + DroolsSessionEntity ent = new DroolsSessionEntity(sess.getSessionName(), sess.getSessionId()); + em.persist(ent); } - + /** * Updates a session, if it exists within the persistent store. - * @param em entity manager - * @param sess session data to be persisted - * @return {@code true} if a record was updated, {@code false} if it - * was not found + * + * @param em + * entity manager + * @param sess + * session data to be persisted + * @return {@code true} if a record was updated, {@code false} if it was not + * found */ private boolean update(EntityManager em, DroolsSession sess) { - - DroolsSessionEntity s = - em.find(DroolsSessionEntity.class, sess.getSessionName()); - if(s == null) { + + DroolsSessionEntity s = em.find(DroolsSessionEntity.class, sess.getSessionName()); + if (s == null) { return false; } logger.info("update: Updating session id to {}", sess.getSessionId()); - s.setSessionId( sess.getSessionId()); - + s.setSessionId(sess.getSessionId()); + return true; } } diff --git a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/PersistenceFeature.java b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/PersistenceFeature.java index db33d05a..032383b4 100644 --- a/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/PersistenceFeature.java +++ b/feature-session-persistence/src/main/java/org/onap/policy/drools/persistence/PersistenceFeature.java @@ -21,10 +21,7 @@ package org.onap.policy.drools.persistence; import java.io.IOException; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.sql.Connection; -import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.HashMap; @@ -35,8 +32,12 @@ import java.util.concurrent.TimeUnit; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; +import javax.transaction.UserTransaction; -import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.apache.commons.dbcp2.BasicDataSource; +import org.apache.commons.dbcp2.BasicDataSourceFactory; import org.kie.api.KieServices; import org.kie.api.runtime.Environment; import org.kie.api.runtime.EnvironmentName; @@ -52,11 +53,6 @@ import org.onap.policy.drools.utils.PropertyUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import bitronix.tm.BitronixTransactionManager; -import bitronix.tm.Configuration; -import bitronix.tm.TransactionManagerServices; -import bitronix.tm.resource.jdbc.PoolingDataSource; - /** * If this feature is supported, there is a single instance of it. It adds * persistence to Drools sessions. In addition, if an active-standby feature @@ -71,7 +67,6 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine private static final Logger logger = LoggerFactory.getLogger(PersistenceFeature.class); - /** * Standard factory used to get various items. */ @@ -88,11 +83,6 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine private KieServices kieSvcFact; /** - * Host name. - */ - private String hostName; - - /** * Persistence properties. */ private Properties persistProps; @@ -159,10 +149,8 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine */ @Override public void globalInit(String args[], String configDir) { - - kieSvcFact = fact.getKieServices(); - initHostName(); + kieSvcFact = fact.getKieServices(); try { persistProps = fact.loadProperties(configDir + "/feature-session-persistence.properties"); @@ -172,10 +160,6 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine } sessionInfoTimeoutMs = getPersistenceTimeout(); - - Configuration bitronixConfiguration = fact.getTransMgrConfig(); - bitronixConfiguration.setJournal(null); - bitronixConfiguration.setServerId(hostName); } /** @@ -199,6 +183,7 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine */ @Override public PolicySession.ThreadModel selectThreadModel(PolicySession session) { + PolicyContainer policyContainer = session.getPolicyContainer(); if (isPersistenceEnabled(policyContainer, session.getName())) { return new PersistentThreadModel(session, getProperties(policyContainer)); @@ -211,10 +196,10 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine */ @Override public void disposeKieSession(PolicySession policySession) { - + ContainerAdjunct contAdj = (ContainerAdjunct) policySession.getPolicyContainer().getAdjunct(this); - if(contAdj != null) { - contAdj.disposeKieSession( policySession.getName()); + if (contAdj != null) { + contAdj.disposeKieSession(policySession.getName()); } } @@ -225,8 +210,8 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine public void destroyKieSession(PolicySession policySession) { ContainerAdjunct contAdj = (ContainerAdjunct) policySession.getPolicyContainer().getAdjunct(this); - if(contAdj != null) { - contAdj.destroyKieSession( policySession.getName()); + if (contAdj != null) { + contAdj.destroyKieSession(policySession.getName()); } } @@ -291,25 +276,12 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine } catch (NumberFormatException e) { logger.error("Invalid value for Drools persistence property persistence.sessioninfo.timeout: {}", - timeoutString, e); + timeoutString, e); } return -1; } - /** - * Initializes {@link #hostName}. - */ - private void initHostName() { - - try { - hostName = fact.getHostName(); - - } catch (UnknownHostException e) { - throw new RuntimeException("cannot determine local hostname", e); - } - } - /* ============================================================ */ /** @@ -322,11 +294,11 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine * 'PolicyContainer' instance that this adjunct is extending. */ private PolicyContainer policyContainer; - + /** * Maps a KIE session name to its data source. */ - private Map<String,PoolingDataSource> name2ds = new HashMap<>(); + private Map<String, DsEmf> name2ds = new HashMap<>(); /** * Constructor - initialize a new 'ContainerAdjunct' @@ -352,89 +324,48 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine */ private KieSession newPersistentKieSession(String name, String kieBaseName) { - long desiredSessionId; - - DroolsSessionConnector conn = getDroolsSessionConnector("onapPU"); + configureSysProps(); - desiredSessionId = getSessionId(conn, name); + BasicDataSource ds = fact.makeDataSource(getDataSourceProperties()); + DsEmf dsemf = new DsEmf(ds); - logger.info("\n\nThis controller is primary... coming up with session {} \n\n", desiredSessionId); + try { + EntityManagerFactory emf = dsemf.emf; + DroolsSessionConnector conn = fact.makeJpaConnector(emf); - // session does not exist -- attempt to create one - logger.info("getPolicySession:session does not exist -- attempt to create one with name {}", name); + long desiredSessionId = getSessionId(conn, name); - System.getProperties().put("java.naming.factory.initial", "bitronix.tm.jndi.BitronixInitialContextFactory"); + logger.info("\n\nThis controller is primary... coming up with session {} \n\n", desiredSessionId); - Environment env = kieSvcFact.newEnvironment(); - String dsName = loadDataSource(name); + // session does not exist -- attempt to create one + logger.info("getPolicySession:session does not exist -- attempt to create one with name {}", name); - configureKieEnv(name, env, dsName); + Environment env = kieSvcFact.newEnvironment(); - KieSessionConfiguration kConf = kieSvcFact.newKieSessionConfiguration(); + configureKieEnv(env, emf); - KieSession kieSession = desiredSessionId >= 0 ? loadKieSession(kieBaseName, desiredSessionId, env, kConf) - : null; + KieSessionConfiguration kConf = kieSvcFact.newKieSessionConfiguration(); - if (kieSession == null) { - // loadKieSession() returned null or desiredSessionId < 0 - logger.info("LOADING We cannot load session {}. Going to create a new one", desiredSessionId); + KieSession kieSession = (desiredSessionId >= 0 + ? loadKieSession(kieBaseName, desiredSessionId, env, kConf) : null); - kieSession = newKieSession(kieBaseName, env); - } + if (kieSession == null) { + // loadKieSession() returned null or desiredSessionId < 0 + logger.info("LOADING We cannot load session {}. Going to create a new one", desiredSessionId); - replaceSession(conn, name, kieSession); + kieSession = newKieSession(kieBaseName, env); + } - return kieSession; - } + replaceSession(conn, name, kieSession); - /** - * Loads a data source into {@link #name2ds}, if one doesn't exist - * yet. - * @param sessName session name - * @return the unique data source name - */ - private String loadDataSource(String sessName) { - PoolingDataSource ds = name2ds.get(sessName); - - if(ds == null) { - Properties props = new Properties(); - addOptProp(props, "URL", persistProps.getProperty(DroolsPersistenceProperties.DB_URL)); - addOptProp(props, "user", persistProps.getProperty(DroolsPersistenceProperties.DB_USER)); - addOptProp(props, "password", persistProps.getProperty(DroolsPersistenceProperties.DB_PWD)); - - ds = fact.makePoolingDataSource(); - ds.setUniqueName("jdbc/BitronixJTADataSource/" + sessName); - ds.setClassName(persistProps.getProperty(DroolsPersistenceProperties.DB_DATA_SOURCE)); - ds.setMaxPoolSize(3); - ds.setIsolationLevel("SERIALIZABLE"); - ds.setAllowLocalTransactions(true); - ds.getDriverProperties().putAll(props); - ds.init(); - - name2ds.put(sessName, ds); - } - - return ds.getUniqueName(); - } + name2ds.put(name, dsemf); - /** - * Configures a Kie Environment - * - * @param name - * session name - * @param env - * environment to be configured - * @param dsName - * data source name - */ - private void configureKieEnv(String name, Environment env, String dsName) { - Properties emfProperties = new Properties(); - emfProperties.setProperty(PersistenceUnitProperties.JTA_DATASOURCE, dsName); - - EntityManagerFactory emfact = fact.makeEntMgrFact("onapsessionsPU", emfProperties); + return kieSession; - env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emfact); - env.set(EnvironmentName.TRANSACTION_MANAGER, fact.getTransMgr()); + } catch (RuntimeException e) { + dsemf.close(); + throw e; + } } /** @@ -487,7 +418,9 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine /** * Closes the data source associated with a session. - * @param name name of the session being destroyed + * + * @param name + * name of the session being destroyed */ private void destroyKieSession(String name) { closeDataSource(name); @@ -495,7 +428,9 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine /** * Closes the data source associated with a session. - * @param name name of the session being disposed of + * + * @param name + * name of the session being disposed of */ private void disposeKieSession(String name) { closeDataSource(name); @@ -503,11 +438,13 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine /** * Closes the data source associated with a session. - * @param name name of the session whose data source is to be closed + * + * @param name + * name of the session whose data source is to be closed */ private void closeDataSource(String name) { - PoolingDataSource ds = name2ds.remove(name); - if(ds != null) { + DsEmf ds = name2ds.remove(name); + if (ds != null) { ds.close(); } } @@ -516,6 +453,53 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine /* ============================================================ */ /** + * Configures java system properties for JPA/JTA. + */ + private void configureSysProps() { + System.setProperty("com.arjuna.ats.arjuna.coordinator.defaultTimeout", "60"); + System.setProperty("com.arjuna.ats.arjuna.objectstore.objectStoreDir", + persistProps.getProperty(DroolsPersistenceProperties.JTA_OBJECTSTORE_DIR)); + System.setProperty("ObjectStoreEnvironmentBean.objectStoreDir", + persistProps.getProperty(DroolsPersistenceProperties.JTA_OBJECTSTORE_DIR)); + } + + /** + * Gets the data source properties. + * + * @return the data source properties + */ + private Properties getDataSourceProperties() { + Properties props = new Properties(); + props.put("driverClassName", persistProps.getProperty(DroolsPersistenceProperties.DB_DRIVER)); + props.put("url", persistProps.getProperty(DroolsPersistenceProperties.DB_URL)); + props.put("username", persistProps.getProperty(DroolsPersistenceProperties.DB_USER)); + props.put("password", persistProps.getProperty(DroolsPersistenceProperties.DB_PWD)); + props.put("maxActive", "3"); + props.put("maxIdle", "1"); + props.put("maxWait", "120000"); + props.put("whenExhaustedAction", "2"); + props.put("testOnBorrow", "false"); + props.put("poolPreparedStatements", "true"); + + return props; + } + + /** + * Configures a Kie Environment + * + * @param env + * environment to be configured + * @param emf + * entity manager factory + */ + private void configureKieEnv(Environment env, EntityManagerFactory emf) { + env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, emf); + env.set(EnvironmentName.TRANSACTION, fact.getUserTrans()); + env.set(EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY, fact.getTransSyncReg()); + env.set(EnvironmentName.TRANSACTION_MANAGER, fact.getTransMgr()); + } + + /** * Removes "old" Drools 'sessioninfo' records, so they aren't used to * restore data to Drools sessions. This also has the useful side-effect of * removing abandoned records as well. @@ -534,21 +518,15 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine return; } - // get DB connection properties - String url = persistProps.getProperty(DroolsPersistenceProperties.DB_URL); - String user = persistProps.getProperty(DroolsPersistenceProperties.DB_USER); - String password = persistProps.getProperty(DroolsPersistenceProperties.DB_PWD); - - if (url == null || user == null || password == null) { - logger.error("Missing DB properties for clean up of sessioninfo table"); - return; - } - // now do the record deletion - try (Connection connection = fact.makeDbConnection(url, user, password); + try (BasicDataSource ds = fact.makeDataSource(getDataSourceProperties()); + Connection connection = ds.getConnection(); PreparedStatement statement = connection.prepareStatement( "DELETE FROM sessioninfo WHERE timestampdiff(second,lastmodificationdate,now()) > ?")) { - statement.setLong(1, sessionInfoTimeoutMs/1000); + + connection.setAutoCommit(true); + + statement.setLong(1, sessionInfoTimeoutMs / 1000); int count = statement.executeUpdate(); logger.info("Cleaning up sessioninfo table -- {} records removed", count); @@ -565,40 +543,6 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine } /** - * Gets a connector for manipulating DroolsSession objects within the - * persistent store. - * - * @param pu - * @return a connector for DroolsSession objects - */ - private DroolsSessionConnector getDroolsSessionConnector(String pu) { - - Properties propMap = new Properties(); - addOptProp(propMap, "javax.persistence.jdbc.driver", - persistProps.getProperty(DroolsPersistenceProperties.DB_DRIVER)); - addOptProp(propMap, "javax.persistence.jdbc.url", persistProps.getProperty(DroolsPersistenceProperties.DB_URL)); - addOptProp(propMap, "javax.persistence.jdbc.user", - persistProps.getProperty(DroolsPersistenceProperties.DB_USER)); - addOptProp(propMap, "javax.persistence.jdbc.password", - persistProps.getProperty(DroolsPersistenceProperties.DB_PWD)); - - return fact.makeJpaConnector(pu, propMap); - } - - /** - * Adds an optional property to a set of properties. - * @param propMap map into which the property should be added - * @param name property name - * @param value property value, or {@code null} if it should not - * be added - */ - private void addOptProp(Properties propMap, String name, String value) { - if (value != null) { - propMap.put(name, value); - } - } - - /** * Gets a session's ID from the persistent store. * * @param conn @@ -613,8 +557,8 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine } /** - * Replaces a session within the persistent store, if it exists. Adds - * it otherwise. + * Replaces a session within the persistent store, if it exists. Adds it + * otherwise. * * @param conn * persistence connector @@ -665,7 +609,7 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine */ private Properties getProperties(PolicyContainer container) { try { - return fact.getPolicyContainer(container).getProperties(); + return fact.getPolicyController(container).getProperties(); } catch (IllegalArgumentException e) { logger.error("getProperties exception: ", e); return null; @@ -705,7 +649,7 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine * compatible with persistence. */ public class PersistentThreadModel implements Runnable, PolicySession.ThreadModel { - + /** * Session associated with this persistent thread. */ @@ -715,22 +659,22 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine * The session thread. */ private final Thread thread; - + /** * Used to indicate that processing should stop. */ private final CountDownLatch stopped = new CountDownLatch(1); - + /** - * Minimum time, in milli-seconds, that the thread should sleep - * before firing rules again. + * Minimum time, in milli-seconds, that the thread should sleep before + * firing rules again. */ long minSleepTime = 100; - + /** - * Maximum time, in milli-seconds, that the thread should sleep - * before firing rules again. This is a "half" time, so that - * we can multiply it by two without overflowing the word size. + * Maximum time, in milli-seconds, that the thread should sleep before + * firing rules again. This is a "half" time, so that we can multiply it + * by two without overflowing the word size. */ long halfMaxSleepTime = 5000L / 2L; @@ -745,11 +689,11 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine public PersistentThreadModel(PolicySession session, Properties properties) { this.session = session; this.thread = new Thread(this, getThreadName()); - + if (properties == null) { return; } - + // extract 'minSleepTime' and/or 'maxSleepTime' String name = session.getName(); @@ -782,8 +726,8 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine minSleepTime = maxSleepTime; maxSleepTime = tmp; } - - halfMaxSleepTime = Math.max(1, maxSleepTime/2); + + halfMaxSleepTime = Math.max(1, maxSleepTime / 2); } /** @@ -812,18 +756,18 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine public void stop() { // tell the thread to stop stopped.countDown(); - + // wait up to 10 seconds for the thread to stop try { thread.join(10000); - + } catch (InterruptedException e) { logger.error("stopThread exception: ", e); Thread.currentThread().interrupt(); } - + // verify that it's done - if(thread.isAlive()) { + if (thread.isAlive()) { logger.error("stopThread: still running"); } } @@ -847,7 +791,7 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine @Override public void run() { logger.info("PersistentThreadModel running"); - + // set thread local variable session.setPolicySession(); @@ -856,33 +800,34 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine // We want to continue, despite any exceptions that occur // while rules are fired. - - for(;;) { - + + for (;;) { + try { if (kieSession.fireAllRules() > 0) { // some rules fired -- reduce poll delay - sleepTime = Math.max(minSleepTime, sleepTime/2); + sleepTime = Math.max(minSleepTime, sleepTime / 2); } else { // no rules fired -- increase poll delay sleepTime = 2 * Math.min(halfMaxSleepTime, sleepTime); } + } catch (Exception | LinkageError e) { logger.error("Exception during kieSession.fireAllRules", e); - } - + } + try { - if(stopped.await(sleepTime, TimeUnit.MILLISECONDS)) { + if (stopped.await(sleepTime, TimeUnit.MILLISECONDS)) { break; } - + } catch (InterruptedException e) { logger.error("startThread exception: ", e); Thread.currentThread().interrupt(); break; } } - + logger.info("PersistentThreadModel completed"); } } @@ -890,46 +835,104 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine /* ============================================================ */ /** - * Factory for various items. Methods can be overridden for junit testing. + * DataSource-EntityManagerFactory pair. */ - protected static class Factory { + private class DsEmf { + private BasicDataSource bds; + private EntityManagerFactory emf; /** - * Gets the configuration for the transaction manager. + * Makes an entity manager factory for the given data source. * - * @return the configuration for the transaction manager + * @param bds + * pooled data source + */ + public DsEmf(BasicDataSource bds) { + try { + Map<String, Object> props = new HashMap<>(); + props.put(org.hibernate.cfg.Environment.JPA_JTA_DATASOURCE, bds); + + this.bds = bds; + this.emf = fact.makeEntMgrFact(props); + + } catch (RuntimeException e) { + closeDataSource(); + throw e; + } + } + + /** + * Closes the entity manager factory and the data source. */ - public Configuration getTransMgrConfig() { - return TransactionManagerServices.getConfiguration(); + public void close() { + try { + emf.close(); + + } catch (RuntimeException e) { + closeDataSource(); + throw e; + } + + closeDataSource(); } /** + * Closes the data source only. + */ + private void closeDataSource() { + try { + bds.close(); + + } catch (SQLException e) { + throw new PersistenceFeatureException(e); + } + + } + } + + private static class SingletonRegistry { + private static final TransactionSynchronizationRegistry transreg = new com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple(); + } + + /** + * Factory for various items. Methods can be overridden for junit testing. + */ + protected static class Factory { + + /** * Gets the transaction manager. * * @return the transaction manager */ - public BitronixTransactionManager getTransMgr() { - return TransactionManagerServices.getTransactionManager(); + public TransactionManager getTransMgr() { + return com.arjuna.ats.jta.TransactionManager.transactionManager(); } /** - * Gets the KIE services. + * Gets the user transaction. * - * @return the KIE services + * @return the user transaction */ - public KieServices getKieServices() { - return KieServices.Factory.get(); + public UserTransaction getUserTrans() { + return com.arjuna.ats.jta.UserTransaction.userTransaction(); } /** - * Gets the current host name. + * Gets the transaction synchronization registry. * - * @return the current host name, associated with the IP address of the - * local machine - * @throws UnknownHostException + * @return the transaction synchronization registry */ - public String getHostName() throws UnknownHostException { - return InetAddress.getLocalHost().getHostName(); + public TransactionSynchronizationRegistry getTransSyncReg() { + return SingletonRegistry.transreg; + } + + /** + * Gets the KIE services. + * + * @return the KIE services + */ + public KieServices getKieServices() { + return KieServices.Factory.get(); } /** @@ -946,58 +949,41 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine } /** - * Makes a connection to the DB. + * Makes a Data Source. * - * @param url - * DB URL - * @param user - * user name - * @param pass - * password - * @return a new DB connection - * @throws SQLException + * @param dsProps + * data source properties + * @return a new data source */ - public Connection makeDbConnection(String url, String user, String pass) throws SQLException { - - return DriverManager.getConnection(url, user, pass); - } + public BasicDataSource makeDataSource(Properties dsProps) { + try { + return BasicDataSourceFactory.createDataSource(dsProps); - /** - * Makes a new pooling data source. - * - * @return a new pooling data source - */ - public PoolingDataSource makePoolingDataSource() { - return new PoolingDataSource(); + } catch (Exception e) { + throw new PersistenceFeatureException(e); + } } /** * Makes a new JPA connector for drools sessions. * - * @param pu - * PU for the entity manager factory - * @param propMap - * properties with which the factory should be configured + * @param emf + * entity manager factory * @return a new JPA connector for drools sessions */ - public DroolsSessionConnector makeJpaConnector(String pu, Properties propMap) { - - EntityManagerFactory emf = makeEntMgrFact(pu, propMap); - + public DroolsSessionConnector makeJpaConnector(EntityManagerFactory emf) { return new JpaDroolsSessionConnector(emf); } /** * Makes a new entity manager factory. * - * @param pu - * PU for the entity manager factory - * @param propMap + * @param props * properties with which the factory should be configured * @return a new entity manager factory */ - public EntityManagerFactory makeEntMgrFact(String pu, Properties propMap) { - return Persistence.createEntityManagerFactory(pu, propMap); + public EntityManagerFactory makeEntMgrFact(Map<String, Object> props) { + return Persistence.createEntityManagerFactory("onapsessionsPU", props); } /** @@ -1007,8 +993,26 @@ public class PersistenceFeature implements PolicySessionFeatureAPI, PolicyEngine * container whose controller is to be retrieved * @return the container's controller */ - public PolicyController getPolicyContainer(PolicyContainer container) { + public PolicyController getPolicyController(PolicyContainer container) { return PolicyController.factory.get(container.getGroupId(), container.getArtifactId()); } } + + /** + * Runtime exceptions generated by this class. Wraps exceptions generated by + * delegated operations, particularly when they are not, themselves, Runtime + * exceptions. + */ + public static class PersistenceFeatureException extends RuntimeException { + private static final long serialVersionUID = 1L; + + /** + * + * @param e + * exception to be wrapped + */ + public PersistenceFeatureException(Exception e) { + super(e); + } + } } diff --git a/feature-session-persistence/src/main/resources/META-INF/persistence.xml b/feature-session-persistence/src/main/resources/META-INF/persistence.xml index 7ddd2fd3..6b8345c3 100644 --- a/feature-session-persistence/src/main/resources/META-INF/persistence.xml +++ b/feature-session-persistence/src/main/resources/META-INF/persistence.xml @@ -23,20 +23,10 @@ xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> - <persistence-unit name="onapPU" transaction-type="RESOURCE_LOCAL"> - <!-- This is for database access by non-drools methods --> - <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> - <class>org.onap.policy.drools.persistence.DroolsSessionEntity</class> - <class>org.drools.persistence.info.SessionInfo</class> - <class>org.drools.persistence.info.WorkItemInfo</class> - <properties> - <!-- Properties are passed in --> - </properties> - </persistence-unit> - <persistence-unit name="onapsessionsPU" transaction-type="JTA"> <!-- Used for drools session data access --> - <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> + <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> + <class>org.onap.policy.drools.persistence.DroolsSessionEntity</class> <class>org.drools.persistence.info.SessionInfo</class> <class>org.drools.persistence.info.WorkItemInfo</class> <properties> @@ -44,18 +34,19 @@ <property name="hibernate.max_fetch_depth" value="3" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="false" /> - <property name="hibernate.transaction.manager_lookup_class" - value="org.hibernate.transaction.BTMTransactionManagerLookup" /> + <property name="hibernate.transaction.factory_class" value="org.hibernate.transaction.JTATransactionFactory" /> + <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup" /> </properties> </persistence-unit> <persistence-unit name="schemaDroolsPU" transaction-type="RESOURCE_LOCAL"> <!-- Limited use for generating the DB and schema files for drools DB - uses eclipselink for convenience --> - <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> + <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <class>org.onap.policy.drools.persistence.DroolsSessionEntity</class> <class>org.drools.persistence.info.SessionInfo</class> <class>org.drools.persistence.info.WorkItemInfo</class> <properties> + <property name="hibernate.dialect" value="org.hibernate.dialect.MariaDBDialect" /> <property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/> <property name="javax.persistence.schema-generation.scripts.create-target" value="sql/generatedCreateDrools.ddl"/> <property name="javax.persistence.schema-generation.scripts.drop-target" value="sql/generatedDropDrools.ddl"/> |