Tomcat Multiple Datasources with decrypt password logic - java

I am facing some issues with while working with multiple datasources in Tomcat environment. Please find the details below.
I have below 2 datasources in my tomcat/conf/server.xml file
Data Source1:
<Resource name="myds1"
global="myds1"
auth="Container"
type="javax.sql.DataSource"
factory="com.tomcat.datasorceEncrypt.EncryptedDataSourceFactory"
driverClassName="oracle.jdbc.driver.OracleDriver"
singleton = "false"/>
Data Source2:
<Resource name="myds2"
global="myds2"
auth="Container"
type="javax.sql.DataSource"
factory="com.tomcat.datasorceEncrypt.EncryptedDataSourceFactory"
driverClassName="com.ibm.db2.jcc.DB2Driver"
singleton = "false"/>
Here is my EncryptedDataSourceFactory file which extends DataSourceFactory:
package com.tomcat.datasorceEncrypt;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Properties;
import java.util.stream.Stream;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.sql.DataSource;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.jdbc.pool.DataSourceFactory;
import org.apache.tomcat.jdbc.pool.PoolConfiguration;
import org.apache.tomcat.jdbc.pool.XADataSource;
public class EncryptedDataSourceFactory extends DataSourceFactory {
private static final Log log = LogFactory.getLog(EncryptedDataSourceFactory.class);
private static final String PROP_DIALECT = "dialect";
private static final String[] CUSTOM_PROPERTIES = new String[]{PROP_DIALECT};
private static final String[] PROPERTIES = Stream.of(ALL_PROPERTIES, CUSTOM_PROPERTIES).flatMap(Stream::of).toArray(String[]::new);
#Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
throws Exception {
if (obj != null && obj instanceof Reference) {
Reference ref = (Reference) obj;
Properties properties = new Properties();
for (int i = 0; i < PROPERTIES.length; ++i) {
String propertyName = PROPERTIES[i];
RefAddr ra = ref.get(propertyName);
if (ra != null) {
String propertyValue = ra.getContent().toString();
properties.setProperty(propertyName, propertyValue);
}
}
return this.createDataSource(properties, nameCtx,false);
} else {
return null;
}
}
#Override
public DataSource createDataSource(Properties properties, Context context, boolean XA) throws Exception {
// Here we decrypt our password.
PoolConfiguration poolProperties = parsePoolProperties(properties);
Properties dbProperties = loadProperties();
poolProperties.setPassword(CryptoUtility.decryptDBPass(dbProperties.getProperty("DB_key"), dbProperties.getProperty("DB_password")));
poolProperties.setUsername(dbProperties.getProperty("DB_username"));
poolProperties.setUrl(dbProperties.getProperty("DB_url"));
System.out.println(poolProperties.getPoolName() + "****-------*****" + poolProperties.getName() );
System.out.println(poolProperties.getDataSourceJNDI() + "****------***" + poolProperties.getDataSource());
// The rest of the code is copied from Tomcat's DataSourceFactory.
if (poolProperties.getDataSourceJNDI() != null && poolProperties.getDataSource() == null) {
performJNDILookup(context, poolProperties);
}
org.apache.tomcat.jdbc.pool.DataSource dataSource = XA ? new XADataSource(poolProperties)
: new org.apache.tomcat.jdbc.pool.DataSource(poolProperties);
dataSource.createPool();
return dataSource;
}
private Properties loadProperties() {
Properties prop = new Properties();
try {
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("DBPassword.properties");
prop.load(inputStream);
}catch (Exception e) {
log.fatal("Error Loading the properties.", e);
throw new RuntimeException(e);
}
return prop;
}
}
I was trying to identify the datasource JNDI name from poolProperties.getDataSourceJNDI() so that I can apply proper credentials through my properties, but I am receiving poolProperties.getDataSourceJNDI() as null.
Have I missed any property in the Resource while creating datasource?
Note: While working with resource I could able to set user name and password though I have got poolProperties.getDataSourceJNDI() is null.

For timebeeing I have created one more class by extending DatasourceFactory for second datasource, it's working but I don't think it's an Idle solution.

