It is always a good idea to unit test the spring contexts that define an application. This can be as simple as a unit test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:com/me/my_context.xml" })
public class SpringContextTest implements ApplicationContextAware
{
/**
* The spring context.
*/
private ApplicationContext applicationContext;
/**
* Test the spring wiring.
*/
@Test
public void testSpringWiring()
{
final Object obj = applicationContext.getBean("myBean");
assertTrue(obj instanceof MyBean);
}
/**
* {@inheritDoc}
*/
@Override
public void setApplicationContext(final ApplicationContext applicationContext)
{
this.applicationContext = applicationContext;
}
}
However, where there is interaction with a JNDI resource as part of the spring start up this needs to be modified to make the JNDI resource available. Adding this @Before method will set up a JNDI resource for a MySql database.
/**
* Set up the jndi data source so that the wiring tests still work.
*/
@BeforeClass
public static void setUpClass()
{
// Setup the jndi context and the datasource
try
{
// Create a database connection to satisfy the data loading requirements.
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://server:port");
dataSource.setUsername("username");
dataSource.setPassword("password");
final SimpleNamingContextBuilder builder = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
builder.bind("jdbc/MY_JNDI_NAME", dataSource);
builder.activate();
}
catch (final NamingException ex)
{
LOG.error("Error creating JNDI resource", ex);
}
}
Wednesday, 30 April 2014
Monday, 10 February 2014
Command Line Application Start
Java has the 'main' method to start its apps and this is very easy to invoke. However, there are times when optional arguments need to be passed into the app and for this the apache commons cli (Command Line Interface) is really useful.
CommandLineParser parser = new BasicParser();
OptionBuilder
// the name of the argument
.withArgName("timeout")
// this has two arguments -timeout <value>
.hasArgs(2)
// the separator '-' is used
.withValueSeparator()
// the description used for the help text
.withDescription("Millisecond timeout for this test (default: 20000)")
// create this option refered to as 'timeout'
.create("timeout")
This option is then added to the list of options
final Options options = new Options();
options.addOption(OptionBuilder.withArgName(.......));
which are added to the parser
CommandLine line = parser.parse(options, args);
final String timeoutStr = line.getOptionValue("timeout", "20000");
or query that an option has been provided,
if (line.hasOption("timeout")) {
}
Help Text
The descriptions created in the Options can be used to generate help text
final HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("sample", options);
which is useful if a value fails validation or particular options are not provided.
import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
public class SampleMain
{
/**
* Main.
*
* @param args The command line args
*/
public static void main(final String[] args)
{
final CommandLineParser parser = new BasicParser();
final Options options = new Options();
options.addOption(OptionBuilder.withArgName("timeout").hasArgs(2).withValueSeparator()
.withDescription("Millisecond timeout for this app (default: 20000)").create("timeout"));
options.addOption(OptionBuilder.withArgName("filepath").hasArgs(2).withValueSeparator()
.withDescription("Configuration file").create("filepath"));
options.addOption(OptionBuilder.withArgName("logdirectory").hasArgs(2).withValueSeparator()
.withDescription("log directory (default: ./logs)").create("logdirectory"));
CommandLine line = parser.parse(options, args);
// Get the timeout
final String timeoutStr = line.getOptionValue("timeout", "20000");
final long timeout = Long.valueOf(timeoutStr);
// Log directory for the app
final String logDirectory = line.getOptionValue("logdirectory", "./logs");
if (line.hasOption("filepath"))
{
// Do something with this file
}
else
{
final HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("sample", options);
}
}
}
or to use the defaults
Creating a Parser
Creating a parser is really simple and involves just one lineCommandLineParser parser = new BasicParser();
Creating Options
The options for the command line are built using a builder pattern. Here is an exampleOptionBuilder
// the name of the argument
.withArgName("timeout")
// this has two arguments -timeout <value>
.hasArgs(2)
// the separator '-' is used
.withValueSeparator()
// the description used for the help text
.withDescription("Millisecond timeout for this test (default: 20000)")
// create this option refered to as 'timeout'
.create("timeout")
This option is then added to the list of options
final Options options = new Options();
options.addOption(OptionBuilder.withArgName(.......));
which are added to the parser
CommandLine line = parser.parse(options, args);
Getting the values
This CommandLine object can then be used to get the values that have been provided.final String timeoutStr = line.getOptionValue("timeout", "20000");
or query that an option has been provided,
if (line.hasOption("timeout")) {
}
Help Text
The descriptions created in the Options can be used to generate help text
final HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("sample", options);
which is useful if a value fails validation or particular options are not provided.
Example
Here is a full exampleimport org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
public class SampleMain
{
/**
* Main.
*
* @param args The command line args
*/
public static void main(final String[] args)
{
final CommandLineParser parser = new BasicParser();
final Options options = new Options();
options.addOption(OptionBuilder.withArgName("timeout").hasArgs(2).withValueSeparator()
.withDescription("Millisecond timeout for this app (default: 20000)").create("timeout"));
options.addOption(OptionBuilder.withArgName("filepath").hasArgs(2).withValueSeparator()
.withDescription("Configuration file").create("filepath"));
options.addOption(OptionBuilder.withArgName("logdirectory").hasArgs(2).withValueSeparator()
.withDescription("log directory (default: ./logs)").create("logdirectory"));
CommandLine line = parser.parse(options, args);
// Get the timeout
final String timeoutStr = line.getOptionValue("timeout", "20000");
final long timeout = Long.valueOf(timeoutStr);
// Log directory for the app
final String logDirectory = line.getOptionValue("logdirectory", "./logs");
if (line.hasOption("filepath"))
{
// Do something with this file
}
else
{
final HelpFormatter formatter = new HelpFormatter();
formatter.printHelp("sample", options);
}
}
}
Use
This code would then be used,
java -jar sample.jar -logdirectory ./mylog -timeout 5000 -filepath mydir/myfile
or to use the defaults
java -jar sample.jar -filepath mydir/myfile
Monday, 20 January 2014
Dynamic Spring Message Driven Beans
Creating MDBs from spring is really easy particularly if all the information is known up front. As usual it is just some configuration in the spring context and is shown here.
For dynamic beans things can still be put into the spring configuration but need the destination setting at runtime. This can be done using some spring context as prototype beans so that a new instance of them is created each time and a small bit of wiring in the code.
<!-- This bean is a prototype bean which is loaded dynamically-->
<!-- it is loaded using a getBean("jmsDestination", requiredTopic") and as such the HOLDING_VALUE is -->
<!-- replaced with whatever is required by the class in question -->
<bean id="jmsDestination" class="com.ibm.mq.jms.MQTopic" scope="prototype">
<constructor-arg value="HOLDING_VALUE" />
</bean>
<!-- Generic MDB Container -->
<bean id="springMdbContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" scope="prototype">
<property name="connectionFactory" ref="springConnectionFactory" />
<!-- The destination is dynamically set in the factory method but a default is provided here-->
<property name="destination" ref="jmsDestination" />
<!-- The normal MessageListener which is put here is added dynamically in the factory -->
</bean>
/**
* Create a Destination object.
*
* @param topic The topic to construct the destination with
* @return the Destination created.
*/
public Destination createDestination(final String topic)
{
// Create the destination with the topic string.
return (Destination) applicationContext.getBean("jmsDestination", topic);
}
This creates a new Destination object based on the spring bean. This allows the MQ provided to be changed in the spring configuration without having to change code.
To create a new MDB create a destination as above and then use the code,
/**
* Create a MDB wired by spring.
*
* @param destination The destination topic to listen to.
* @param messageListener The message listener (MDB) to wire
*/
private void wireMdb(final Destination destination, final MessageListener messageListener)
{
// Use spring to wire up the MDB with this destination and a ConnectionFactory
// which is already provided in the spring context.
// The MDB and Destination are set here and then the container is manually started.
final DefaultMessageListenerContainer container =
(DefaultMessageListenerContainer) applicationContext.getBean("springMdbContainer");
container.setDestination(destination);
container.setMessageListener(messageListener);
container.start();
}
It is also possible to change the destination that a container is listening to once it has started. Using the setDestination(...) method does this according to the spring documentation.
For dynamic beans things can still be put into the spring configuration but need the destination setting at runtime. This can be done using some spring context as prototype beans so that a new instance of them is created each time and a small bit of wiring in the code.
Spring Context
<!-- MQ / JMS Connection factory -->
<bean id="jmsConnectionFactory" class="com.ibm.mq.jms.MQTopicConnectionFactory">
<property name="hostName" value="${jms.mq.ip}" />
<property name="port" value="${jms.mq.port}" />
<property name="queueManager" value="${jms.mq.queueManager}" />
<property name="transportType" value="1" />
</bean>
<!-- Spring Connection Factory -->
<bean id="springConnectionFactory" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="jmsConnectionFactory" />
<property name="username" value="${jms.mq.username}" />
<property name="password" value="${jms.mq.password}" />
</bean>
<!-- it is loaded using a getBean("jmsDestination", requiredTopic") and as such the HOLDING_VALUE is -->
<!-- replaced with whatever is required by the class in question -->
<bean id="jmsDestination" class="com.ibm.mq.jms.MQTopic" scope="prototype">
<constructor-arg value="HOLDING_VALUE" />
</bean>
<!-- Generic MDB Container -->
<bean id="springMdbContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer" scope="prototype">
<property name="connectionFactory" ref="springConnectionFactory" />
<!-- The destination is dynamically set in the factory method but a default is provided here-->
<property name="destination" ref="jmsDestination" />
<!-- The normal MessageListener which is put here is added dynamically in the factory -->
</bean>
Java
In the java code a new destination can be obtained using the bean above and the code,/**
* Create a Destination object.
*
* @param topic The topic to construct the destination with
* @return the Destination created.
*/
public Destination createDestination(final String topic)
{
// Create the destination with the topic string.
return (Destination) applicationContext.getBean("jmsDestination", topic);
}
This creates a new Destination object based on the spring bean. This allows the MQ provided to be changed in the spring configuration without having to change code.
To create a new MDB create a destination as above and then use the code,
/**
* Create a MDB wired by spring.
*
* @param destination The destination topic to listen to.
* @param messageListener The message listener (MDB) to wire
*/
private void wireMdb(final Destination destination, final MessageListener messageListener)
{
// Use spring to wire up the MDB with this destination and a ConnectionFactory
// which is already provided in the spring context.
// The MDB and Destination are set here and then the container is manually started.
final DefaultMessageListenerContainer container =
(DefaultMessageListenerContainer) applicationContext.getBean("springMdbContainer");
container.setDestination(destination);
container.setMessageListener(messageListener);
container.start();
}
It is also possible to change the destination that a container is listening to once it has started. Using the setDestination(...) method does this according to the spring documentation.
Tuesday, 19 November 2013
Java Keytool
I constantly forget how to use the keytool so here are some memory joggers! The keytool app is part of the the standard Java distribution.
These will be added to over time.
keytool -list -keystore <keystore.jks> -storepass <password>
These will be added to over time.
List
List the contents of a jks filekeytool -list -keystore <keystore.jks> -storepass <password>
Remote Keys
Print a certificate for a remote server keytool -printcert -rfc -sslserver my.company.com
Copy the output into a file .pemImport Key
Import a key to a key store. In this case it is imported into the java default Certificate Authority file (cacerts). This will prompt for a password for the cacerts file which is 'changeit' by default. keytool -importcert -file ./certificate.pem -keystore $JRE_LIB/lib/security/cacerts
Thursday, 14 November 2013
Spring WS Interceptor
Using the spring interceptor methods a SOAP message can be manipulated by adding or removing elements.
Create an interceptor and add it to the spring config
<bean id="myInterceptor" class="com.me.MyInterceptor">
</bean>
<sws:interceptors>
<ref bean="myInterceptor" />
</sws:interceptors>
The interceptor class implements the EndpointInterceptor
public class MyInterceptor implements EndpointInterceptor
This interface defines four methods,
// Used to read and / or manipulate the request coming in the endpoint
boolean handleRequest(MessageContext paramMessageContext, Object paramObject)
// Used to read and / or manipulate the response coming out of the endpoint
boolean handleResponse(MessageContext paramMessageContext, Object paramObject)
// Used to read and / or manipulate any faults that have occurred
boolean handleFault(MessageContext paramMessageContext, Object paramObject)
// Called after the interceptor has finished.
void afterCompletion(MessageContext paramMessageContext, Object paramObject, Exception paramException)
SOAPBody
SOAPHeader
SOAPMessage
These objects use the standard org.w3c.dom objects to manipulate the contents. These objects can be obtained using the following,
SaajSoapMessage message = (SaajSoapMessage) messageContext.getRequest();
SOAPMessage soapMessage = message.getSaajMessage();
SOAPHeader soapHeader = soapMessage.getSOAPHeader();
SOAPBody soapBody = soapMessage.getSOAPBody();
SoapBody
SoapBody soapHeader = message.getSoapHeader();
Create an interceptor and add it to the spring config
<bean id="myInterceptor" class="com.me.MyInterceptor">
</bean>
<sws:interceptors>
<ref bean="myInterceptor" />
</sws:interceptors>
The interceptor class implements the EndpointInterceptor
public class MyInterceptor implements EndpointInterceptor
This interface defines four methods,
// Used to read and / or manipulate the request coming in the endpoint
boolean handleRequest(MessageContext paramMessageContext, Object paramObject)
// Used to read and / or manipulate the response coming out of the endpoint
boolean handleResponse(MessageContext paramMessageContext, Object paramObject)
// Used to read and / or manipulate any faults that have occurred
boolean handleFault(MessageContext paramMessageContext, Object paramObject)
// Called after the interceptor has finished.
void afterCompletion(MessageContext paramMessageContext, Object paramObject, Exception paramException)
Java Soap Objects
The default java soap objects are from the java.xml.soap package,SOAPBody
SOAPHeader
SOAPMessage
These objects use the standard org.w3c.dom objects to manipulate the contents. These objects can be obtained using the following,
SaajSoapMessage message = (SaajSoapMessage) messageContext.getRequest();
SOAPMessage soapMessage = message.getSaajMessage();
SOAPHeader soapHeader = soapMessage.getSOAPHeader();
SOAPBody soapBody = soapMessage.getSOAPBody();
Spring Soap Objects
The spring objects are in the package org.springframework.ws.soap,SoapBody
SoapHeader
SoapEnvelope
SoapElement
SoapEnvelope
SoapElement
and have only a few methods. The Body and Header can be used to get a standard javax.xml.transform.Source or Result object. These objects can be obtained using,
SaajSoapMessage message = (SaajSoapMessage) messageContext.getRequest();
SoapBody soapBody = message.getSoapBody();
The header will now include the xml. At the point above the xml is just a string so could be generated using JAXB to create complicated additional nested xml tags if necessary.
Reading using the Java Objects
Reading using the java objects is pretty easy. Using the java SOAPBody a node list can be obtained,
SOAPBody soapBody = soapMessage.getSOAPBody();
NodeList soapBodyNodeList = soapBody.getChildNodes();
String soapBodyStr = null;
for (int i = 0; i < soapBodyNodeList.getLength(); i++)
{
String localName = soapBodyNodeList.item(i).getLocalName();
}
or other standard dom manipulation eg getElementByTagName("myTag").
Reading using the Spring Objects
Using the Spring soap header or body can really simply be read using a Transformer,
SoapBody springSoapBody = message.getSoapBody();
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
StringWriter stringWriter = new StringWriter();
transformer.transform(springSoapBody.getPayloadSource(), new StreamResult(stringWriter));
The contents can then be obtained from the stringWriter using the toString(). Alternatively a DOMResult can be used,
DOMResult result = new DOMResult();
transformer.transform(springSoapBody.getPayloadSource(), result);
Adding using the Spring Objects
Added an object in easy using the transformer defined above,
SoapHeader soapHeader = message.getSoapHeader();
StringSource stringSource = new StringSource("<xmlToAdd>Hello</xmlToAdd>");
transformer.transform(stringSource , soapHeader.getResult());
The header will now include the xml. At the point above the xml is just a string so could be generated using JAXB to create complicated additional nested xml tags if necessary.
Friday, 27 September 2013
JD Eclipse Decompile
JD Eclipse is a brilliant java decompile which very usefully provides line numbers in the decompiled class file. Unfortunately it is no longer supported or in the Eclipse MarketPlace. To get it running on eclipse copy the two jars
jd.ide.eclipse.win32.x86_64_0.1.3.jar
jd.ide.eclipse_0.1.3.jar
into the eclipse/plugins directory and restart Eclipse.
Once eclipse has restarted go to,
Window - Preferences - General - Editors - File Associations
Click on 'Class' and then 'Add'. There is a new option now available called 'Class File Editor'. Add this and make it the default. Do the same to the 'Class without Source'.
Once completed the JD-Eclipse class viewer will be used to open class files.
I'd be interested to know if there is anything else around that decompiles like JD Eclipse? The ByteCode Visualiser in the MarketPlace is good but I want the actual code not the byte code.
Update
After posting this I have found this site with instructions and updates.
http://jd.benow.ca/
jd.ide.eclipse.win32.x86_64_0.1.3.jar
jd.ide.eclipse_0.1.3.jar
into the eclipse/plugins directory and restart Eclipse.
Once eclipse has restarted go to,
Window - Preferences - General - Editors - File Associations
Click on 'Class' and then 'Add'. There is a new option now available called 'Class File Editor'. Add this and make it the default. Do the same to the 'Class without Source'.
Once completed the JD-Eclipse class viewer will be used to open class files.
I'd be interested to know if there is anything else around that decompiles like JD Eclipse? The ByteCode Visualiser in the MarketPlace is good but I want the actual code not the byte code.
Update
After posting this I have found this site with instructions and updates.
http://jd.benow.ca/
Tuesday, 30 July 2013
Soap UI
SoapUI is a brilliant tool for testing web services. It can be downloaded from http://www.soapui.org/.
Right Click on the Test Steps -> Add Step -> Property Transfer
The transfer is done using XPath by default. An example of a property transfer is below using the xml
CreateRequest
<CreateRequest>
<name>Andy</name>
<data>123456</data>
</CreateRequest>
CreateResponse
<CreateResponse>
<id>159</id>
<name>Andy</name>
<data>123456</data>
</CreateResponse>
DeleteRequest
<DeleteResponse>
<id>159</id>
</DeleteResponse>
Here the property transfer is between the CreateResponse and the DeleteRequest. In SoapUI this will look like,
Source: Create Property: Response
declare namespace myns='http://www.me.com/example';
//myns:CreateResponse/id
Target: Delete Property: Request
declare namespace myns='http://www.me.com/example';
//myns:DeleteRequest/id
It is possible to include the whole <id>159</id> or to just transfer the value you can check the
Transfer text content
Transfering a whole block of xml can be really powerful but the 'Transfer text content' does keep things simple and allows the transfer of the 'value' only.
Property Transfers
SoapUI allows testing individual calls to a service but also allows multiple requests to be put together to form test cases. For example, a test case creating and deleting would require the id generated by the first request to be passed to the delete request. Soap UI's mechanism for doing this is with a Property Transfer.Right Click on the Test Steps -> Add Step -> Property Transfer
The transfer is done using XPath by default. An example of a property transfer is below using the xml
CreateRequest
<CreateRequest>
<name>Andy</name>
<data>123456</data>
</CreateRequest>
CreateResponse
<CreateResponse>
<id>159</id>
<name>Andy</name>
<data>123456</data>
</CreateResponse>
<DeleteResponse>
<id>159</id>
</DeleteResponse>
Here the property transfer is between the CreateResponse and the DeleteRequest. In SoapUI this will look like,
Source: Create Property: Response
declare namespace myns='http://www.me.com/example';
//myns:CreateResponse/id
Target: Delete Property: Request
declare namespace myns='http://www.me.com/example';
//myns:DeleteRequest/id
It is possible to include the whole <id>159</id> or to just transfer the value you can check the
Transfer text content
Transfering a whole block of xml can be really powerful but the 'Transfer text content' does keep things simple and allows the transfer of the 'value' only.
Subscribe to:
Posts (Atom)