How to start HSQLDB in server mode from Spring boot application - spring

I have a Spring boot application, running with jpa data and hsqldb 2.3.3 (in Centos 7), the application runs fine but I would like to use HSQLDB database manager to check the data status, however it failed:
application.properties:
spring.datasource.url=jdbc:hsqldb:mem:testdb
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.HSQLDialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
Command to start HSQLDB:
java -cp /home/mycentos/.m2/repository/org/hsqldb/hsqldb/2.3.3/hsqldb-2.3.3.jar org.hsqldb.util.DatabaseManagerSwing
If I tried to log in with HSQLDB server mode, it pops Connection refused error
jdbc:hsqldb:hsql://localhost/testdb
If I tried to log in in-memory db, I can log in but no table and data showing up
jdbc:hsqldb:hsql:testdb
Question:
How to make it works?
Do I have to refer to the hsqldb.jar from tomcat deployment folder because that is the one using by the application?
Any configuration difference to configure hsqldb in server mode or in-memory mode from Spring application?
Can any method make in-memory mode working in such situation (to check data by db created Spring boot)?

To access the HSQL DB created by Spring boot app, you have to start HSQL server. For example, create a XML configuration file hsql_cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="hqlServer" class="org.hsqldb.server.Server" init-method="start" destroy-method="stop">
<property name="properties"><bean class="org.hsqldb.persist.HsqlProperties">
<constructor-arg><props>
<prop key="server.database.0">mem:testdb</prop>
<prop key="server.dbname.0">testdb</prop><!--DB name for network connection-->
<prop key="server.no_system_exit">true</prop>
<prop key="server.port">9001</prop><!--default port is 9001 -->
</props></constructor-arg>
</bean></property>
</bean>
</beans>
Here is a example to import the XML configuration in main application class.
#SpringBootApplication
#ImportResource(value="classpath:/package/hsql_cfg.xml")
public class MyApplication {
}
The HSQL server will start with Spring boot app. Other applications could connect to the HSQL server using JDBC url
jdbc:hsqldb:hsql://ip_address:port/testdb
Of course, hsqldb.jar is required for loading JDBC driver class.

Just to add to beckyang's answer, here is my approach.
Includes a hack to redirect logs to slf4j.
Includes specifying a corresponding datasource.
import org.hsqldb.jdbc.JDBCDataSource;
import org.hsqldb.server.Server;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
#Configuration
public class DataSourceConfiguration {
private final Logger log = LoggerFactory.getLogger(getClass());
#Bean(initMethod = "start", destroyMethod = "stop")
#ConfigurationProperties//(prefix = "alarms.idempotent.server")
public Server idempotentServer(#Value("${alarms.idempotent.server.path}") String path, #Value("${alarms.idempotent.port}") int port, #Value("${alarms.idempotent.name}") String name) {
Server server = new Server();
server.setDatabaseName(0, name);
server.setDatabasePath(0, path);
server.setPort(port);
server.setLogWriter(slf4jPrintWriter());
server.setErrWriter(slf4jPrintWriter());
return server;
}
#Bean("idempotentDataSource")
#Primary
#ConfigurationProperties
public DataSource idempotentDataSource(#Value("${alarms.idempotent.datasource.url}") String urlNoPath, #Value("${alarms.idempotent.name}") String name) {
JDBCDataSource jdbcDataSource = new JDBCDataSource();
String url = urlNoPath;
if (!url.endsWith("/")) {
url += "/";
}
url += name;
jdbcDataSource.setUrl(url);
jdbcDataSource.setUser("sa");
return jdbcDataSource;
}
private PrintWriter slf4jPrintWriter() {
PrintWriter printWriter = new PrintWriter(new ByteArrayOutputStream()) {
#Override
public void println(final String x) {
log.debug(x);
}
};
return printWriter;
}
}

Related

Unable to post message to IBM MQ Queue