In the routine, getObjectInstance, the parameter name can be used for this.
Based on the name, the decrypt method can be called for different data sources.
I had 8 datasources defined. I used this approach so that I just use one DataSourcefactory class.

Related

Custom ConfigSource for Quarkus

I'm trying now to configure custom ConfigSource in my Quarkus App. Like in many other manuals i'm created my own DatabaseSourceConfig and implements org.eclipse.microprofile.config.spi.ConfigSource interface.I registered my ConfigSource in:
/META-INF/services/org.eclipse.microprofile.config.spi.ConfigSource
There is my ConfigSource:
public class DatabaseConfigSource implements ConfigSource {
private DataSource dataSource;
public DatabaseConfigSource() {
try {
dataSource = (DataSource) new InitialContext().lookup("openejb:Resource/config-source-database");
} catch (final NamingException e) {
throw new IllegalStateException(e);
}
}
#Override
public Map<String, String> getProperties() {
// Implementing Method
}
#Override
public String getValue(final String propertyName) {
// Implementing Method
}
#Override
public String getName() {
return DatabaseConfigSource.class.getSimpleName();
}
}
But this not working for Quarkus because of JNDI name. I need to use CDI. I was trying to use something like this:
#Inject
#io.quarkus.agroal.DataSource("my_connection")
AgroalDataSource usersDataSource;
and declare this connection in application.properties but it didn't help me. I'm getting all the time NULL Exception.
Maybe someone have ideas, how can i get DB connection there without to use JNDI namespace?
You can obtain the data source via
AgroalDataSource dataSource = Arc.container()
.instance(AgroalDataSource.class, new DataSource.DataSourceLiteral("my_connection"))
.get();
You'll need to do this somewhere else than the constructor though, I think, because the ConfigSource instance is created before CDI is fully booted. You can cache the obtained data source instance then to avoid executing this multiple times.
I found some answer myself, maybe it will be useful also for other ppl.
Like #Janmartiška said, CDI booted later, than ConfigSource, that's why i don't see any way to inject my connection via CDI.
I was created some HibernateUtil Class:
package org.myproject.config;
import java.util.Properties;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.myproject.entities.ConfigurationsEntity;
public class HibernateUtil {
private static SessionFactory sessionFactory;
private static SessionFactory buildSessionFactory() {
try {
Properties props = new Properties();
props.setProperty("hibernate.connection.url", "jdbc:mysql://[db-host]:[db-port]/db_name");
props.setProperty("hibernate.connection.driver_class", "com.mysql.cj.jdbc.Driver");
props.setProperty("hibernate.connection.username", "username");
props.setProperty("hibernate.connection.password", "password");
props.setProperty("hibernate.current_session_context_class", "thread");
props.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL8Dialect");
Configuration configuration = new Configuration();
configuration.addProperties(props);
configuration.addAnnotatedClass(ConfigurationsEntity.class);
System.out.println("Hibernate Configuration loaded");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
System.out.println("Hibernate serviceRegistry created");
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
if(sessionFactory == null) sessionFactory = buildSessionFactory();
return sessionFactory;
}
}
than i used it in my SourceConfig:
package org.myproject.config;
import io.quarkus.runtime.annotations.RegisterForReflection;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.myproject.entities.ConfigurationsEntity;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
#RegisterForReflection
public class DatabaseSourceConfig implements ConfigSource {
public SessionFactory sessionFactory;
public Session currentSession;
public DatabaseSourceConfig() {
sessionFactory = HibernateUtil.getSessionFactory();
this.checkFactoryConnection();
}
public void checkFactoryConnection() {
if (currentSession == null || (currentSession != null && !currentSession.isOpen())) {
try {
currentSession = sessionFactory.getCurrentSession();
} catch (NullPointerException e) {
currentSession = sessionFactory.openSession();
}
}
}
#Override
public Map<String, String> getProperties() {
// Implementing Method
}
#Override
public String getValue(String propertyName) {
this.checkFactoryConnection();
ConfigurationsEntity conf = new ConfigurationsEntity();
currentSession.beginTransaction();
try {
Query query = currentSession.createNamedQuery("Configuration.selectOne", ConfigurationsEntity.class);
query.setParameter("name", propertyName);
conf = (ConfigurationsEntity) query.getSingleResult();
currentSession.getTransaction().commit();
} catch (Exception ex) {
currentSession.getTransaction().rollback();
}
return conf.getValue();
}
#Override
public String getName() {
return DatabaseSourceConfig.class.getSimpleName();
}
}
Now i can use my ConfigSource in other classes like:
#Inject
#ConfigProperty(name = "[property-name-like-in-db]")
public String someProperty;
After my further research it was found that ConfigSource has no access to CDi and application.properties. That is why there is nothing left but to establish a connection to the database in the manner described above.
However, I did a little editing of the example. I cached properties from the database and created a #ApplicationScoped Bean that looks into the database once every 5 minutes to see whether one of properties "updated_at" has a timestamp later than others from Bean loaded properties.
However, I have to say that according to Quarkus and Apache developers - this violates “immutable deployment” and is not planned to change the application settings during runtime. So it depends on you whether you write it in the app or not.

Spring Boot #Value is not being populated..why?

I am trying to get a value from my application.properties in Spring Boot using #Value but no matter what I do it is always null.
I am doing this in my HTTPClient test class. I have tried using environment variables, propertySource, PostConstruct, using getters and setters, and anything else I could find online but it does not seem to be populating at all... My test class is in src/test/java and the application.properties is in src/test/resources. I do also have a application.properties in my src/main/java but that is in a completely different folder so it should not be affecting it.
Here is my code:
import static org.junit.Assert.*;
import java.io.IOException;
import java.util.Map;
import javax.annotation.PostConstruct;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ConfigurableApplicationContext;
import com.google.gson.Gson;
import com.nulogix.billing.configuration.EndPointTestConfiguration;
import com.nulogix.billing.mockserver.MockServerApp;
#SpringBootTest(classes = EndPointTestConfiguration.class)
public class HttpClientTest {
#Value("${billing.engine.address}")
private String billingEngineAddress;
#Value("${billing.engine.port}")
private String billingEnginePort;
#PostConstruct
private void customInit() {
System.out.print(billingEngineAddress);
System.out.print(billingEnginePort);
}
public static final String request_bad = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|";
public static final String request_good = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|-123|-123|-123|0.0|0.0|0.0|0.0|0.0|0.0|0.0";
#Test
public void test_bad() throws ClientProtocolException, IOException {
// missing parameter
String result = Request.Post("http://" + billingEngineAddress + ":" + billingEnginePort)
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_bad, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, false);
String errorMessage = (String) resultJsonObj.get("errorMessage");
assertEquals(errorMessage.contains("Payload has incorrect amount of parts"), true);
}
#Test
public void test_good() throws ClientProtocolException, IOException {
String result = Request.Post("http://" + billingEngineAddress + ":" + billingEnginePort)
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_good, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), false);
assertEquals(resultJsonObj.containsKey("HasCopay"), true);
assertEquals(resultJsonObj.containsKey("CopayAmount"), true);
assertEquals(resultJsonObj.containsKey("HasCoinsurance"), true);
assertEquals(resultJsonObj.containsKey("CoinsuranceAmount"), true);
assertEquals(resultJsonObj.containsKey("version"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, true);
String version = (String) resultJsonObj.get("version");
assertEquals(version, "0.97");
}
}
I am getting the values from my application.properties to get the IP address and port and test my Request.post.
Here is my application.properties
server.port=9119
server.ssl.enabled=false
logging.config=classpath:logback-spring.xml
logging.file=messages
logging.file.max-size=50MB
logging.level.com.nulogix=DEBUG
billing.engine.address=127.0.0.1
billing.engine.port=9119
billing.engine.api.version=0.97
billing.engine.core.name=Patient_Responsibility
So what solved my issue is copying over the application.properties from my main to my test/resources. I then used #PropertySource to change the value to test.properties, separating it from application.properties in main. I created a bean of values in my endpoint config and then auto wired it into my httpclient test class.
I also added in web environment in my SpringBootTest annotation to use the defined port in test.properties and to run the test with my endpoint config class and main app class. This caused the #value strings to be populated and not be null.
#Configuration
public class EndPointTestConfiguration {
#Value("${billing.engine.address}")
private String mockServerIP;
#Value("${billing.engine.port}")
private String mockServerPort;
#Bean
public String mockAddress() {
String mockServerAddress = "http://" + mockServerIP + ":" + mockServerPort;
return mockServerAddress;
}
#Bean
public GetVersionEndPoint getVersionEndPoint() {
return new GetVersionEndPoint();
}
#Bean
public AnalyzeEndPoint analyzeEndPoint() throws JAXBException {
return new AnalyzeEndPoint();
}
#Bean
public PredictionEngineService predictionEngineService() {
return new PredictionEngineService();
}
#Bean
public String studyDetailDemo() throws IOException {
File file = ResourceUtils.getFile("src/test/resources/study-details-demo.txt");
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
#Bean
public String studyDetailSampleNormal() throws IOException {
File file = ResourceUtils.getFile("src/test/resources/study-details-normal.txt");
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
#Bean
public String studyDetailSampleCms() throws IOException {
File file = ResourceUtils.getFile("src/test/resources/study-details-cms.txt");
String content = new String(Files.readAllBytes(file.toPath()));
return content;
}
}
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT,classes = {EndPointTestConfiguration.class,MockServerApp.class
})
#PropertySource(value={"classpath:test.properties"}, ignoreResourceNotFound = true)
public class HttpClientTest {
#Autowired
private String mockAddress;
public static final String request_bad = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|";
public static final String request_good = "ncs|56-2629193|1972-03-28|20190218|77067|6208|3209440|self|-123|-123|-123|0.0|0.0|0.0|0.0|0.0|0.0|0.0";
#Test
public void test_bad() throws ClientProtocolException, IOException {
// missing parameter
String result = Request.Post(mockAddress)
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_bad, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, false);
String errorMessage = (String) resultJsonObj.get("errorMessage");
assertEquals(errorMessage.contains("Payload has incorrect amount of parts"), true);
}
#Test
public void test_good() throws ClientProtocolException, IOException {
String result = Request.Post(mockAddress)
.connectTimeout(2000)
.socketTimeout(2000)
.bodyString(request_good, ContentType.TEXT_PLAIN)
.execute().returnContent().asString();
Map<?, ?> resultJsonObj = new Gson().fromJson(result, Map.class);
// ensure the key exists
assertEquals(resultJsonObj.containsKey("status"), true);
assertEquals(resultJsonObj.containsKey("errorMessage"), false);
assertEquals(resultJsonObj.containsKey("HasCopay"), true);
assertEquals(resultJsonObj.containsKey("CopayAmount"), true);
assertEquals(resultJsonObj.containsKey("HasCoinsurance"), true);
assertEquals(resultJsonObj.containsKey("CoinsuranceAmount"), true);
assertEquals(resultJsonObj.containsKey("version"), true);
// validate values
Boolean status = (Boolean) resultJsonObj.get("status");
assertEquals(status, true);
String version = (String) resultJsonObj.get("version");
assertEquals(version, "0.97");
}
}
You need to move your application.properties to src/test/resource folder. For test, spring load application properties from this path.
You can do as follows :
#RunWith(SpringRunner.class)
#SpringBootTest(classes={Application.class})
public class HttpClientTest {
.............
.................
}

