/*
* Copyright 2011 Red Hat Inc.
*
* 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.
*/
package org.drools.persistence.util;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Properties;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import org.drools.core.base.MapGlobalResolver;
import org.drools.core.impl.EnvironmentFactory;
import org.infinispan.AdvancedCache;
import org.infinispan.manager.DefaultCacheManager;
import org.kie.api.KieBase;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.EnvironmentName;
import org.kie.api.runtime.KieSessionConfiguration;
import org.kie.internal.KnowledgeBaseFactory;
import org.kie.internal.persistence.jpa.JPAKnowledgeService;
import org.kie.internal.runtime.StatefulKnowledgeSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import bitronix.tm.BitronixTransactionManager;
import bitronix.tm.TransactionManagerServices;
public class PersistenceUtil {
private static Logger logger = LoggerFactory.getLogger( PersistenceUtil.class );
private static boolean TEST_MARSHALLING = true;
// Persistence and data source constants
public static final String DROOLS_PERSISTENCE_UNIT_NAME = "drools-configured-cache";
public static final String JBPM_PERSISTENCE_UNIT_NAME = "jbpm-configured-cache";
protected static final String DATASOURCE_PROPERTIES = "/datasource.properties";
// Setup and marshalling setup constants
public static String DATASOURCE = "org.droolsjbpm.persistence.datasource";
/**
* @see #setupWithPoolingDataSource(String, String, boolean)
* @param persistenceUnitName The name of the persistence unit to be used.
* @return test context
*/
public static HashMap<String, Object> setupWithPoolingDataSource(String persistenceUnitName) {
return setupWithPoolingDataSource(persistenceUnitName, true);
}
/**
* @see #setupWithPoolingDataSource(String, String, boolean)
* @param persistenceUnitName The name of the persistence unit to be used.
* @return test context
*/
public static HashMap<String, Object> setupWithPoolingDataSource(String persistenceUnitName, boolean testMarshalling) {
HashMap<String, Object> context = new HashMap<String, Object>();
// set the right jdbc url
Properties dsProps = getDatasourceProperties();
Object testMarshallingProperty = dsProps.get("testMarshalling");
if( "true".equals(testMarshallingProperty) ) {
TEST_MARSHALLING = true;
if( !testMarshalling ) {
TEST_MARSHALLING = false;
}
}
else {
TEST_MARSHALLING = false;
}
if( TEST_MARSHALLING ) {
Class<?> testClass = null;
StackTraceElement [] ste = Thread.currentThread().getStackTrace();
int i = 1;
do {
try {
testClass = Class.forName(ste[i++].getClassName());
} catch (ClassNotFoundException e) {
// do nothing..
}
} while ( PersistenceUtil.class.equals(testClass) && i < ste.length );
assertNotNull("Unable to resolve test class!", testClass);
}
// Setup persistence
try {
DefaultCacheManager cm = new DefaultCacheManager("infinispan.xml");
AdvancedCache<?, ?> ac = cm.getCache("jbpm-configured-cache").getAdvancedCache();
if (TEST_MARSHALLING) {
try {
UserTransaction ut = (UserTransaction) ac.getTransactionManager().getTransaction();
context.put(EnvironmentName.TRANSACTION, ut);
//cm.start();
} catch (SystemException e) {
//TODO
}
context.put(EnvironmentName.TRANSACTION_SYNCHRONIZATION_REGISTRY, TransactionManagerServices.getTransactionSynchronizationRegistry());
}
context.put(EnvironmentName.ENTITY_MANAGER_FACTORY, cm);
} catch (IOException e) {
//TODO
}
return context;
}
/**
* Please use {@link #cleanUp(HashMap)} because tearDown() ends up conflicting with Junit methods at times.
* @see {@link PersistenceUtil#cleanUp(HashMap)}
*/
@Deprecated
public static void tearDown(HashMap<String, Object> context) {
cleanUp(context);
}
/**
* This method should be called in the @After method of a test to clean up
* the persistence unit and datasource.
*
* @param context
* A HashMap generated by
* {@link org.kie.api.persistence.util.PersistenceUtil setupWithPoolingDataSource(String)}
*
*/
public static void cleanUp(HashMap<String, Object> context) {
if (context != null) {
BitronixTransactionManager txm = TransactionManagerServices.getTransactionManager();
if( txm != null ) {
txm.shutdown();
}
Object cmObject = context.remove(EnvironmentName.ENTITY_MANAGER_FACTORY);
if (cmObject != null) {
try {
DefaultCacheManager cm = (DefaultCacheManager) cmObject;
//cm.stop();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
/**
* This reads in the (maven filtered) datasource properties from the test
* resource directory.
*
* @return Properties containing the datasource properties.
*/
public static Properties getDatasourceProperties() {
String propertiesNotFoundMessage = "Unable to load datasource properties [" + DATASOURCE_PROPERTIES + "]";
// Central place to set additional H2 properties
System.setProperty("h2.lobInDatabase", "true");
InputStream propsInputStream = PersistenceUtil.class.getResourceAsStream(DATASOURCE_PROPERTIES);
assertNotNull(propertiesNotFoundMessage, propsInputStream);
Properties props = new Properties();
if (propsInputStream != null) {
try {
props.load(propsInputStream);
} catch (IOException ioe) {
logger.warn("Unable to find properties, using default H2 properties: " + ioe.getMessage());
ioe.printStackTrace();
}
}
return props;
}
/**
* Reflection method when doing ugly hacks in tests.
*
* @param fieldname
* The name of the field to be retrieved.
* @param source
* The object containing the field to be retrieved.
* @return The value (object instance) stored in the field requested from
* the given source object.
*/
public static Object getValueOfField(String fieldname, Object source) {
String sourceClassName = source.getClass().getSimpleName();
Field field = null;
try {
field = source.getClass().getDeclaredField(fieldname);
field.setAccessible(true);
} catch (SecurityException e) {
fail("Unable to retrieve " + fieldname + " field from " + sourceClassName + ": " + e.getCause());
} catch (NoSuchFieldException e) {
fail("Unable to retrieve " + fieldname + " field from " + sourceClassName + ": " + e.getCause());
}
assertNotNull("." + fieldname + " field is null!?!", field);
Object fieldValue = null;
try {
fieldValue = field.get(source);
} catch (IllegalArgumentException e) {
fail("Unable to retrieve value of " + fieldname + " from " + sourceClassName + ": " + e.getCause());
} catch (IllegalAccessException e) {
fail("Unable to retrieve value of " + fieldname + " from " + sourceClassName + ": " + e.getCause());
}
return fieldValue;
}
public static Environment createEnvironment(HashMap<String, Object> context) {
Environment env = EnvironmentFactory.newEnvironment();
UserTransaction ut = (UserTransaction) context.get(EnvironmentName.TRANSACTION);
if( ut != null ) {
env.set( EnvironmentName.TRANSACTION, ut);
}
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, context.get(EnvironmentName.ENTITY_MANAGER_FACTORY) );
TransactionManager tm = TransactionManagerServices.getTransactionManager();
env.set( EnvironmentName.TRANSACTION_MANAGER, tm );
env.set( EnvironmentName.GLOBALS, new MapGlobalResolver() );
return env;
}
public static StatefulKnowledgeSession createKnowledgeSessionFromKBase(KieBase kbase, HashMap<String, Object> context) {
KieSessionConfiguration ksconf = KnowledgeBaseFactory.newKnowledgeSessionConfiguration();
StatefulKnowledgeSession knowledgeSession = JPAKnowledgeService.newStatefulKnowledgeSession(kbase, ksconf, createEnvironment(context));
return knowledgeSession;
}
}