I am trying to connect to IBM MQ and post message. getting below exception but the same code works in development environment.
org.springframework.jms.connection.SingleConnectionFactory.createSession(SingleConnectionFactory.java:437)
com.ibm.mq.jms.MQQueueConnection.createSession(MQQueueConnection.java:154) ~[com.ibm.mq.allclient-9.0.4.0.jar:9.0.4.0 - p904-L171030.1
com.ibm.mq.jms.MQQueueConnection.createQueueSession(MQQueueConnection.java:130) ~[com.ibm.mq.allclient-9.0.4.0.jar:9.0.4.0 - p904-L171030.1]
com.ibm.mq.jms.MQQueueSession.<init>(MQQueueSession.java:58) ~[com.ibm.mq.allclient-9.0.4.0.jar:9.0.4.0 - p904-L171030.1]
com.ibm.mq.jms.MQSession.<init>(MQSession.java:262) ~[com.ibm.mq.allclient-9.0.4.0.jar:9.0.4.0 - p904-L171030.1]\\n\
com.ibm.mq.jms.MQSession.getTransacted(MQSession.java:876) ~[com.ibm.mq.allclient-9.0.4.0.jar:9.0.4.0 - p904-L171030.1]
Caused by: java.lang.NullPointerException
Basically, the session is becoming null in other regions when we are trying to post a message from Spring JMS Template to IBM MQ.
from java,
public void sendNotificationsMessageToQueue(String jsonMessage)
{
jmsTemplate(Queue, new MessageCreator(){
#Override public Message createMessage(Session session) throws JMSException
{
return session.createTextMessage(jsonMessage);
} });
From XML:
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate"> <property name="connectionFactory" ref="ibmConnectionFactory" />
<property name="defaultDestination" ref="exQueue" />
</bean>
Read this as a comment as opposed to an answer. It's a long comment and needed a little formatting.
Your XML should also have a ibmConnectionFactory bean defined which will point at the IBM MQ Factory classes. What is in there is going to be important. You need to share that, as it looks like that that is where your deployed code is failing.
I am guessing that this is not a Spring-Boot project, and you are not making use of the mq-jms-spring-boot-starter.
If you were then that you are defining jmsTemplate and ibmConnectionFactory beans is a bit strange. If the IBM MQ classes are the only Messaging classes defined in your spring-boot project then spring will automatically bind the IBM MQ connection classes to the default jmsTemplate bean.
If you have other Messaging classes defined as dependencies in your project, then your beans are ignoring them, which indicates that they are not needed and hence shouldn't be there.
If, however, you are using Spring-Boot and mq-jms-spring-boot-starter, then I find it easier to define the beans in Java code than XML, although you only need to if you are changing the defaults.
import com.ibm.mq.jms.MQConnectionFactory;
import com.ibm.mq.samples.jms.spring.globals.handlers.OurDestinationResolver;
import com.ibm.mq.samples.jms.spring.globals.handlers.OurMessageConverter;
import com.ibm.mq.spring.boot.MQConfigurationProperties;
import com.ibm.mq.spring.boot.MQConnectionFactoryFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;
import javax.jms.JMSException;
#Configuration
public class MQConfiguration114 {
protected final Log logger = LogFactory.getLog(getClass());
#Bean
public MQConnectionFactory mqConnectionFactory() throws JMSException {
MQConfigurationProperties properties = new MQConfigurationProperties();
// Properties will be a mix of defaults, and those found in application.properties
// under ibm.mq
// Here we can override any of the properties should we need to
MQConnectionFactoryFactory mqcff = new MQConnectionFactoryFactory(properties,null);
MQConnectionFactory mqcf = mqcff.createConnectionFactory(MQConnectionFactory.class);
return mqcf;
}
#Bean("myJmsTemplate")
public JmsTemplate myJmsTemplate() throws JMSException {
JmsTemplate jmsTemplate = new JmsTemplate(mqConnectionFactory());
// Any other customisations necessary go here.
// ...
return jmsTemplate;
}
}
It worked after removing spring jms template and written new class for obtaining IBM MQ connection.
We had the same problem.
It was not related to reading configurations but to the dd-java-agent.jar. The version 0.82.0 was causing the issue. We moved to 0.84.0 and problem solved!

Infinispan cache returning null object

Getting NullPointer exception while put the values into cache using cache.put() method.
Environment:
Jboss 7.2
Here is the sample code I've written to reproduce the issue.
Configuration form standalone.xml file:
`<cache-container name="sampleCache" default-cache="default">
<local-cache name="default"/>
</cache-container>`
Added dependencies in deploy descriptor file like
`<jboss-deployment-structure>
<deployment>
<dependencies>
<module name="org.infinispan.commons" />
<module name="org.infinispan" />
</dependencies>
</deployment>
</jboss-deployment-structure>`
Getting the cache object via #Resource from Java code
`import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import org.infinispan.Cache;
/**
* InfiniSpanJbossCache Implementation
*
*/
#Startup
#Singleton
public class InfiniSpanJbossCacheExample {
#Resource(lookup="java:/jboss/infinispan/cache/sampleCache/default")
private static Cache<String, String> cache;
#PostConstruct
public static void deploy(){
cache.put("test","inserted1element");
}
}`
While trying to insert some values into cache(cache.put("","")) I'm getting the error, Did I miss any configs????

Dynamically provide directory and file name to ftp outbound gateway

We have a requirement for the FTP client to download a file whose name and directory is provided at run-time. So, the FTP client may be asked to download file1.txt from foo1/foo2 directory path on the remote server.
We do have a solution using Spring Integration FTP outbound gateway. With this solution to make it dynamic:
the ApplicationContext for the gateway is created
the gateway properties get set using file name and remote directory path
the file is downloaded
the ApplicationContext is closed.
What we're not happy about is that the ApplicationContext is created and closed every time which obviously affects performance. Is there a way to dynamically pass the file name and the directory path to the gateway without reloading the Appplication Context every time?
Your help will be greatly appreciated.
Here's the main code and configuration:
package com.cvc.ipcdservice.ftp;
import java.util.List;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.StandardEnvironment;
public class DynamicFtpClient {
private static final Logger LOGGER = LoggerFactory
.getLogger(DynamicFtpClient.class);
public void download(final FtpMetaData ftpMetaData) {
final ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] { "/META-INF/spring/integration/FtpOutboundGateway-context.xml" },
false);
setEnvironment(ctx, ftpMetaData);
ctx.refresh();
final ToFtpFlowGateway toFtpFlow = ctx.getBean(ToFtpFlowGateway.class);
// execute the flow (mget to download from FTP server)
final List<Boolean> downloadResults = toFtpFlow.mGetFiles("/");
LOGGER.info(
"Completed downloading from remote FTP server. ftpMetaData:{}, downloadResults.size:{} ",
ftpMetaData, downloadResults.size());
ctx.close();
}
/**
* Populate {#code ConfigurableApplicationContext} with Provider-specific
* FTP properties.
*
* #param ctx
* #param customer
*/
private void setEnvironment(final ConfigurableApplicationContext ctx,
final FtpMetaData ftpMetaData) {
final StandardEnvironment env = new StandardEnvironment();
final Properties props = new Properties();
// populate properties for customer
props.setProperty("ftp.host", ftpMetaData.getHost());
props.setProperty("ftp.port", ftpMetaData.getPort());
props.setProperty("ftp.userid", ftpMetaData.getUserName());
props.setProperty("ftp.password", ftpMetaData.getPassword());
// props.setProperty("remote.directory", "/");
// WARNING: the file name pattern has to be surrounded by single-quotes
props.setProperty("ftp.remote.filename.pattern",
"'" + ftpMetaData.getFileNamePattern() + "'");
props.setProperty("ftp.local.dir", ftpMetaData.getLocalDirectory());
final PropertiesPropertySource pps = new PropertiesPropertySource(
"ftpprops", props);
env.getPropertySources().addLast(pps);
ctx.setEnvironment(env);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-ftp="http://www.springframework.org/schema/integration/ftp"
xsi:schemaLocation="http://www.springframework.org/schema/integration/ftp http://www.springframework.org/schema/integration/ftp/spring-integration-ftp.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder/>
<int:gateway id="gw" service-interface="com.cvc.ipcdservice.ftp.ToFtpFlowGateway"
default-request-channel="inbound"/>
<bean id="ftpSessionFactory"
class="org.springframework.integration.ftp.session.DefaultFtpSessionFactory">
<property name="host" value="${ftp.host}"/>
<property name="port" value="${ftp.port}"/>
<property name="username" value="${ftp.userid}"/>
<property name="password" value="${ftp.password}"/>
</bean>
<int-ftp:outbound-gateway id="gatewayGET"
local-directory="${ftp.local.dir}"
session-factory="ftpSessionFactory"
request-channel="inbound"
command="mget"
command-options="-P"
expression="${ftp.remote.filename.pattern}"/>
</beans>
There is no need to create the context for each request.
Instead of using a literal for the expression:
props.setProperty("ftp.remote.filename.pattern",
"'" + ftpMetaData.getFileNamePattern() + "'");
Use an expression based on the request; e.g.
props.setProperty("ftp.remote.filename.pattern",
"payload");
Then simply send the required path in your gateway call...
final List<Boolean> downloadResults = toFtpFlow.mGetFiles("/some/path/*.txt");

Spring Inject PersistenceContext

Trying to implement a DDD architecture with aspect oriented tests that access a database and check if user exists, using AspectJ LTW...
Currently I am faces with two issues, I don't know if this class is being injected in a Spring context. I have tried to add the
//#RunWith(SpringJUnit4ClassRunner.class)
//#ContextConfiguration(locations = {"classpath*:EntityTest-context.xml"})
With no sucess. Here is the test that I am trying to run. If you notice I am creating the EntityManager on the #Before I don't know if this is a proper usage, because when I try to find the object that is created I get returned null.
package ienterprise.common.aspects;
import ienterprise.common.model.CompanyPosition;
import ienterprise.common.model.InternalUser;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import static org.junit.Assert.assertEquals;
import org.springframework.test.context.ContextConfiguration;
//#RunWith(SpringJUnit4ClassRunner.class)
//#ContextConfiguration(locations = {"classpath*:EntityTest-context.xml"})
public class EntityTest {
private static final Logger logger = LoggerFactory.getLogger(EntityTest.class);
// #PersistenceContext(unitName="mysql") // FIXME inject this in unit tests
private static EntityManager manager;
#Before
public void setUp(){
EntityManagerFactory mngFactory = Persistence.createEntityManagerFactory("mysql");
manager = mngFactory.createEntityManager();
}
#Test
public void createUser(){
InternalUser someGuy = new InternalUser();
someGuy.setName("Adam");
someGuy.setUser("Engineer");
someGuy.create();
logger.debug("created user: {}", someGuy);
//FIXME: Can't find the user in the database.
InternalUser foundUser = manager.find(InternalUser.class, 1L);
logger.debug("fetched user: {}",foundUser);
assertEquals( someGuy, foundUser);
}
}
Our context xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:load-time-weaver/>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property>
</bean>
</beans>
How can I remove the #Before and inject a PersistenceContext?
How can I make sure that my class has a Spring Context?
This is all new stuff for me, and I would appreciate some links to github repositories if there are any with this kind of Spring+Hibernate+AspectJ+JUnit setup.
Let me know if something is not clear or additional detail is necessary.

Testing JNDI Spring Websphere Outside the Container

I have successfully tested some DAO outside a weblogic server by looking up the datasource information through jndi. I have search for a similar option with websphere and have to yet come accross a solution that does not involve hardcoding the username and password in some location within the application or something similar. Right now my jndi settings look like this inside spring:
<bean id="applicationServerEnviromentProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties"><props>
<prop key="java.naming.factory.initial">com.ibm.websphere.naming.WsnInitialContextFactory</prop>
<prop key="java.naming.provider.url">iiop://localhost:2809</prop>
</props>
</property>
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>PeopleAppDS</value></property>
<property name="jndiEnvironment"><ref local="applicationServerEnviromentProperties"/></property>
</bean>
I have Tested the jndi connection and it is working when the application is loaded on to websphere. I would like to be able to test the daos inside eclipse for instance before the app is loaded. Any help would be much appreciated.
Here are the details for the test case.
-------BaseTestCase.java--------------------
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations= {"file:data-access-config.xml"})
public class BaseTestCase {
}
-----PersonDaoTest.java----------------
import static org.junit.Assert.assertNotNull;
import java.util.List;<br>
import org.junit.Test;<br>
import org.springframework.beans.factory.annotation.Autowired;
import ....dao.PersonDao;<br>
import ....domain.Person;<br>
public class PersonDaoTest extends BaseTestCase {
#Autowired
private PersonDao personDao;
#Test
public void findByName() {
List<Person> people = personDao.listByName("j%", false, "userId");
assertNotNull(people);
}
}
The right way to do it is to have a JNDI data source with a DriverManagerDataSource default. If you run in the container, Spring will use the named data source; if the lookup fails, it'll use the non-JNDI data source.

Resources