EJB MDB listening through JCA adapter failing on starting

I am writing this MDB which will listen message on IBM MQ queues and onMessage it will make call to ilrsession for running jrules. JCA adapter
and Activation config is configured on WAS console
While starting this MDB throws the following error. Is it the static block which is why its failing.
I am posting here if something can review the code and provide some suggestions.
Here is the exception I get while starting the MDB.
An operation in the enterprise bean constructor failed. It is recommended that component initialization logic be placed in a PostConstruct method instead of the bean class no-arg constructor.; nested exception is:
java.lang.NullPointerException
at com.ibm.ws.ejbcontainer.runtime.SharedEJBRuntimeImpl.startBean(SharedEJBRuntimeImpl.java:620)
at com.ibm.ws.runtime.component.WASEJBRuntimeImpl.startBean(WASEJBRuntimeImpl.java:586)
at com.ibm.ws.ejbcontainer.runtime.AbstractEJBRuntime.fireMetaDataCreatedAndStartBean(AbstractEJBRuntime.java:1715)
at com.ibm.ws.ejbcontainer.runtime.AbstractEJBRuntime.startModule(AbstractEJBRuntime.java:667)
... 52 more
Caused by: java.lang.NullPointerException
Here is the MDB Code.
package com.abc.integration.ejb
import ilog.rules.res.model.IlrPath;
import ilog.rules.res.session.IlrEJB3SessionFactory;
import ilog.rules.res.session.IlrSessionException;
import ilog.rules.res.session.IlrSessionRequest;
import ilog.rules.res.session.IlrSessionResponse;
import ilog.rules.res.session.IlrStatelessSession;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
/**
* Message-Driven Bean implementation class for: DecisionServiceMDB
*
*/
#MessageDriven(activationConfig = { #ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class DecisionServiceMDB implements MessageListener
{
/**
* default serial version id
*/
private static final long serialVersionUID = 2300836924029589692L;
private static final Logger responseTimeLogger = Logger.getLogger(PropertyManager.getResponseTimeLogger());
private static final Logger errorLogger = Logger.getLogger(PropertyManager.getErrorLogger());
private static final Logger ruleExceptionLogger = Logger.getLogger(PropertyManager.getRuleExceptionLogger());
private static final String RULEAPP_NAME = PropertyManager.getRuleAppName();
private static final String RULESET_NAME = PropertyManager.getRuleSetName();
private static InitialContext ic;
private static ConnectionFactory cf;
private static Destination destination;
private static String qcfLookup = PropertyManager.getQueueFactoryJndiName();
private static String qLookup = PropertyManager.getQueueDestinationJndiName();
private Connection c = null;
private Session s = null;
private MessageProducer mp = null;
private boolean isInitializedOkay = true;
private static IlrEJB3SessionFactory factory;
private static IlrStatelessSession ruleSession;
private static IlrPath path;
private IlrSessionRequest sessionRequest;
static {
URL url = Thread.currentThread().getContextClassLoader().getResource("log4j.xml");
DOMConfigurator.configure(url);
errorLogger.info("log4j xml initialized::::::::::::::::");
}
public DecisionServiceMDB() throws NamingException, JMSException
{
try
{
if (ic == null)
{
ic = new InitialContext();
}
if (cf == null)
{
cf = (ConnectionFactory) ic.lookup(qcfLookup);
}
if (destination == null)
{
destination = (Destination) ic.lookup(qLookup);
}
} catch (NamingException e)
{
isInitializedOkay = false;
errorLogger.error("FATAL:NamingException Occurred: " + e.getMessage());
errorLogger.error(e.getMessage(), e);
e.printStackTrace();
//throw e;
}
// 1. Get a POJO Session Factory
if (factory == null)
{
//factory = new IlrJ2SESessionFactory();
//to log rule execution start time by using bre logger
//transactionLogger.setRuleExecutionStartTime(new Date());
factory = new IlrEJB3SessionFactory();
// As the EJBS are embedded within the ear file, we need to prepend
// the ear file name to the JNDI.
factory.setStatelessLocalJndiName("ejblocal:ilog.rules.res.session.ejb3.IlrStatelessSessionLocal");
}
// 2. Create a stateless rule session using this factory
try
{
if (ruleSession == null)
{
ruleSession = factory.createStatelessSession();
}
} catch (Exception e)
{
e.printStackTrace();
return;
}
// 3. Create a session request to invoke the RES (defining the ruleset
// path and the input ruleset parameters)
if (path == null)
{
path = new IlrPath(RULEAPP_NAME, RULESET_NAME);
}
sessionRequest = factory.createRequest();
sessionRequest.setRulesetPath(path);
}
public void onMessage(Message receivedMsg)
{
// onMessage code goes here.
}
}
You are violating programming restrictions (see EJB spec 16.2.2):
An enterprise bean must not use read/write static fields. Using read-only static fields is allowed. Therefore, it is recommended that all static fields in the enterprise bean class be declared as final.
Remove your (non-final) static fields, your static initializer and the constructor. Intialisation is done within the postConstruct lifecycle callback method.
Your EJB could look like this:
#MessageDriven(activationConfig = { #ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class DecisionServiceMDB implements MessageListener
{
private Logger responseTimeLogger;
private Logger errorLogger;
private Logger ruleExceptionLogger;
private String RULEAPP_NAME;
private String RULESET_NAME;
private InitialContext ic;
private ConnectionFactory cf;
private Destination destination;
private String qcfLookup;
private String qLookup;
private Connection c;
private Session s;
private MessageProducer mp;
private boolean isInitializedOkay = true;
private IlrEJB3SessionFactory factory;
private IlrStatelessSession ruleSession;
private IlrPath path;
private IlrSessionRequest sessionRequest;
#PostConstruct
public void init() {
responseTimeLogger = Logger.getLogger(PropertyManager.getResponseTimeLogger());
errorLogger = Logger.getLogger(PropertyManager.getErrorLogger());
ruleExceptionLogger = Logger.getLogger(PropertyManager.getRuleExceptionLogger());
RULEAPP_NAME = PropertyManager.getRuleAppName();
RULESET_NAME = PropertyManager.getRuleSetName();
qcfLookup = PropertyManager.getQueueFactoryJndiName();
qLookup = PropertyManager.getQueueDestinationJndiName();
ic = new InitialContext();
cf = (ConnectionFactory) ic.lookup(qcfLookup);
destination = (Destination) ic.lookup(qLookup);
factory = new IlrEJB3SessionFactory();
factory.setStatelessLocalJndiName("ejblocal:ilog.rules.res.session.ejb3.IlrStatelessSessionLocal");
ruleSession = factory.createStatelessSession();
sessionRequest.setRulesetPath(path);
}
public void onMessage(Message receivedMsg)
{
// onMessage code goes here.
}
}
I removed the static initializer. Looks like you try to configure logging, which should not be done within your EJB. Refer to the documentation of your application server how to do this properly.
This is just some example code based on the original code.
The implementation you provided looks like a plain java implementation. Be aware of requirements in an enterprise environment (e.g. EJB lifecycle, EJB providers responsibility, ...). Read the EJB spec and some JEE tutorials before proceeding.
With this in mind, you should take a look at your PropertyManager afterwards. This might not be implemented in a suitable manner.

Mule Properties in a java component

In my Mule project, I have a property file that contains my http address for instance
server.address = http://localhost:8080/test/
and then in my flow i will reference it as ${server.address} , but how do i reference that property in a java component class?
For instance:
public String address = ${server.address}
You can set the property in your java class as a Spring property. For a singleton object, the property would be set when the flow is started.
<flow name="propertyprojectFlow1" doc:name="propertyprojectFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8581" path="echoServer" doc:name="HTTP"/>
<component doc:name="Java">
<singleton-object class="MyClass">
<property key="server" value="${server.address}"/>
</singleton-object>
</component>
</flow>
The class would need to have a setter for the property.
import org.apache.log4j.Logger;
import org.mule.api.MuleEventContext;
import org.mule.api.lifecycle.Callable;
public class MyClass implements Callable {
private static Logger logger = Logger.getLogger(MyClass.class);
private String server;
public MyClass() {
}
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
logger.info("Server is " + server);
return null;
}
public void setServer(String server) {
logger.info("Setting server to " + server);
this.server = server;
}
}
Property name in properties file:
your.property.name.in.properties.file=testing
Java component:
import org.mule.api.MuleEventContext;
import org.mule.api.lifecycle.Callable;
import org.springframework.beans.factory.annotation.Value;
public class PropertyTest implements Callable {
#Value("${your.property.name.in.properties.file}")
private String yourPropertyNameInPropertiesFile;
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
System.out.println("yourPropertyNameInPropertiesFile"+yourPropertyNameInPropertiesFile);
// TODO Auto-generated method stub
return null;
}
}
You can load that property or any other property, loading the properties file. (although it could create some performance issues, loading the properties file every time the flow is executed).
public Properties loadProperties(String name) {
if(properties == null){
return loadProperties(name, Thread.currentThread().getContextClassLoader());
} else {
return properties;
}
}
And then:
Properties props = loadProperties("application.properties");
String url = props.getProperty("server.address");
Making some changes to #Matt answer
import org.apache.log4j.Logger;
import org.mule.api.MuleEventContext;
import org.mule.api.lifecycle.Callable;
public class MyClass implements Callable {
private static Logger logger = Logger.getLogger(MyClass.class);
private String server;
private Properties properties;
public MyClass() { }
#Override
public Object onCall(MuleEventContext eventContext) throws Exception {
properties = loadProperties("application.properties");
server = properties.getProperty("server.address");
logger.info("Server is " + server);
return null;
}
public Properties loadProperties(String name) {
if(properties == null){
return loadProperties(name, Thread.currentThread().getContextClassLoader());
} else {
return properties;
}
}
}

Getting Database Connection using Quartz

I have a requirement where i need to insert data and retrieve the same during my scheduling process.Though i can create my own connection class and can do the work but i am wondering is there a way to obtain a data base connection using Quartz API.
Since Quartz is efficiently doing data base connection and handling so my intention was to use a well defined structure in stead of creating my own.
I saw the following code in the Quartz
conn = DBConnectionManager.getInstance().getConnection(
getDataSource());
but i am not sure how good this approach is to obtain the connection.Or is there any good example/resource to create an efficient database connection class.
Quartz Property File
org.quartz.scheduler.instanceName=QuartzScheduler
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.threadPool.threadCount=7
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.dataSource = myDS
org.quartz.dataSource.myDS.driver=com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL=jdbc:mysql://localhost:3306/quartz
org.quartz.dataSource.myDS.user=root
org.quartz.dataSource.myDS.password=root
org.quartz.dataSource.myDS.maxConnections=5
You can get connection utilizing Quartz by naming the data-source you have defined in your property file like
conn = DBConnectionManager.getInstance().getConnection("myDS");
here myDS is the name of the data source you have defined in your property file
but since you are using the underlying data pool of quartz make sure that you close the connection so that it should get back to the pool.
This is just an outline based on my knowledge of Quartz and how it get connection.
If you want to get DataSource:
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Properties;
import javax.sql.DataSource;
import org.quartz.SchedulerException;
import org.quartz.utils.PoolingConnectionProvider;
import org.quartz.utils.PropertiesParser;
/**
* This class just exposes the underlying data source backed by C3PO
* (http://www.mchange.com/projects/c3p0/index.html).
*/
class MyDataSource extends PoolingConnectionProvider {
public MyDataSource(Properties config) throws SchedulerException, SQLException {
super(config);
}
public DataSource dataSource() {
return getDataSource();
}
}
/** This class exposes the data store configured in quartz.properties. */
public class MyDataSourceLoader {
private static final String DATA_SOURCE_CONFIG = "quartz.properties";
private static final String DATA_SOURCE_PREFIX = "org.quartz.dataSource.myDS";
private static final DataSource dataSource;
static {
try {
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(DATA_SOURCE_CONFIG);
Properties quartzConfig = new Properties();
quartzConfig.load(in);
in.close();
PropertiesParser pp = new PropertiesParser(quartzConfig);
Properties dataSourceConfig = pp.getPropertyGroup(DATA_SOURCE_PREFIX, true);
MyDataSource mds = new MyDataSource(dataSourceConfig);
dataSource = mds.dataSource();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static DataSource dataSource() {
return dataSource;
}
}

Categories