tag:blogger.com,1999:blog-5995548684733568022024-03-21T06:51:10.119-07:00Another Double Espresso Please!Random mutterings, but mainly reminders for myself, on all things Java,Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.comBlogger41125tag:blogger.com,1999:blog-599554868473356802.post-63787422102775579222014-03-13T21:32:00.000-07:002014-03-13T21:47:57.501-07:00Redis Publish Subscribe and Long Polling with Spring's DeferredResult<div class="p1">
As well as being key value store, Redis offers a publish subscribe messaging implementation. This post will describe a simple scenario, using Spring Data Redis, of adding a message domain object to a repository via a REST call, publishing that message to a channel, subscribers to that channel receiving that message who as a result set any long polling deferred results with the message.</div>
<div class="p2">
<br /></div>
<div class="p1">
The two key classes in the Redis publish subscribe mechanism are the <i>RedisTemplate</i> class and the <i>RedisMessageListenerContainer</i> class.</div>
<div class="p2">
<br /></div>
<div class="p1">
The <i>RedisTemplate</i> contains the <i>JedisConnectionFactory</i> which holds the Redis connection details and as well as the methods to manipulate the key value stores, there’s a publish method called <i>convertAndSend</i>. This method takes two arguments. The first being the channel name of where the messages need to be published to and the second being the object to be sent. </div>
<div class="p2">
<br /></div>
<div class="p1">
In this example, the publishing of the message is done after the <i>Message</i> is persisted via an aspect.</div>
<div class="p2">
<br /></div>
<div class="p1">
<pre class="brush: java">@Aspect
@Component
public class MessageAspect extends AbstractRedisAspect {
private static final Logger LOGGER = LoggerFactory
.getLogger(MessageAspect.class);
@Value("${messaging.redis.channel.messages}")
private String channelName;
@After("execution(* com.city81.redisPubSub.repository.MessageDao.save(..))")
public void interceptMessage(JoinPoint joinPoint) {
Message message = (Message) joinPoint.getArgs()[0];
// this publishes the message
this.redisTemplate.convertAndSend(channelName, message);
}
}
</pre>
<div class="p2">
<br /></div>
<div class="p1">
The <i>RedisMessageListenerContainer</i>, as well as holding the <i>JedisConnectionFactory</i>, holds a map of message listeners where the key is a message listener instance and the value the channel. The message listener instance references a class which implements the <i>onMessage</i> method of the <i>MessageListener</i> interface.</div>
<div class="p2">
<br /></div>
<div class="p1">
<pre class="brush: 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:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd" >
<!-- for the redis pub sub aop beans -->
<aop:aspectj-autoproxy />
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:host-name="${messaging.redis.hostname}" p:port="${messaging.redis.port}"/>
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnectionFactory">
</bean>
<bean id="messageListener" class="org.springframework.data.redis.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<ref bean="messageManager"/>
</constructor-arg>
</bean>
<bean id="redisContainer" class="org.springframework.data.redis.listener.RedisMessageListenerContainer">
<property name="connectionFactory" ref="jedisConnectionFactory"/>
<property name="messageListeners">
<map>
<entry key-ref="messageListener">
<bean class="org.springframework.data.redis.listener.ChannelTopic">
<constructor-arg value="${messaging.redis.channel.messages}" />
</bean>
</entry>
</map>
</property>
</bean>
</beans>
</pre>
<div class="p2">
<br /></div>
<div class="p1">
When a message is published, those subscribers who are listening to that channel will then receive the published message via the <i>onMessage</i> method. The published message contains the serialised object that was sent in the body of the Redis Message and needs to be deserialised and cast to the original object.</div>
<div class="p2">
<br /></div>
<div class="p1">
<pre class="brush: java"> public void onMessage(
org.springframework.data.redis.connection.Message redisMessage,
byte[] pattern) {
Message message = (Message) SerializationUtils.deserialize(redisMessage.getBody());
// set the deferred results for the user
for (DeferredResult<Message> deferredResult : this.messageDeferredResultList) {
deferredResult.setResult(message);
}
}
</pre>
<div class="p2">
<br /></div>
<div class="p1">
The <i>DeferredResult</i> list is populated by calls to the REST service's <i>getNewMessage</i> method. This will in turn, in the <i>MessageManager</i>, create a <i>DeferredResult</i> object, add it to the list and return the object to the client.<br />
<br />
<br />
<pre class="brush: java"> public DeferredResult<Message> getNewMessage() throws Exception {
final DeferredResult<Message> deferredResult =
new DeferredResult<Message>(deferredResultTimeout);
deferredResult.onCompletion(new Runnable() {
public void run() {
messageDeferredResultList.remove(deferredResult);
}
});
deferredResult.onTimeout(new Runnable() {
public void run() {
messageDeferredResultList.remove(deferredResult);
}
});
messageDeferredResultList.add(deferredResult);
return deferredResult;
}
</pre>
<br />
<br />
The GitHub <a href="https://github.com/city81/redisPubSub" target="_blank">repo</a> for this example contains two simple HTML pages, one which starts a long poll request and another which adds a message. These will call the below REST web service.<br />
<br />
<pre class="brush: java">@Controller
@RequestMapping("/messages")
public class MessageAPIController {
@Inject
private MessageManager messageManager;
//
// ADD A MESSAGE
//
@RequestMapping(value = "/add", method = RequestMethod.POST,
produces = "application/json")
@ResponseBody
public Message addMessage(
@RequestParam(required = true) String text) throws Exception {
return messageManager.addMessage(text);
}
//
// LONG POLLING
//
@RequestMapping(value = "/watch", method = RequestMethod.GET,
produces = "application/json")
@ResponseBody
public DeferredResult<Message> getNewMessage() throws Exception {
return messageManager.getNewMessage();
}
}
</pre>
<br />
<br />
A further enhancement to the above to ensure messages aren't missed in between long polling requests would be to store the messages in Redis in a sorted set with the score being the message's creation timestamp. The Redis publish mechanism could then be used to tell the subscriber that there are new messages in Redis and it could then retrieve them based on the time of the last request, and return a collection of messages back to the client in the DeferredResult object.</div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<div class="p2">
<br /></div>
<br />
<div class="p2">
<br /></div>
</div>
</div>
</div>
Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-3440234688689036032013-12-06T00:57:00.000-08:002014-01-24T06:18:44.396-08:00Spring and Caching JMS ConnectionsAs follow up to previous posts covering <a href="http://city81.blogspot.co.uk/search/label/JMS">JMS</a>, this post will delve into more depth on Spring's CachingConnectionFactory.<br />
<br />
Spring provides two implementations of the javax.jms.ConnectionFactory interface, namely, the SingleConnectionFactory and the CachingConnectionFactory. The SingleConnectionFactory returns as you might expect the same single connection upon all calls to the createConnection() method. This is fine for certain scenarios and applications but the CachingConnectionFactory provides a more performant and scalable solution.<br />
<br />
By default, a single session is cached so for a multi threaded application you would set the sessionCacheSize to be a more suitable number although this number wouldn't reflect the true number of sessions cached as this figure refers to the size of cache per session acknowledgement type eg AUTO_ACKNOWLEDGE, CLIENT_ACKNOWLEDGE, DUPS_OK_ACKNOWLEDGE and SESSION_TRANSACTED.<br />
<br />
By default, the CachingConnectionFactory will cache the Message Producers and Message Consumers for every session. As an aside the Message Consumers are cached using keys which include the JMS selector so the more fine grained the message filter the more Message Consumers there would be, and Message Consumers aren't closed until the session is closed and removed from the pool. An alternative is to use a Listener Container for consuming messages.<br />
<br />
Also to be noted is that on creating a CachingConnectionFactory instance, the reconnect on exception flag is set to be true. This should mean that the onException method on the default ExceptionListener class gets called which will reset the connections. You can also override the default exception listener with your own implementation.<br />
<br />
The below snippet of XML shows a simple configuration of a CachingConnectionFactory:
<br />
<br />
<pre class="brush: xml"><bean id="jmsQueueConnectionFactory"
class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="mqConnectionFactory" />
<property name="username" value="${mq.username}" />
</bean>
<bean id="jmsConnectionFactory"
class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsQueueConnectionFactory" />
<property name="sessionCacheSize" value="50" />
<property name="exceptionListener" ref="jmsExceptionListener" />
</bean>
<bean id="jmsExceptionListener"
class="com.city81.messaging.MessageMQExceptionListener"">
<property name="cachingConnectionFactory" ref="jmsConnectionFactory" /">
</bean>
</pre>
Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.comtag:blogger.com,1999:blog-599554868473356802.post-19435898602746627332013-06-03T05:41:00.000-07:002013-07-18T00:42:42.641-07:00Exposing and Managing Links with Spring HATEOASAs a follow up to the previous <a href="http://city81.blogspot.co.uk/2013/05/spring-mvc-and-hateoas-constraint.html" target="_blank">Spring HATEOAS post</a>, this post will cover how to use the <em>@ExposesResourceFor</em> annotation as an alternative to using the resource's <em>Controller</em> to obtain links.<br />
<br />
It'll also cover how to find links based on a particular relation type in a hypermedia enabled representation.<br />
<br />
In addition to the classes in the previous post, the <em>SettlementController</em> class is responsible for settling bets and exposes one method, <em>settleBet</em>, in order to do this. To return a link to the settled bet, the <em>SettlementController</em> uses the <em>linkTo</em> method on the <em>ControllerLinkBuilder</em> class:
<br />
<br />
<pre class="brush: java">@RequestMapping(method = RequestMethod.PUT, value = "/{betId}")
ResponseEntity<SettlementResource> settleBet(@PathVariable Long betId) {
Settlement settlement = this.settlementService.settleBet(betId);
SettlementResource resource =
settlementResourceAssembler.toResource(settlement);
resource.add(
linkTo(BetController.class).slash(betId).withSelfRel());
return new ResponseEntity<SettlementResource>(resource, HttpStatus.CREATED);
}
</pre>
<br />
An alternative approach to this is to enable <em>EntityLinks</em>. By adding the<em> @ExposesResourcesFor</em> annotation to the <em>BetController</em>, the <em>SettlementController</em> need only know about the resource and not it's <em>Controller</em> class.<br />
<br />
<pre class="brush: java">@Controller
@ExposesResourceFor(Bet.class)
@RequestMapping("/bets")
public class BetController {
...
}
</pre>
<br />
The <em>SettlementController</em> by way of the <em>EntityLinks</em> interface can now obtain the link to a single resource or a link to a resource collection. It can either get the <em>Link</em> or a <em>LinkBuilder. </em>With the latter approach, the relation types can be overwritten:<br />
<br />
<br />
<pre class="brush: java">@Controller
@RequestMapping("/settlements")
public class SettlementController {
private SettlementService settlementService;
private SettlementResourceAssembler settlementResourceAssembler;
private EntityLinks entityLinks;
@Autowired
public SettlementController(SettlementService settlementService,
SettlementResourceAssembler settlementResourceAssembler, EntityLinks entityLinks) {
this.settlementService = settlementService;
this.settlementResourceAssembler = settlementResourceAssembler;
this.entityLinks = entityLinks;
}
@RequestMapping(method = RequestMethod.PUT, value = "/{betId}")
ResponseEntity<SettlementResource> settleBet(@PathVariable Long betId) {
Settlement settlement = this.settlementService.settleBet(betId);
SettlementResource resource =
settlementResourceAssembler.toResource(settlement);
resource.add(this.entityLinks.linkToSingleResource(Bet.class, betId));
return new ResponseEntity<SettlementResource>(
resource, HttpStatus.CREATED);
}
}
</pre>
<em></em><br />
For a collection link, the call would be:<br />
<br />
<pre class="brush: java">resource.add(this.entityLinks.linkToCollectionResource(Bet.class));
</pre>
<br />
To obtain the builders:<br />
<br />
<pre class="brush: java">LinkBuilder linkFor = this.entityLinks.linkFor(Bet.class);
LinkBuilder linkForSingleResource =
this.entityLinks.linkForSingleResource(Bet.class, betId);
</pre>
<br />
To enable all this functionality, the <em>@EnableEntityLinks</em> annotation must be in your Spring configuration.<br />
<br />
Another useful feature that comes with Spring HATEOAS, is the ability to discover links. For a given hypermedia enabled representation, the Link Discoverer API can find a link or links for a particular relation type. For example, from the previous post, to find the cancelBet relation type link of a ResourceSupport object would be:<br />
<br />
<pre class="brush: java">LinkDiscoverer discoverer = new DefaultLinkDiscoverer();
Link link = discoverer.findLinkWithRel("cancelBet", resource.toString());
</pre>
<br />
The DefaultLinkDiscoverer will expect JSON but since 0.5 of Spring HATEOAS, the <a href="http://blog.stateless.co/post/13296666138/json-linking-with-hal" target="_blank">HAL</a> variant has been supported via the HalLinkDiscoverer class.<br />
<br />
Although still evolving, the Spring HATEOAS project provides a good foundation for implementing a HATEOAS compliant REST service. But if all you require is to expose and manage domain objects via a REST web service then the <a href="http://www.springsource.org/spring-data/rest" target="_blank">Spring Data REST</a> project which applies the HATEOAS constraint to persisted entities is worth considering and the <a href="https://github.com/olivergierke/spring-restbucks" target="_blank">Restbucks</a> example an ideal tutorial.<br />
<br />
<br />Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com3tag:blogger.com,1999:blog-599554868473356802.post-64200292325937337802013-05-09T00:32:00.000-07:002013-05-09T00:32:41.286-07:00Spring MVC and the HATEOAS constraint<a href="http://en.wikipedia.org/wiki/HATEOAS" target="_blank">HATEOAS</a> is a REST architecture principle where hypermedia is used to change application state. To change state, the returned resource representation contains links thereby 'constraining' the client on what steps to take next.<br />
<br />
The Spring-HATEOAS project aims to assist those writing Spring MVC code in the creation of such links and the assembly of resources returned to the clients. <br />
<br />
The example below will cover a simple scenario showing how links are created and returned for the resource, <em>Bet</em>. Each operation on the resource is described below:<br />
<br />
<ul>
<li><em>createBet</em> - this <em>POST</em> operation will create a Bet.</li>
<li><em>updateBet</em> - this <em>PUT</em> operation will update the Bet.</li>
<li><em>getBet</em> - this <em>GET</em> operation will retrieve a Bet.</li>
<li><em>cancelBet</em> - this <em>DELETE</em> operation will cancel the Bet.</li>
</ul>
<br />
<pre class="brush: java">@Controller
@RequestMapping("/bets")
public class BetController {
private BetService betService;
private BetResourceAssembler betResourceAssembler;
public BetController(BetService betService,
BetResourceAssembler betResourceAssembler) {
this.betService = betService;
this.betResourceAssembler = betResourceAssembler;
}
@RequestMapping(method = RequestMethod.POST)
ResponseEntity<BetResource> createBet(@RequestBody Bet body) {
Bet bet = betService.createBet(body.getMarketId(),
body.getSelectionId(), body.getPrice(), body.getStake(),
body.getType());
BetResource resource = betResourceAssembler.toResource(bet);
return new ResponseEntity<BetResource>(resource, HttpStatus.CREATED);
}
@RequestMapping(method = RequestMethod.PUT, value = "/{betId}")
ResponseEntity<BetResource> updateBet(@PathVariable Long betId,
@RequestBody Bet body) throws BetNotFoundException, BetNotUnmatchedException {
Bet bet = betService.updateBet(betId, body);
BetResource resource = betResourceAssembler.toResource(bet);
return new ResponseEntity<BetResource>(resource, HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.GET, value = "/{betId}")
ResponseEntity<BetResource> getBet(@PathVariable Long betId) throws BetNotFoundException {
Bet bet = betService.getBet(betId);
BetResource resource = betResourceAssembler.toResource(bet);
if (bet.getStatus() == BetStatus.UNMATCHED) {
resource.add(linkTo(BetController.class).slash(bet.getId()).withRel("cancel"));
}
return new ResponseEntity<BetResource>(resource, HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.GET)
ResponseEntity<List<BetResource>> getBets() {
List<Bet> betList = betService.getAllBets();
List<BetResource> resourceList = betResourceAssembler.toResources(betList);
return new ResponseEntity<List<BetResource>>(resourceList, HttpStatus.OK);
}
@RequestMapping(method = RequestMethod.DELETE, value = "/{betId}")
ResponseEntity<BetResource> cancelBet(@PathVariable Long betId) {
Bet bet = betService.cancelBet(betId);
BetResource resource = betResourceAssembler.toResource(bet);
return new ResponseEntity<BetResource>(resource, HttpStatus.OK);
}
@ExceptionHandler
ResponseEntity handleExceptions(Exception ex) {
ResponseEntity responseEntity = null;
if (ex instanceof BetNotFoundException) {
responseEntity = new ResponseEntity(HttpStatus.NOT_FOUND);
} else if (ex instanceof BetNotUnmatchedException) {
responseEntity = new ResponseEntity(HttpStatus.CONFLICT);
} else {
responseEntity = new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR);
}
return responseEntity;
}
}
</pre>
<div class="brush: java">
</div>
All the operations will create a <em>BetResource</em> for returning to the client. This is done by calling <em>toResource</em> on the <em>BetResourceAssembler class</em>:<br />
<br />
<pre class="brush: java">public class BetResourceAssembler extends ResourceAssemblerSupport<Bet, BetResource> {
public BetResourceAssembler() {
super(BetController.class, BetResource.class);
}
public BetResource toResource(Bet bet) {
BetResource resource = instantiateResource(bet);
resource.bet = bet;
resource.add(linkTo(BetController.class).slash(bet.getId()).withSelfRel());
return resource;
}
}
</pre>
<div class="brush: java">
This class extends <span class="n"><em>ResourceAssemblerSupport</em> which requires the implementation of a <em>toResource</em> method as it implements the <span class="nc"><em>ResourceAssembler</em> interface. This is where the mapping between <em>Bet</em> and <em>BetResource</em> is done. In this case, <em>BetResource</em> is just a wrapper for <em>Bet</em> so it is simply a case of setting the <em>bet</em> attribute. The <em>instantiateResource</em> method will return a <em>BetResource</em> without any links so links can be added at this point if required. In this example a link to self is added. An alternative approach would be to use <span class="nf"><em>createResourceWithId</em> which will return a <em>BetResource</em> with the self link.</span></span></span> </div>
<div class="brush: java">
<span class="n"><span class="nc"></span></span> </div>
<pre class="brush: java">public class BetResource extends ResourceSupport {
public Bet bet;
}
</pre>
<div class="brush: java">
</div>
<div class="brush: java">
Also in this example, links are added to the <em>BetResource</em> within the <em>BetController</em> class to ensure the application of the HATEOAS constraint. If the REST service receives a GET request then a check is made on the status of the <em>Bet</em>. If the <em>Bet</em> is <em>UNMATCHED</em>, then a link to cancel the <em>Bet</em> can be added to the <em>BetResource</em>. This is done in similar fashion to the self link but with the relationship attribute name of cancel.</div>
<div class="brush: java">
</div>
<div class="brush: java">
An alternative approach to this is to build a link to a method as opposed to constructing a URI. </div>
<div class="brush: java">
</div>
<pre class="brush: java">resource.add(linkTo(methodOn(BetController.class).cancelBet(betId))
.withRel("cancel"));
</pre>
<div class="brush: java">
</div>
<div class="brush: java">
The <em>methodOn</em> would create a proxy of the <em>BetController</em> class and as a result the return type of the <em>cancelBet</em> method would have to be capable of proxying. Therefore in this example the return type of <em>cancelBet</em> method would be<em> HttpEntity<Bet></em> and not <em>ResponseEntity<Bet>.</em> If the latter, then the likely exception from the server would be:</div>
<div class="brush: java">
</div>
<span lang="">[org.springframework.http.ResponseEntitycom.city81.hateoas.rest.BetResource> com.city81.hateoas.controller.BetController.getBet(java.lang.Long) throws com.city81.hateoas.BetNotFoundException]:org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class org.springframework.http.ResponseEntity]: common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Superclass has no null constructors but no arguments were given</span><br />
<div class="brush: java">
</div>
<div class="brush: java">
Back to the GET request, and the returned JSON for requesting a <em>Bet</em> resource which has a status of <em>UNMATC</em>HED is shown below:<br />
<span style="font-size: x-small;"></span><br />
<span style="font-size: x-small;">{</span><br />
<span style="font-size: x-small;"> "links":[</span><br />
<span style="font-size: x-small;"> {"rel":"self","href":<a href="http://localhost:8080/hateoas-1-SNAPSHOT/bets/0">http://localhost:8080/hateoas-1-SNAPSHOT/bets/0</a>},<br /> {"rel":"cancel","href":<a href="http://localhost:8080/hateoas-1-SNAPSHOT/bets/0">http://localhost:8080/hateoas-1-SNAPSHOT/bets/0</a>} </span><span style="font-size: x-small;">],</span><br />
<span style="font-size: x-small;"> "bet":{"id":0,"marketId":1,"selectionId":22,"price":4.0,"stake":2.0,"type":"BACK","status":"UNMATCHED"}</span><br />
<span style="font-size: x-small;">}
</span><br />
<br />
The client can therefore use the self link for retrieving and updating the <em>Bet</em>, and also the cancel link to effectively delete it.<br />
<br />
This post describes just some of the functionality of the Spring-HATEOAS project which is evolving all the time. For an up to date and more detailed explanation, visit the <a href="https://github.com/SpringSource/spring-hateoas" target="_blank">GitHub</a> pages.</div>
<div class="brush: java">
</div>
<div class="brush: java">
</div>
<div class="brush: java">
</div>
<div class="brush: java">
</div>
Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com4tag:blogger.com,1999:blog-599554868473356802.post-76939537238583621482013-04-04T02:28:00.000-07:002013-04-04T02:28:06.312-07:00Mocking Static Methods in GroovyUsing Groovy to test not only other Groovy classes but also Java classes is an increasing popular approach given frameworks like Spock which facilitate Test Driven and Behaviour Driven Development. <br />
<br />
A common problem when testing though is having to deal with legacy code and more often than not having to mock static methods calls. When writing tests in Groovy, the approach to mocking static calls will depend on the type of class you're testing and what type of class has the static method in.<br />
<br />
If the Groovy class you're testing makes calls a static method on another Groovy class, then you could use the ExpandoMetaClass which allows you to dynamically add methods, constructors, properties and static methods. The below Account Groovy class has a static method called getType(). The Customer Groovy class you're trying to test calls the getType() static method within it's getAccountType() method:<br />
<br />
<br />
<pre class="brush: groovy">class Customer {
String getAccountType() {
return Account.getType();
}
}
class Account {
static String getType() {
return "Personal";
}
}
class CustomerTest extends GroovyTestCase {
void testGetAccountType() {
Customer cust = new Customer()
assert cust.getAccountType() == "Personal"
Account.metaClass.static.getType = {return "Business"}
assert cust.getAccountType() == "Business"
}
}
</pre>
<br />
The CustomerTest Groovy class shows how the getType static method can be overridden using the metaClass property. This isn't strictly mocking, more dynamically changing a class. An alternative approach is to use Spock's GroovyMock to achieve a similar result. (A more detailed description of Spock's mocking and stubbing features can be found <a href="http://docs.spockframework.org/en/latest/interaction_based_testing.html#groovymocks" target="_blank">here</a>:)<br />
<br />
<br />
<pre class="brush: groovy">import spock.lang.*
class CustomerTest extends Specification {
def "get account type"() {
setup:
GroovyMock(Account, global: true)
Account.getType() >> "Business"
Customer cust = new Customer()
when: "obtaining a customer's account type"
def type = cust.getAccountType()
then: "the type will be a Business account"
type == "Business"
}
}
</pre>
<br />
If the Account class is a Java not Groovy class then we can still mock it out using the above methods. The problem with mocking Java static methods though, when using Groovy for testing, is when they are called from Java classes and these calling classes are the ones you are trying to test. <br />
<br />
For example, if we now have a Customer Java class and also an Account Java class, and a CustomerTest Groovy class, the ExpandoMetaClass and GroovyMock approaches will not work globally but will work locally. The below CustomerTest will pass.<br />
<br />
<br />
<pre class="brush: java">public class Customer {
public String getAccountType() {
return Account.getType();
}
}
public class Account {
public static String getType() {
return "Personal";
}
}
</pre>
<pre class="brush: groovy">class CustomerTest extends GroovyTestCase {
void testGetAccountType() {
Customer cust = new Customer()
assert cust.getAccountType() == "Personal"
Account.metaClass.static.getType = {return "Business"}
assert Account.getType() == "Business"
assert cust.getAccountType() == "Personal"
}
}
</pre>
<br />
The way around this is to use a mocking framework like Powermock or JMockit. The below amended CustomerTest Groovy class shows how Powermock can be integrated into a GroovyTestCase:<br />
<br />
<br />
<pre class="brush: groovy">import groovy.mock.interceptor.*
import org.powermock.api.mockito.PowerMockito;
import static org.mockito.Mockito.*;
import org.powermock.core.classloader.annotations.PrepareForTest
import org.junit.runner.RunWith;
import org.powermock.modules.junit4.PowerMockRunner
@RunWith( PowerMockRunner.class )
@PrepareForTest(Account.class)
class CustomerTest extends GroovyTestCase {
public void testGetAccountType() {
Customer cust = new Customer()
assert cust.getAccountType() == "Personal"
PowerMockito.mockStatic(Account.class);
when(Account.getType()).thenReturn("Business");
assert cust.getAccountType() == "Business"
}
}
</pre>
Using Mockito's when to mock the return value of the static getType() call enables "Business" to be returned instead of "Personal".
This example shows how when writing Groovy tests to test Java classes, using a framework like Powermock can fill the void of mocking Java static methods when called from the Java classes you are trying to test.
Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-40850612858509014922013-02-27T02:29:00.000-08:002013-03-21T12:29:53.638-07:00JSON, POJOs and Groovy's HTTPBuilder class<br />
<div class="MsoNormal" style="margin: 0cm 0cm 10pt; mso-layout-grid-align: none; mso-pagination: none;">
<span lang="EN" style="mso-ansi-language: EN; mso-ascii-font-family: Calibri; mso-bidi-font-family: Calibri; mso-hansi-font-family: Calibri;"><span style="font-family: inherit;"><span style="font-family: inherit;">Whilst previous posts have looked at the use of <em>RESTClient</em>, this post will concentrate on its parent class, <em>HTTPBuilder</em> and also touch briefly on the <em>JSONBuilder</em> class. This post will cover the building and parsing of JSON, converting JSON to and from POJOs, adding authentication headers and handling response success and failures.<br />
<br />
The <em>HTTPBuilder</em> class provides an API to make HTTP requests and parse the responses, and builds upon the Apache <em>AbstractHttpClient</em> class. The <em>HTTPBuilder</em> class can be instantiated with a URI to be used as default for all request methods. A default content type can also be supplied but for this example it will be the instantiated default of <em>ContentType.ANY</em>. <br />
<br />
The below method takes an AccountFilter POJO, creates a <em>JSONBuilder</em> object and instantiates a <em>HTTPBuilder</em> with the default URI. It then makes a request specifying the method (POST) and contentType (JSON). The request body will be converted to a url-encoded form string. The code also shows how headers can be set, in this case, X-Application and X-Authentication using instance variables.</span></span></span><br />
<span lang="EN" style="mso-ansi-language: EN; mso-ascii-font-family: Calibri; mso-bidi-font-family: Calibri; mso-hansi-font-family: Calibri;"><span style="font-family: inherit;"><span style="font-family: inherit;"><br /></span></span></span>
<span lang="EN" style="mso-ansi-language: EN; mso-ascii-font-family: Calibri; mso-bidi-font-family: Calibri; mso-hansi-font-family: Calibri;"><span style="font-family: inherit;"><span style="font-family: inherit;">NOTE: The request is retrieving data and not creating or updating data, so would normally be a GET but the criteria can be complex and nested and therefore needs to be sent as JSON in the request body, hence the use of POST. (There is whole discussion on the web about GET requests containing a request body.) </span></span></span><br />
<span lang="EN" style="mso-ansi-language: EN; mso-ascii-font-family: Calibri; mso-bidi-font-family: Calibri; mso-hansi-font-family: Calibri;"><span style="font-family: inherit;"></span></span><br />
<span lang="EN" style="mso-ansi-language: EN; mso-ascii-font-family: Calibri; mso-bidi-font-family: Calibri; mso-hansi-font-family: Calibri;"><span style="font-family: inherit;">
</span></span><br />
<pre class="brush: groovy">Set<Customer> listCustomers(AccountFilter accountFilter) {
def resultList = new ArrayList<Customer>()
def builder = new JsonBuilder(accountFilter)
def http = new HTTPBuilder( 'https://beta-api.city81.com/json-rpc' )
// POST request
http.request (POST, JSON){req->
body = [
"jsonrpc" : "2.0",
"method" : "Bank/v1.0/listCustomers",
"params" : builder.toString(),
"id" : 1
]
headers.'X-Application' = this.applicationKey
headers.'X-Authentication' = this.sessionToken
// success response handler
response.success = { resp, json ->
json.result.each {
resultList.add(new Customer(
it.customer.id, it.customer.name))
}
}
// failure response handler
response.failure = { resp ->
println "Unexpected error: ${resp.statusLine.statusCode}"
println ${resp.statusLine.reasonPhrase}
}
}
return resultList
}
</pre>
<span style="font-family: inherit;">The success response handler will iterate over the JSON result set and create <em>Customer</em> objects adding them to a collection. The failure response handler will print out the status code and reason phrase for the failure of the POST request.<br />
<br />
As mentioned above, the code uses <em>JSONBuilder</em> to turn the POJO into JSON. For a <em>Filter</em> POJO with the field accountIds set, the JSON would appear as below:</span>
<br />
<span style="font-family: Calibri;"></span><br />
<span style="font-family: Calibri;">"params":{"filter":{"accountIds":[1]}}<br />
</span><br />
<span style="font-family: inherit;">There is a flaw with this though in that if the filter attribute of MarketFilter is not set then the Filter tag will not be present in the JSON. If the service you are POSTing to requires this as its mandatory (albeit empty) then the req body params line would be:</span>
<span style="font-family: Calibri;"></span><br />
<br />
<span style="font-family: Calibri;">"params" : [filter:[:]], <br />
<br />
</span><span style="font-family: inherit;">which would generate JSON:</span>
<br />
<span style="font-family: Calibri;"></span><br />
<span style="font-family: Calibri;">"param": {"filter": {} }<br />
</span><br />
<span style="font-family: inherit;">This post covers only a small part of HTTPBuilder and one of a number of ways of POSTing a request, generating the JSON and parsing its response, many of which have been simplified with the RESTClient class.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">
</span>
<span style="font-family: inherit;">The POJOS used in the above example:</span>
<br />
<br />
<pre class="brush: java">public class Customer {
private String id;
private String name;
public Customer(String id, String name) {
this.id = id;
this.name = name;
}
// ... getters and setters
}
public class AccountFilter {
private Filter filter;
public AccountFilter(Filter filter) {
this.filter = filter;
}
// ... getters and setters
}
public class Filter {
private Set<String> accountIds;
// ... getters and setters
}
</pre>
</div>
Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-65277092436029987562012-11-26T22:51:00.000-08:002012-11-27T00:51:14.626-08:00Groovy's RESTClient with Spock ExtensionsGroovy has an extension to its <em>HTTPBuilder</em> class called <em>RESTClient</em> which makes it fairly easy to test a RESTful web service. This post will describe how to use the <em>RESTClient</em>, how to inject it into a Groovy Spock test class via custom annotations, how to swap the injected client between a real one and a mocked one using Mockito, and how to test it.<br />
<br />
The <em>RESTClient</em> class provides methods to perform the HTTP's GET, POST, PUT and DELETE methods. The <em>RESTClient</em> instance can be constructed with a url string and optionally a content type. The HTTP methods can then be called with a named parameter list. For example, the below code will create a <em>RESTClient</em> instance and call the get method passing in the path and a path parameter:<br />
<br />
<pre class="brush: groovy">def client = new RESTClient("http://localhost:8080/testWebService/")
def resp = client.get(path : "server/status/ServerOne")
</pre>
<br />
The response returned is an instance of <em>HttpResponseDecorator</em>. This wraps the <i>HttpResponse </i>to allow for easy access to the data which is parsed depending upon the content type. The below class shows it's use within a Spock framework test and how the parsed data can be extracted from the response object. The returned XML is:<br />
<br />
<pre class="brush: xml"><serverstatus>
<servername>ServerOne</servername>
<isrunning>true</isrunning>
</serverstatus>
</pre>
<br />
then
<br />
<br />
<pre class="brush: xml"><serverstatus>
<servername>ServerTwo</servername>
<isrunning>false</isrunning>
</serverstatus>
</pre>
<div class="brush: xml">
</div>
<div class="brush: xml">
</div>
<pre class="brush: groovy"></pre>
<pre class="brush: groovy"></pre>
<pre class="brush: groovy">import groovy.util.slurpersupport.GPathResult
import groovyx.net.http.RESTClient
import spock.lang.*
import groovyx.net.http.ContentType
class InjectedRestServiceTest extends Specification {
@RESTWebClient
def client
def "Test Server Statuses"() {
when: "retrieve server status"
def resp1 = client.get(path : "server/status/ServerOne")
def resp2 = client.get(path : "server/status/ServerTwo")
then: "test server one response"
assert resp1.data.serverName.text() == "ServerOne"
assert resp1.data.isRunning.text() == "true"
then: "test server two response"
assert resp2.data.serverName.text() == "ServerTwo"
assert resp2.data.isRunning.text() == "false"
}
}
</pre>
<br />
The test asserts are purely there in this example to prove that the response from the real web service are the same as from the mocked web service. In reality, you would be testing some other functionality of which calling a RESTful web service is part of the flow. You wouldn't really assert the response from a mocked RESTClient although you may want to verify that it has been called n times.<br />
<br />
The <i>InjectedRestServiceTest </i>class has the RESTClient injected using the custom made annotation <em>@RESTWebClient</em>. There are three classes involved which enable this functionality. First the interface, which is marked as only visible at field level, contains an <em>@ExtensionAnnotation</em> specifying the class which basically tells Spock what to do when it encounters the <em>@RESTClient</em> annotation:<br />
<br />
<pre class="brush: groovy">import java.lang.annotation.ElementType
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
import java.lang.annotation.Target
import org.spockframework.runtime.extension.ExtensionAnnotation
@Retention(RetentionPolicy.RUNTIME)
@Target([ ElementType.FIELD ])
@ExtensionAnnotation(RESTWebClientAnnotationDrivenExtension)
public @interface RESTWebClient{}</pre>
<div class="brush: groovy">
</div>
<div class="brush: groovy">
</div>
The <em>RESTWebClientAnnotationDrivenExtension</em> class in this example only needs to override the <em>visitFieldAnnotation</em> method of the <em>AbstractAnnotationDrivenExtension</em> class because of the annotation's target element type:<br />
<br />
<pre class="brush: groovy">import org.spockframework.runtime.extension.AbstractAnnotationDrivenExtension
import org.spockframework.runtime.extension.AbstractMethodInterceptor
import org.spockframework.runtime.extension.IMethodInvocation
import org.spockframework.runtime.model.FieldInfo
import org.spockframework.runtime.model.SpecInfo
class RESTWebClientAnnotationDrivenExtension extends
AbstractAnnotationDrivenExtension<RESTWebClient> {
private static final String url =
System.getProperties().getProperty("url")
private static final boolean useMock =
Boolean.parseBoolean(System.getProperties().getProperty("useMock"))
@Override
void visitFieldAnnotation(RESTWebClient annotation, FieldInfo field) {
def methodInterceptor = new RESTWebClientMethodInterceptor(field, url, useMock)
methodInterceptor.install(field.parent)
}
}
</pre>
<br />
The above extension tells Spock that when it encounters <em>@RESTClient</em>, it must create an interceptor with the arguments denoting the field to which the RESTClient instance is to be set, the url of the web service and a boolean to specify if the mock is to be used or the real web service should be used. (The meaning of the two values could be combined to just have a url and if set then the real web service must be used.)<br />
<br />
The interceptor will create either a mock RESTClient or a real one. It will do this when the client field needs to be set in the InjectedRestServiceTest class. If the real RESTClient is required then an instance using the url will be created and set using the <em>fieldInfo.writeValue</em> method. If a mock is required then a Mockito mock RESTClient is created and the expected behaviour mocked using instances of the class <em>HttpResponseDecorator</em> (although these could be mocks too.) Again, this is set using the<em> fieldInfo.writeValue</em> method. The mocking code should probably be in its own method or even class but for this simple example its within the <em>setupRESTClient</em> method:<br />
<br />
<pre class="brush: groovy">import groovy.mock.interceptor.MockFor
import groovyx.net.http.HttpResponseDecorator
import groovyx.net.http.RESTClient
import org.spockframework.runtime.extension.AbstractMethodInterceptor;
import org.spockframework.runtime.extension.IMethodInvocation;
import org.spockframework.runtime.model.FieldInfo;
import org.spockframework.runtime.model.SpecInfo;
import static org.mockito.Mockito.*
import static org.mockito.Matchers.*
class RESTWebClientMethodInterceptor extends AbstractMethodInterceptor {
private final FieldInfo fieldInfo
private final String url
private final boolean useMock
RESTWebClientMethodInterceptor(FieldInfo fieldInfo, String url, boolean useMock) {
this.fieldInfo = fieldInfo
this.url = url
this.useMock = useMock
}
@Override
void interceptSetupMethod(IMethodInvocation methodInvocation) {
setupRESTClient(methodInvocation.target)
methodInvocation.proceed()
}
@Override
void install(SpecInfo specInfo) {
specInfo.setupMethod.addInterceptor this
}
private void setupRESTClient(target) {
if (useMock) {
def xmlServerOne =
"""
<serverStatus>
<serverName>ServerOne</serverName>
<isRunning>true</isRunning>
</serverStatus>
"""
def xmlServerTwo =
"""
<serverStatus>
<serverName>ServerTwo</serverName>
<isRunning>false</isRunning>
</serverStatus>
"""
def httpResponseDecoratorServerOne = new HttpResponseDecorator(
null, new XmlParser().parseText(xmlServerOne))
def httpResponseDecoratorServerTwo = new HttpResponseDecorator(
null, new XmlParser().parseText(xmlServerTwo))
def mapServerOne = [path:"server/status/ServerOne"]
def mapServerTwo = [path:"server/status/ServerTwo"]
RESTClient mockRESTClient = org.mockito.Mockito.mock(RESTClient)
when(mockRESTClient.get(mapServerOne)).thenReturn(httpResponseDecoratorServerOne);
when(mockRESTClient.get(mapServerTwo)).thenReturn(httpResponseDecoratorServerTwo);
fieldInfo.writeValue(target, mockRESTClient)
}
else {
fieldInfo.writeValue(target, new RESTClient(url))
}
}
}
</pre>
<br />
Whilst there are different ways to mock and test RESTful web services, the above classes do show how easily RESTful web services can be called and their responses parsed, how annotations can be created and how objects can be mocked. Similar examples could be constructed for different aspects of a Spock test eg features, fixtures etc.. <br />
<br />
More can be found on extensions at <a href="http://code.google.com/p/spock/wiki/SpockBasics#Extensions">http://code.google.com/p/spock/wiki/SpockBasics#Extensions</a> and on RESTClient at <a href="http://groovy.codehaus.org/modules/http-builder/doc/rest.html">http://groovy.codehaus.org/modules/http-builder/doc/rest.html</a><br />
<br />Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-17870497327054249172012-09-14T03:59:00.000-07:002012-09-14T03:59:20.966-07:00Using Spock to test Spring classesAs the previous <a href="http://city81.blogspot.co.uk/2012/09/testing-java-using-spock-framework.html" target="_blank">post</a> mentioned, Spock is a powerful DSL built on Groovy ideal for TDD and BDD testing and this post will describe how easy it is to use Spock to test Spring classes, in this case the CustomerService class from the post <a href="http://city81.blogspot.co.uk/2012/07/using-spring-data-to-access-mongodb.html" target="_blank">Using Spring Data to access MongoDB</a>. It will also cover using Spock for mocking.<br />
<br />
Spock relies heavily on the Spring's TestContext framework and does this via the <span style="font-family: "Courier New", Courier, monospace;">@ContextConfiguration</span> annotation. This allows the test specification class to load an application context from one or more locations.<br />
<br />
This will then allow the test specification to access beans either via the annotation <span style="font-family: "Courier New", Courier, monospace;">@Autowired</span> or <span style="font-family: "Courier New", Courier, monospace;">@Resource</span>. The test below shows how an injected <span style="font-family: "Courier New", Courier, monospace;">CusotmerService</span> instance can be tested using Spock and the Spring TestContext: (This is a slightly contrived example as to properly unit test the <span style="font-family: "Courier New", Courier, monospace;">CustomerService</span> class as you would create a <span style="font-family: "Courier New", Courier, monospace;">CustomerService</span> class in the test as opposed to one created and injected by Spring.)<br />
<br />
<pre class="brush: groovy">package com.city81.mongodb.springdata.dao
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration
import spock.lang.*
import com.city81.mongodb.springdata.entity.Account
import com.city81.mongodb.springdata.entity.Address
import com.city81.mongodb.springdata.entity.Customer
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
class CustomerServiceTest extends Specification {
@Autowired
CustomerService customerService
def setup() {
customerService.dropCustomerCollection()
}
def "insert customer"() {
setup:
// setup test class args
Address address = new Address()
address.setNumber("81")
address.setStreet("Mongo Street")
address.setTown("City")
address.setPostcode("CT81 1DB")
Account account = new Account()
account.setAccountName("Personal Account")
List<Account> accounts = new ArrayList<Account>()
accounts.add(account)
Customer customer = new Customer()
customer.setAddress(address)
customer.setName("Mr Bank Customer")
customer.setAccounts(accounts)
when:
customerService.insertCustomer(customer)
then:
def customers = customerService.findAllCustomers()
customers.size == 1
customers.get(0).name == "Mr Bank Customer"
customers.get(0).address.street == "Mongo Street"
}
}
</pre><br />
The problem though with the above test is that MongoDB needs to be up and running so to remove this dependency we can Mock out the interaction the database. Spock's mocking framework provides many of the features you'd find in similar frameworks like Mockito.<br />
<br />
The enhanced <span style="font-family: "Courier New", Courier, monospace;">CustomerServiceTest</span> mocks the <span style="font-family: "Courier New", Courier, monospace;">CustomerRepository</span> and sets the mocked object on the <span style="font-family: "Courier New", Courier, monospace;">CustomerService</span>. <br />
<br />
<pre class="brush: groovy">package com.city81.mongodb.springdata.dao
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.test.context.ContextConfiguration
import spock.lang.*
import com.city81.mongodb.springdata.entity.Account
import com.city81.mongodb.springdata.entity.Address
import com.city81.mongodb.springdata.entity.Customer
@ContextConfiguration(locations = "classpath:spring/applicationContext.xml")
class CustomerServiceTest extends Specification {
@Autowired
CustomerService customerService
CustomerRepository customerRepository = Mock()
def setup() {
customerService.customerRepository = customerRepository
customerService.dropCustomerCollection()
}
def "insert customer"() {
setup:
// setup test class args
Address address = new Address()
address.setNumber("81")
address.setStreet("Mongo Street")
address.setTown("City")
address.setPostcode("CT81 1DB")
Account account = new Account()
account.setAccountName("Personal Account")
List<Account> accounts = new ArrayList<Account>()
accounts.add(account)
Customer customer = new Customer()
customer.setAddress(address)
customer.setName("Mr Bank Customer")
customer.setAccounts(accounts)
when:
customerService.insertCustomer(customer)
then:
1 * customerRepository.save(customer)
}
def "find all customers"() {
setup:
// setup test class args
Address address = new Address()
address.setStreet("Mongo Street")
Customer customer = new Customer()
customer.setAddress(address)
customer.setName("Mr Bank Customer")
// setup mocking
def mockCustomers = []
mockCustomers << customer
customerRepository.findAll() >> mockCustomers
when:
def customers = customerService.findAllCustomers()
then:
customers.size() == 1
customers.get(0).name == "Mr Bank Customer"
}
}
</pre><br />
The <span style="font-family: "Courier New", Courier, monospace;">CustomerRepository</span> is by way of name and type although it could be inferred by just the name eg<br />
<br />
<pre class="brush: groovy">def customerRepository = Mock(CustomerRepository)
</pre><br />
The injected <span style="font-family: "Courier New", Courier, monospace;">customerRepository</span> is overwritten by the mocked instance and then in the test setup, functionality can be mocked. <br />
<br />
In the <span style="font-family: "Courier New", Courier, monospace;">then</span> block of the <span style="font-family: "Courier New", Courier, monospace;">insert customer</span> feature, the number of interactions with the <span style="font-family: "Courier New", Courier, monospace;">save</span> method of <span style="font-family: "Courier New", Courier, monospace;">customerRepository</span> is tested and in the <span style="font-family: "Courier New", Courier, monospace;">find all customers</span> feature, the return list of customers from the <span style="font-family: "Courier New", Courier, monospace;">findAll</span> call is a mocked <span style="font-family: "Courier New", Courier, monospace;">List,</span>as opposed to one retrieved from the database. <br />
<br />
More detail on Spock's mocking capabilities can be found on the project's <a href="http://code.google.com/p/spock/wiki/Interactions" target="_blank">home page</a>.<br />
<br />
<br />
Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com2tag:blogger.com,1999:blog-599554868473356802.post-87078684383358262702012-09-11T03:08:00.001-07:002012-09-11T03:09:48.711-07:00Testing Java using the Spock FrameworkThe testing framework Spock is a powerful DSL built on Groovy which enables easily writable and extremely readable tests which lends itself well to software development processes like TDD and BDD.<br />
<br />
As an example of how much clarity Spock and Groovy bring to testing I'll compare it with the tests for the ForkJoinPool example class <a href="http://city81.blogspot.co.uk/2012/01/parallel-processing-with-forkjoinpool.html" target="_blank">InterpolationService</a>. <br />
<br />
Every Spock test (or specification) extends <span style="font-family: "Courier New", Courier, monospace;">spock.lang.Specification</span>. This abstract class uses Spock's JUnit runner, <span style="font-family: "Courier New", Courier, monospace;">org.spockframework.runtime.Sputnik</span>, and contains useful methods for writing tests eg creating mock objects<br />
<br />
There are four main aspects to a specification: Fields, Fixtures, Features and Helpers. There is no point going into depth on each as there are well documented on the <a href="http://code.google.com/p/spock/wiki/SpockBasics" target="_blank">Spock Basics wiki</a> but we'll certainly concentrate on Features with respect to the comparison with the JUnit <span style="font-family: "Courier New", Courier, monospace;">InterpolationService</span> tests.<br />
<br />
Features are instance methods which must contain at least one block where a block is one of six methods: setup, when, then, expect, cleanup and where. The blocks setup and cleanup are as you might expect but others are described in more detail below.<br />
<br />
First though and the first few lines of the <span style="font-family: "Courier New", Courier, monospace;">InterpolationServiceTest</span> are shown below:<br />
<br />
<pre class="brush: groovy">package com.city81.interpolation.service
import spock.lang.*
class InterpolateServiceTest extends Specification {
@Shared def interpolateService = new InterpolateService()
</pre><br />
The class under test ie <span style="font-family: "Courier New", Courier, monospace;">InterpolationService</span> is marked as being <span style="font-family: "Courier New", Courier, monospace;">@Shared</span> (ie all features use the same instance). This annotation is ideal for expensive resources like a DB connection.<br />
<br />
Next the first feature which tests the interpolation of two numbers with an even number of steps:<br />
<br />
<pre class="brush: groovy">def "interpolate two numbers with even no. of steps"() {
expect:
interpolateService.interpolate(a, b, c) == d
where:
a | b | c | d
5.0 | 25.0 | 4 | [5.0, 10.0, 15.0, 20.0, 25.0]
}
</pre><br />
<br />
The equivalent JUnit assert test method would be:<br />
<br />
<pre class="brush: java">@Test
public void testInterpolateTwoValues() {
List<Double> interpolatedList =
interpolateService.interpolate(5.0, 25.0, 4);
assertEquals(5, interpolatedList.size());
assertEquals(5.0, interpolatedList.get(0), 0);
assertEquals(10.0, interpolatedList.get(1), 0);
assertEquals(15.0, interpolatedList.get(2), 0);
assertEquals(20.0, interpolatedList.get(3), 0);
assertEquals(25.0, interpolatedList.get(4), 0);
}
</pre><br />
<br />
The clarity in what you are testing is easy to see and it is so easy with Spock just to add another where line to test another scenario:<br />
<br />
<pre class="brush: groovy">def "interpolate two numbers with even no. of steps"() {
expect:
interpolateService.interpolate(a, b, c) == d
where:
a | b | c | d
5.0 | 25.0 | 4 | [5.0, 10.0, 15.0, 20.0, 25.0]
2.0 | 14.0 | 6 | [2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0]
}
</pre><br />
It is also worth noting at this point that Groovy uses <span style="font-family: "Courier New", Courier, monospace;">BigDecimal</span> for floating number numbers but if you want to denote doubles then numbers can be appended with a d eg 5.0d, -15.0d<br />
<br />
Whilst the above demonstrates the expect and where blocks, the below shows how to test for exceptions using when and then blocks:<br />
<br />
<pre class="brush: groovy">def "interpolate two numbers where first arg is null"() {
when:
interpolateService.interpolate(null, 25.0, 4)
then:
thrown(IllegalArgumentException)
}
</pre><br />
An alternative approach to using <span style="font-family: "Courier New", Courier, monospace;">thrown(IllegalArgumentException)</span> could be to bind a variable to access the exception:<br />
<br />
<pre class="brush: groovy">then:
IllegalArgumentException e = thrown()
e.cause == InterpolateService.VALUE_ARG_NOT_NULL_EXCP_TEXT
</pre><br />
You can also use the when and then blocks to order interactions although not if the first when throws an exception.<br />
<br />
There is much more on Spock on it's <a href="http://code.google.com/p/spock/" target="_blank">Google code</a> pages and the above only describes a few basics but the next post will look at Mocking and also examine it's use with Spring by testing code from a previous post. Might even get the Groovy code formatting working by then too!<br />
<br />
Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-87608011426289385652012-07-13T05:41:00.000-07:002012-10-04T05:54:47.375-07:00Using Spring Data to access MongoDBSpring Data is the data access Spring project for integrating with data stores. This post will cover the Spring Data sub project for accessing the document store MongoDB. It follows on from the <a href="http://city81.blogspot.co.uk/2012/07/using-morphia-to-map-java-objects-in.html" target="_blank">Morphia</a> post by showing how Spring Data for MongoDB would persist and query the same POJOs.<br />
<br />
The four domain objects are shown below: <br />
<br />
<pre class="brush: java">package com.city81.mongodb.springdata.entity;
import org.springframework.data.annotation.Id;
public abstract class BaseEntity {
@Id
protected String id;
private Long version;
public BaseEntity() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
}
</pre>
<br />
<pre class="brush: java">package com.city81.mongodb.springdata.entity;
import java.util.List;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class Customer extends BaseEntity {
private String name;
private List<Account> accounts;
private Address address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
</pre>
<br />
<pre class="brush: java">package com.city81.mongodb.springdata.entity;
public class Address {
private String number;
private String street;
private String town;
private String postcode;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getPostcode() {
return postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
}
</pre>
<br />
<pre class="brush: java">package com.city81.mongodb.springdata.entity;
import org.springframework.data.mongodb.core.mapping.Document;
@Document
public class Account extends BaseEntity {
private String accountName;
public String getAccountName() {
return accountName;
}
public void setAccountName(String accountName) {
this.accountName = accountName;
}
}
</pre>
<br />
Some classes are marked with the @Document annotation. This is optional but does allow you to provide a collection name eg <br />
<br />
<pre class="brush: java">@Document(collection="personalBanking")
</pre>
<br />
<span style="font-family: Times New Roman; font-size: small;"><span style="font-family: Times New Roman; font-size: small;"></span></span><br />
Also in the Customer class, the Address and Accounts attributes would be stored as embedded within the document but they can be stored separately by marking the variables with @DBRef. These objects will then be eagerly loaded when the Customer record is retrieved.<br />
<br />
Next, using XML based metadata to register a MongoDB instance and a MongoTemplate instance. <br />
<br />
The MongoFactoryBean is used to register an instance of com.mongodb.Mongo. Using the Bean as opposed to creating an instance of Mongo itself ensures that the calling code doesn't have to handle the checked exception UnknownHostException. It also ensures database specific exceptions are translated to be Spring exceptions of the DataAccessException hierarchy.<br />
<br />
The MongoTemplate provides the operations (via the MongoOperations interface) to interact with MongoDB documents. This thread safe class has several constructors but for this example we only need to call the one that takes an instance of Mongo and the database name.<br />
<br />
Whilst you could call the operations on the MongoTemplate to manage the entities, there exists a MongoRepository interface which can be extended to be 'document' specific via the use of Generics. The <em><mongo:repositories base-package="com.city81.mongodb.springdata.dao" /></em> registers beans extending this interface.<br />
<br />
<br />
<br />
<pre class="brush: 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"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
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
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">
<context:annotation-config />
<context:component-scan base-package="com.city81.mongodb.springdata" />
<!-- MongoFactoryBean instance -->
<bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">
<property name="host" value="localhost" />
</bean>
<!-- MongoTemplate instance -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg name="mongo" ref="mongo" />
<constructor-arg name="databaseName" value="bank" />
</bean>
<mongo:repositories base-package="com.city81.mongodb.springdata.dao" />
</beans>
</pre>
<br />
The repository class in this example is the CustomerRepository. It gets wired with the MongoTemplate so provides the same (this time implicit type safe) operations but also provides the ability to add other methods. In this example, a find method has been added to demonstrate how a query can be built from the method name itself. There is no need to implement this method as Spring Data will parse the method name and determine the criteria ie findByNameAndAddressNumberAndAccountsAccountName will return documents where the customer name is equal to the first arg (name), and where the customer address number is equal to the second arg (number) and where the customer has an account which has an account name equal to the thrid arg (accountName).<br />
<br />
<br />
<pre class="brush: java">package com.city81.mongodb.springdata.dao;
import java.util.List;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
import com.city81.mongodb.springdata.entity.Customer;
@Repository
public interface CustomerRepository extends MongoRepository<Customer,String> {
List<Customer> findByNameAndAddressNumberAndAccountsAccountName(
String name, String number, String accountName);
}
</pre>
<br />
In this example, we'll add a service layer in the form of the CustomerService class, which for this simple example just wraps the repository calls. The class has the CustomerRepository wired in and this service class is then in turn called from the Example class, which performs similar logic to the Morphia Example class.<br />
<br />
<pre class="brush: java">package com.city81.mongodb.springdata.dao;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.city81.mongodb.springdata.entity.Customer;
@Service
public class CustomerService {
@Autowired
CustomerRepository customerRepository;
public void insertCustomer(Customer customer) {
customerRepository.save(customer);
}
public List<Customer> findAllCustomers() {
return customerRepository.findAll();
}
public void dropCustomerCollection() {
customerRepository.deleteAll();
}
public List<Customer> findSpecificCustomers(
String name, String number, String accountName) {
return customerRepository.findByNameAndAddressNumberAndAccountsAccountName(
name, number, accountName);
}
}
</pre>
<br />
<pre class="brush: java">package com.city81.mongodb.springdata;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.city81.mongodb.springdata.dao.CustomerService;
import com.city81.mongodb.springdata.entity.Account;
import com.city81.mongodb.springdata.entity.Address;
import com.city81.mongodb.springdata.entity.Customer;
public class Example {
public static void main( String[] args ) {
ConfigurableApplicationContext context
= new ClassPathXmlApplicationContext("spring/applicationContext.xml");
CustomerService customerService = context.getBean(CustomerService.class);
// delete all Customer records
customerService.dropCustomerCollection();
Address address = new Address();
address.setNumber("81");
address.setStreet("Mongo Street");
address.setTown("City");
address.setPostcode("CT81 1DB");
Account account = new Account();
account.setAccountName("Personal Account");
List<Account> accounts = new ArrayList<Account>();
accounts.add(account);
Customer customer = new Customer();
customer.setAddress(address);
customer.setName("Mr Bank Customer");
customer.setAccounts(accounts);
// insert a Customer record into the database
customerService.insertCustomer(customer);
address = new Address();
address.setNumber("101");
address.setStreet("Mongo Road");
address.setTown("Town");
address.setPostcode("TT10 5DB");
account = new Account();
account.setAccountName("Business Account");
accounts = new ArrayList<Account>();
accounts.add(account);
customer = new Customer();
customer.setAddress(address);
customer.setName("Mr Customer");
customer.setAccounts(accounts);
// insert a Customer record into the database
customerService.insertCustomer(customer);
// find all Customer records
System.out.println("\nALL CUSTOMERS:");
List<Customer> allCustomers = customerService.findAllCustomers();
for (Customer foundCustomer : allCustomers) {
System.out.println(foundCustomer.getId() + " " + foundCustomer.getName());
System.out.println(foundCustomer.getAddress().getTown());
System.out.println(foundCustomer.getAccounts().get(0).getAccountName() + "\n");
}
// find by customer name, address number and account name
System.out.println("\nSPECIFIC CUSTOMERS:");
List<Customer> specficCustomers = customerService.findSpecificCustomers(
"Mr Customer","101","Business Account");
for (Customer foundCustomer : specficCustomers) {
System.out.println(foundCustomer.getId() + " " + foundCustomer.getName());
System.out.println(foundCustomer.getAddress().getTown());
System.out.println(foundCustomer.getAccounts().get(0).getAccountName() + "\n");
}
}
}
</pre>
The output from the above would look similiar to the below:<br />
<br />
<pre class="brush: java">04-Oct-2012 13:48:48 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@15eb0a9: startup date [Thu Oct 04 13:48:48 BST 2012]; root of context hierarchy
04-Oct-2012 13:48:48 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [spring/applicationContext.xml]
04-Oct-2012 13:48:48 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1c92535: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,customerService,mongo,mongoTemplate,customerRepository,org.springframework.data.repository.core.support.RepositoryInterfaceAwareBeanPostProcessor#0]; root of factory hierarchy
ALL CUSTOMERS:
506d85b115503d4c92392c79 Mr Bank Customer
City
Personal Account
506d85b115503d4c92392c7a Mr Customer
Town
Business Account
SPECIFIC CUSTOMERS:
506d85b115503d4c92392c7a Mr Customer
Town
Business Account
</pre>
<br />
<br />
This is a brief overview of Spring Data from MongoDB but there are many other facets to this project including MappingConverters, Compound Indexes and MVC support. For more info <a href="http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/">http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/</a>Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com9tag:blogger.com,1999:blog-599554868473356802.post-77368208007768885272012-07-11T06:04:00.002-07:002012-07-13T00:11:51.919-07:00Using Morphia to map Java objects in MongoDBMongoDB is an open source document-oriented NoSQL database system which stores data as JSON-like documents with dynamic schemas. As it doesn't store data in tables as is done in the usual relational database setup, it doesn't map well to the JPA way of storing data. Morphia is an open source lightweight type-safe library designed to bridge the gap between the MongoDB Java driver and domain objects. It can be an alternative to SpringData if you're not using the Spring Framework to interact with MongoDB.<br />
<br />
This post will cover the basics of persisting and querying entities along the lines of JPA by using Morphia and a MongoDB database instance.<br />
<br />
There are four POJOs this example will be using. First we have BaseEntity which is an abstract class containing the Id and Version fields:<br />
<br />
<pre class="brush: java">package com.city81.mongodb.morphia.entity;
import org.bson.types.ObjectId;
import com.google.code.morphia.annotations.Id;
import com.google.code.morphia.annotations.Property;
import com.google.code.morphia.annotations.Version;
public abstract class BaseEntity {
@Id
@Property("id")
protected ObjectId id;
@Version
@Property("version")
private Long version;
public BaseEntity() {
super();
}
public ObjectId getId() {
return id;
}
public void setId(ObjectId id) {
this.id = id;
}
public Long getVersion() {
return version;
}
public void setVersion(Long version) {
this.version = version;
}
}
</pre><br />
Whereas JPA would use @Column to rename the attribute, Morphia uses @Property. Another difference is that @Property needs to be on the variable whereas @Column can be on the variable or the get method.<br />
<br />
The main entity we want to persist is the Customer class:<br />
<br />
<pre class="brush: java">package com.city81.mongodb.morphia.entity;
import java.util.List;
import com.google.code.morphia.annotations.Embedded;
import com.google.code.morphia.annotations.Entity;
@Entity
public class Customer extends BaseEntity {
private String name;
private List<Account> accounts;
@Embedded
private Address address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
</pre><br />
As with JPA, the POJO is annotated with @Entity. The class also shows an example of @Embedded:<br />
<br />
The Address class is also annotated with @Embedded as shown below:<br />
<br />
<pre class="brush: java">package com.city81.mongodb.morphia.entity;
import com.google.code.morphia.annotations.Embedded;
@Embedded
public class Address {
private String number;
private String street;
private String town;
private String postcode;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getTown() {
return town;
}
public void setTown(String town) {
this.town = town;
}
public String getPostcode() {
return postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
}
</pre>Finally, we have the Account class of which the customer class has a collection of:<br />
<br />
<pre class="brush: java">package com.city81.mongodb.morphia.entity;
import com.google.code.morphia.annotations.Entity;
@Entity
public class Account extends BaseEntity {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
</pre><br />
The above show only a small subset of what annotations can be applied to domain classes. More can be found at <a href="http://code.google.com/p/morphia/wiki/AllAnnotations">http://code.google.com/p/morphia/wiki/AllAnnotations</a><br />
<br />
The Example class shown below goes through the steps involved in connecting to the MongoDB instance, populating the entities, persisting them and then retrieving them:<br />
<br />
<pre class="brush: java">package com.city81.mongodb.morphia;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import com.city81.mongodb.morphia.entity.Account;
import com.city81.mongodb.morphia.entity.Address;
import com.city81.mongodb.morphia.entity.Customer;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Key;
import com.google.code.morphia.Morphia;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/**
* A MongoDB and Morphia Example
*
*/
public class Example {
public static void main( String[] args ) throws UnknownHostException, MongoException {
String dbName = new String("bank");
Mongo mongo = new Mongo();
Morphia morphia = new Morphia();
Datastore datastore = morphia.createDatastore(mongo, dbName);
morphia.mapPackage("com.city81.mongodb.morphia.entity");
Address address = new Address();
address.setNumber("81");
address.setStreet("Mongo Street");
address.setTown("City");
address.setPostcode("CT81 1DB");
Account account = new Account();
account.setName("Personal Account");
List<Account> accounts = new ArrayList<Account>();
accounts.add(account);
Customer customer = new Customer();
customer.setAddress(address);
customer.setName("Mr Bank Customer");
customer.setAccounts(accounts);
Key<Customer> savedCustomer = datastore.save(customer);
System.out.println(savedCustomer.getId());
}
</pre><br />
Executing the first few lines will result in the creation of a Datastore. This interface will provide the ability to get, delete and save objects in the 'bank' MongoDB instance.<br />
<br />
The mapPackage method call on the morphia object determines what objects are mapped by that instance of Morphia. In this case all those in the package supplied. Other alternatives exist to map classes, including the method map which takes a single class (this method can be chained as the returning object is the morphia object), or passing a Set of classes to the Morphia constructor.<br />
<br />
After creating instances of the entities, they can be saved by calling save on the datastore instance and can be found using the primary key via the get method. The output from the Example class would look something like the below:<br />
<br />
<pre class="brush: java">11-Jul-2012 13:20:06 com.google.code.morphia.logging.MorphiaLoggerFactory chooseLoggerFactory
INFO: LoggerImplFactory set to com.google.code.morphia.logging.jdk.JDKLoggerFactory
4ffd6f7662109325c6eea24f
Mr Bank Customer
</pre><br />
There are many other methods on the Datastore interface and they can be found along with the other Javadocs at <a href="http://morphia.googlecode.com/svn/site/morphia/apidocs/index.html">http://morphia.googlecode.com/svn/site/morphia/apidocs/index.html</a><br />
<br />
An alternative to using the Datastore directly is to use the built in DAO support. This can be done by extending the BasicDAO class as shown below for the Customer entity:<br />
<br />
<pre class="brush: java">package com.city81.mongodb.morphia.dao;
import com.city81.mongodb.morphia.entity.Customer;
import com.google.code.morphia.Morphia;
import com.google.code.morphia.dao.BasicDAO;
import com.mongodb.Mongo;
public class CustomerDAO extends BasicDAO<Customer, String> {
public CustomerDAO(Morphia morphia, Mongo mongo, String dbName) {
super(mongo, morphia, dbName);
}
}
</pre>To then make use of this, the Example class can be changed (and enhanced to show a query and a delete):<br />
<br />
<pre class="brush: java">...
CustomerDAO customerDAO = new CustomerDAO(morphia, mongo, dbName);
customerDAO.save(customer);
Query<Customer> query = datastore.createQuery(Customer.class);
query.and(
query.criteria("accounts.name").equal("Personal Account"),
query.criteria("address.number").equal("81"),
query.criteria("name").contains("Bank")
);
QueryResults<Customer> retrievedCustomers = customerDAO.find(query);
for (Customer retrievedCustomer : retrievedCustomers) {
System.out.println(retrievedCustomer.getName());
System.out.println(retrievedCustomer.getAddress().getPostcode());
System.out.println(retrievedCustomer.getAccounts().get(0).getName());
customerDAO.delete(retrievedCustomer);
}
...
</pre><br />
With the output from running the above shown below:<br />
<br />
<pre class="brush: java">11-Jul-2012 13:30:46 com.google.code.morphia.logging.MorphiaLoggerFactory chooseLoggerFactory
INFO: LoggerImplFactory set to com.google.code.morphia.logging.jdk.JDKLoggerFactory
Mr Bank Customer
CT81 1DB
Personal Account
</pre><br />
This post only covers a few brief basics of Morphia but shows how it can help bridge the gap between JPA and NoSQL.Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com3tag:blogger.com,1999:blog-599554868473356802.post-44687407256316960562012-05-03T21:00:00.000-07:002012-05-03T21:00:02.553-07:00Using Spring @Profile with @EnableAspectJAutoProxyA new feature introduced in Spring 3.1 is the ability to mark components as being ready for registration if one or more 'profiles' (logical groupings) have been activated. The activation of the profiles is done at runtime either through a system property (-Dspring.profiles.active=xxx) or programmatically by calling the setActiveProfiles method on the ConfigurableEnvironment interface.<br />
<br />
A common example of using profiles is to have different datasource beans for different environments eg a local jdbc datasource for a profile of dev but a jndi datasource for a profile of prod. This post though will describe a simple example of using @Profile to switch between different aspects when in different profiles.<br />
<br />
Also as this example will use annotations and no XML, it will briefly cover the ability to enable AspectJ auto proxying using the new annotation @EnableAspectJAutoProxy.<br />
<br />
The below CustomerApplication class has one simple task and that is to process a Customer object. In order to do that, the CustomerService bean needs to be obtained from the context and the context in this example is an AnnotationConfigApplicationContext. <br />
<br />
This type of context will register annotated classes with the package prefix of <em>com.city81</em>. Classes marked with @Profile but not dev will be ignored. (More than one profile can be specified as setActiveProfiles takes an array of Strings.)<br />
<br />
<br />
<pre class="brush: java">public class CustomerApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("dev");
ctx.scan("com.city81");
ctx.refresh();
Customer address = new Customer();
address.setId("idOne");
address.setName("custOne");
address.setAge(21);
address.setAddress("addressOne");
CustomerService customerService = ctx.getBean(CustomerService.class);
customerService.processCustomer(address);
}
}
</pre>
As we're using Spring configuration programmatically, the getBean method on the context is able find the CustomerService bean as we have a CustomerServiceConfig class which is annotated with @Configuration. This allows the container to generate bean definitions at runtime.<br />
<br />
<pre class="brush: java">@Configuration
@EnableAspectJAutoProxy
public class CustomerServiceConfig {
@Bean
public CustomerService customerService() {
return new CustomerServiceImpl();
}
}
</pre>
This is the class that also includes @EnableAspectJAutoProxy. Prior to Spring 3.1, auto proxying AspectJ could be done using <code><aop:aspectj-autoproxy></code> but now @Configuration classes can include the @EnableAspectJAutoProxy annotation thereby enabling support for classes annotated with @Aspect.<br />
<br />
In this example, there are two classes marked with @Aspect. Both extend an abstract class which defines the pointcut.<br />
<br />
<pre class="brush: java">public abstract class LoggingAspect {
@Pointcut("execution(* com.city81.service.CustomerService.processCustomer(..))")
public void processCustomer() {
}
}
@Configuration
@Profile("prod")
@Aspect
public class ConciseLoggingAspect extends LoggingAspect {
@Before("processCustomer()")
public void logCustomerId(JoinPoint jp) {
Customer customer = (Customer) jp.getArgs()[0];
System.out.println("id = " + customer.getId());
}
}
@Configuration
@Profile("dev")
@Aspect
public class VerboseLoggingAspect extends LoggingAspect {
@Before("processCustomer()")
public void logCustomerAll(JoinPoint jp) {
Customer customer = (Customer) jp.getArgs()[0];
System.out.println("id = " + customer.getId());
System.out.println("name = " + customer.getName());
System.out.println("age = " + customer.getAge());
System.out.println("address = " + customer.getAddress());
}
}
</pre>
In this example, there are two profiles, dev and prod, and depending on the profile activated there will be a different level of (contrived) 'logging'. <br />
<br />
Each concrete LoggingAspect class contains an @Profile annotation. This can specify one or more profiles. Therefore in the case of using ctx.getEnvironment().setActiveProfiles("dev") only VerboseLoggingAspect will be registered.<br />
<br />
This post shows how easy it is to create profiles and activate them programmatically although it can be done just as easily using XML config.<br />
<br />
<br />Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-33584747738707103862012-04-25T22:00:00.000-07:002012-04-25T22:00:00.278-07:00Hibernate and Multiple BagsCertain associations an Entity can have can be deemed 'bags' by Hibernate. A bag is an unordered collection that permits duplicate elements and when persisting these collections, the order of elements cannot be guaranteed. For these reasons, bags are an efficient way of representing a collection as you can add to a bag collection without the collection having been loaded. An example of a bag would be an ArrayList.<br />
<br />
When designing the mapping between the objects and the database ie building entities, thought must be given to the type of associations between the entities and the fetching strategy for each association.<br />
<br />
A common problem encountered when modelling entities using Hibernate is that of multiple bags. ie when an Entity contains two or more associations which are bags that have a fetch strategy of EAGER. This could be an Entity which has two member collections like the Company class below, or an Entity that contains collections within its object graph, for example, the Company class may contain a collection of Buildings which in turn has a collection of MeetingRooms. <br />
<br />
(Note: BaseEntity contains Id and Version fields.)<br />
<br />
<br />
<pre class="brush: java">@Entity
public class Company extends BaseEntity {
private List<Department> departments;
private List<String> shareholders;
@OneToMany(fetch=FetchType.EAGER)
@Cascade(value ={CascadeType.SAVE_UPDATE, CascadeType.DELETE_ORPHAN})
@JoinColumn(name="CO_ID")
public List<Department> getDepartments() {
return this.departments;
}
public void setDepartments(List<Department> departments) {
this.departments = departments;
}
@CollectionOfElements(fetch=FetchType.EAGER,targetElement=java.lang.String.class)
@JoinTable(name="CO_SHR",joinColumns=@JoinColumn(name="CO_ID"))
@Column(name="CO_SHR")
public List<String> getShareholders() {
return this.shareholders;
}
public void setShareholders(List<String> shareholders) {
this.shareholders = shareholders;
}
}
</pre>
<br />
<br />
The Hibernate exception when identifying more than one bag to fetch is shown below:<br />
<br />
Caused by: org.hibernate.HibernateException: cannot simultaneously fetch multiple bags<br />
at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:66)<br />
at org.hibernate.loader.entity.EntityLoader.<init>(EntityLoader.java:75)<br />
<br />
There are a few ways to resolve this problem once the offending association(s) have been identified. One option is to make all or all but one collection have a fetch strategy of LAZY. This is the default strategy for Hibernate. This would mean that LAZY associations would not be loaded until requested but if requested outside of a session, this would raise a LazyInitializationException. One way to get around this is to load the collection when in a session. For example, if the Company -> Departments association is changed to be @OneToMany, the collection can be loaded as described below using Hibernate.initialize:<br />
<br />
<br />
<pre class="brush: java"> public Company findById(String id) {
HibernateTemplate ht = getHibernateTemplate();
Company company = (Company) ht.get(Company.class, id);
Hibernate.initialize(company.getDepartments());
return company;
}
</pre>
<br />
<br />
Another option is to revise the type of collection being used. Does it have to be java.util.List? An alternative could be to use java.util.Set which isn't treated by Hibernate as a bag. An example of this would be to change the Company -> Shareholders association to be a SortedSet as shown below:<br />
<br />
<br />
<pre class="brush: java"> private SortedSet<String> shareholders;
@CollectionOfElements(fetch=FetchType.EAGER,targetElement=java.lang.String.class)
@JoinTable(name="CO_SHR",joinColumns=@JoinColumn(name="CO_ID"))
@Column(name="CO_SHR")
@Sort(type=SortType.NATURAL)
public SortedSet<String> getShareholders() {
return this.shareholders;
}
</pre>
<br />
<br />
(Note that if you use HashSet, the retrieved collection may not be in the same order as it was persisted.)<br />
<br />
<br />
If it must be java.util.List, then another solution is to use @IndexColumn which would mean the Collection semantic is that of List and not Bag. As well as a name, the Index can have a base number which if not specified will default to zero.<br />
<br />
<br />
<pre class="brush: java"> @CollectionOfElements(fetch=FetchType.EAGER,targetElement=java.lang.String.class)
@JoinTable(name="CO_SHR",joinColumns=@JoinColumn(name="CO_ID"))
@Column(name="CO_SHR")
@IndexColumn(name="IDX",base=1)
public List<String> getShareholders() {
return this.shareholders;
}
</pre>
<br />
<br />
This post highlights the need to think carefully about all associations and pose questions like what needs to be EAGERly loaded, what is the effect on memory usage, etc...Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-28290673798057618462012-03-22T04:11:00.000-07:002012-03-22T04:11:14.234-07:00RestTemplate and Spring MVCThis post is a follow up to the <a href="http://city81.blogspot.co.uk/2012/01/spring-mvc-and-restful-web-services.html" target="_blank">Spring MVC and RESTful Web Services</a> post and shows a simple example of using Spring's <span style="font-family: "Courier New", Courier, monospace;">RestTemplate</span> class for client side access to, in this case, the Spring MVC RESTful web service built in the aforementioned post.<br />
<br />
The <span style="font-family: "Courier New", Courier, monospace;">RestTemplate</span> class is, as it's javadoc describes, "<strong>the central class for client-side HTTP access.</strong> It simplifies communication with HTTP servers, and enforces RESTful principles. It handles HTTP connections, leaving application code to provide URLs (with possible template variables) and extract results."<br />
<br />
In this example, we'll only be using the GET HTTP method (as that is all we have on our MVC example!) but the idea will be pretty much the same for other methods.<br />
<br />
First, the Spring config and the XML below lists three beans. The <span style="font-family: "Courier New", Courier, monospace;">Jaxb2Marshaller</span> bean lists the classes that the JAXBContext needs to be aware of. This bean is then in turn injected into the <span style="font-family: "Courier New", Courier, monospace;">MarshallingHttpMessageConverter</span> as the marshaller and unmarshaller so Objects can be converted to and from an XML Stream. (Note that by default the <span style="font-family: "Courier New", Courier, monospace;">MarshallingHttpMessageConverter</span> supports <code>text/xml</code> and <code>application/xml.) </code>For this example, the message converter is the only entry in the list set on the <span style="font-family: "Courier New", Courier, monospace;">RestTemplate</span> bean. Finally, the <span style="font-family: "Courier New", Courier, monospace;">RestTemplate</span> bean is injected into the <span style="font-family: "Courier New", Courier, monospace;">ExampleControllerClient</span> bean.<br />
<br />
<br />
<pre class="brush: xml"><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="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.city81.spring.mvc.rest.domain.Message</value>
</list>
</property>
</bean>
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean id="messageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxbMarshaller" />
<property name="unmarshaller" ref="jaxbMarshaller" />
</bean>
</list>
</property>
</bean>
<bean id="exampleControllerClient" class="com.city81.spring.mvc.rest.ExampleControllerClient">
<constructor-arg ref="restTemplate" />
</bean>
</beans>
</pre><br />
The <span style="font-family: "Courier New", Courier, monospace;">ExampleControllerClient</span> class below shows how simple it is to make a RESTful web service call:<br />
<br />
<pre class="brush: java">package com.city81.spring.mvc.rest;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.client.RestTemplate;
import com.city81.spring.mvc.rest.domain.Message;
public class ExampleControllerClient {
private RestTemplate restTemplate;
public ExampleControllerClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public void getMessage() {
Message message = restTemplate.getForObject(
"http://localhost:8080/spring-rest-0.0.1-SNAPSHOT/example/controller/message",
Message.class);
System.out.println(message.getMessageString());
}
public static void main(String[] args) {
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
new String[] {"applicationContext.xml"});
BeanFactory factory = (BeanFactory) appContext;
ExampleControllerClient client = (ExampleControllerClient) factory
.getBean("exampleControllerClient");
client.getMessage();
}
}
</pre><br />
The <span style="font-family: "Courier New", Courier, monospace;">getForObject</span> method takes a URL and the type of the response object and retrieves a representation by doing a GET on the URL arg. This method is overloaded and can be used for different URLs. For example, if there are URI templates in the URL, then these can be populated by a third arg of a Map containing a collection of name value pairs or by using varargs.<br />
<br />
<br />
<pre class="brush: java">public <t> T getForObject(String url,
Class<t> responseType,
Object... urlVariables)
throws RestClientException
public <t> T getForObject(String url,
Class<t> responseType,
Map<string,?> urlVariables)
throws RestClientException
</pre><br />
Back to the example and when the <span style="font-family: "Courier New", Courier, monospace;">getForObject</span> call is invoked, the JAXB marshaller behind the scenes will convert the XML into a Message object. An alternative to using the <span style="font-family: Courier New;">Jaxb2Marshaller</span> is the <span style="font-family: "Courier New", Courier, monospace;">XStreamMarshaller</span>. To swap JAXB for XStream would just be a Spring XML change as shown below:<br />
<br />
<br />
<pre class="brush: xml"><bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="message">com.city81.spring.mvc.rest.domain.Message</prop>
</props>
</property>
</bean>
...
<property name="marshaller" ref="xstreamMarshaller" />
<property name="unmarshaller" ref="xstreamMarshaller" />
...
</pre><br />
There are many different marshallers to achieve the same goal, and indeed many different media types with different marshallers. This post barely scratches the surface but just shows how simple it is to create client side code for calling a RESTful web service.Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-38451612037832976222012-01-31T03:11:00.000-08:002012-02-03T00:34:30.540-08:00Parallel Processing with ForkJoinPoolWith the release of Java 7 came the new Executor Service, <span style="font-family: "Courier New", Courier, monospace;">ForkJoinPool</span>. The class uses the notion of work-stealing threads which execute tasks which have been created by other tasks. Ultimately, this division of work will result in large problems becoming a series of smaller ones which will eventually result in one answer when all the tasks have completed their processing. <br />
<br />
This post will demonstrate this new threading feature by an interpolation example. In this case, for two numbers with a given number of steps, the code will attempt to construct new points between those numbers using linear interpolation, and for simplicity using only a number of steps divisible by 2. eg for the numbers 5 and 25 with a step number of 4, the generated sequence would be:<br />
<br />
[<strong>5.0</strong>, 10.0, 15.0, 20.0, <strong>25.0</strong>]<br />
<br />
The <span style="font-family: "Courier New", Courier, monospace;">InterpolationService</span> class below will contain an instance of the <span style="font-family: "Courier New", Courier, monospace;">ForkJoinPool</span> class. A <span style="font-family: "Courier New", Courier, monospace;">ForkJoinPool</span> instance can be created with an argument representing a target parallelism. This can either be supplied or left as the default which will be the number of processors ie <code><span style="font-family: "Courier New", Courier, monospace;">Runtime.availableProcessors()</span></code><br />
<br />
<pre class="brush: java">package com.city81.forkjoin;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
public class InterpolateService {
private final ForkJoinPool forkJoinPool;
public InterpolateService() {
forkJoinPool = new ForkJoinPool();
}
public List<Double> interpolate(double valueOne, double valueTwo, int steps) {
ForkJoinTask<List<Double>> job = forkJoinPool.submit(
new InterpolateTask(valueOne, valueTwo, steps));
return job.join();
}
private static class InterpolateTask
extends RecursiveTask<List<Double>> {
private final double valueOne;
private final double valueTwo;
private final int steps;
private static final int LOWEST_STEP = 2;
protected InterpolateTask(double valueOne, double valueTwo, int steps) {
this.valueOne = valueOne;
this.valueTwo = valueTwo;
this.steps = steps;
}
@Override
protected List<Double> compute() {
List<Double> interpolatedArray = new ArrayList<Double>();
double interpolatedValue = interpolate(valueOne, valueTwo);
if (this.steps == LOWEST_STEP) {
interpolatedArray.add(valueOne);
interpolatedArray.add(interpolatedValue);
interpolatedArray.add(valueTwo);
} else {
InterpolateTask interpolateTask1 =
new InterpolateTask(valueOne, interpolatedValue, (steps/2));
interpolateTask1.fork();
InterpolateTask interpolateTask2 =
new InterpolateTask(interpolatedValue, valueTwo, (steps/2));
List<Double> interpolatedArrayTask2 =
interpolateTask2.compute();
List<Double> interpolatedArrayTask1 =
interpolateTask1.join();
interpolatedArray.addAll(
interpolatedArrayTask1.subList(0, interpolatedArrayTask1.size() - 1));
interpolatedArray.addAll(interpolatedArrayTask2);
}
// System.out.println(interpolatedArray);
return interpolatedArray;
}
private double interpolate(
double valueOne, double valueTwo) {
return ((valueTwo - valueOne) / 2.0) + valueOne;
}
}
public static void main(String[] args) {
InterpolateService interpolateService = new InterpolateService();
List<Double> interpolatedArray = interpolateService.interpolate(5,25,4);
System.out.println(interpolatedArray);
}
}
</pre><br />
The <span style="font-family: "Courier New", Courier, monospace;">InterpolationService</span> 's only public method <span style="font-family: "Courier New", Courier, monospace;">interpolate</span>, takes two numbers and the number of steps. These are the parameters to construct an instance of our private static class <span style="font-family: "Courier New", Courier, monospace;">InterpolateTask</span>. This class implements <span style="font-family: "Courier New", Courier, monospace;">RecursiveTask</span> which can return a result when the compute method is called on the task. An alternative implementation (but not suitable for this example) would be <span style="font-family: "Courier New", Courier, monospace;">RecursiveAction</span> whose compute method returns nothing.<br />
<br />
The constructed task is submitted to the <span style="font-family: "Courier New", Courier, monospace;">ForkJoinPool</span>.<br />
<br />
The <span style="font-family: "Courier New", Courier, monospace;">compute</span> method is where the logic for subdividing the task resides. It decides whether the work it has to process is small enough to process now or whether it needs further division. In the case of our example, the task will determine a task small enough when the step size is 2. If not, it will create two sub tasks, dividing the step size each time.<br />
<br />
Eventually, all tasks will be of a small enough size to be completed. This will result in the arrays being added together as the recursive task tree is traversed back up to the original task.<br />
<br />
This is not example of how to efficiently perform linear interpolation on a set of numbers but is just one example implementation of how to use the <span style="font-family: "Courier New", Courier, monospace;">ForkJoinPool</span> and its associated Task classes. Over time, hopefully this post can be updated to make the above code more efficient as well gathering metrics and benchmarking against other implementations.Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-54877280897381224592012-01-27T00:38:00.000-08:002012-02-03T01:09:06.390-08:00Spring MVC and RESTful Web ServicesThis post is a follow up to the <a href="http://city81.blogspot.com/2011/11/spring-mvc-bare-essentials-example.html" target="_blank">Spring MVC Bare Essentials</a> post and shows how a simple RESTful web service can be implemented using Spring MVC. It'll also show the different ways in which the controller services can be implemented and how the model can be rendered. <br />
<br />
The post will use the same classes and XML files as in the Bare Essentials post but change them to make the methods expoed by the controller RESTful. <br />
<br />
First of all, the <span style="font-family: "Courier New", Courier, monospace;">ExampleController</span> class will change to use web bind annotations which will mark the class and the methods within it with URL paths. <br />
<br />
<pre class="brush: java">@Controller
@RequestMapping("/controller")
public class ExampleController {
@RequestMapping(value="message", method=RequestMethod.GET)
public ModelAndView getMessage() {
Message message = new Message("Spring MVC Rest Example");
ModelAndView modelAndView = new ModelAndView(
"example", "message", message);
return modelAndView;
}
}
</pre><br />
The <span style="font-family: "Courier New", Courier, monospace;">web.xml</span> below shows the changes to the servlet mapping tag and in particular the url-pattern. This means our URLs will be:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;"><em>http://<ip>:<port>/<app name>/<strong>example</strong>/<request mapping></em></span><br />
<br />
<pre class="brush: xml"><servlet-mapping>
<servlet-name>springMVCRESTExample</servlet-name>
<url-pattern>/example/*</url-pattern>
</servlet-mapping>
</pre><br />
In <span style="font-family: inherit;">the servlet's context</span> XML file, we'll auto detect the <span style="font-family: "Courier New", Courier, monospace;">ExampleController</span> bean by using <span style="font-family: Courier New;">context:component-scan</span><span style="font-family: inherit;"> and then add the</span><span style="font-family: Times New Roman;"> </span><span style="font-family: Courier New;">BeanNameViewResolver</span><span style="font-family: inherit;"> to interpret a view name as a bean name. Finally, add a</span><span style="font-family: Times New Roman;"> <span style="font-family: "Courier New", Courier, monospace;">MarshallingView</span> <span style="font-family: inherit;">which will use JAX-B to marshall and unmarshall the</span> </span><span style="font-family: Courier New;">com.city81.spring.mvc.rest.domain.Message </span><span style="font-family: Times New Roman;"><span style="font-family: inherit;">class</span>. </span><br />
<br />
<pre class="brush: xml">
<context:component-scan base-package="com.city81.spring.mvc.rest" />
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />
<bean id="example" class="org.springframework.web.servlet.view.xml.MarshallingView">
<constructor-arg>
<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.city81.spring.mvc.rest.domain.Message</value>
</list>
</property>
</bean>
</constructor-arg>
</bean>
</pre><br />
Building a WAR and deploying to a container such as Tomcat would then enable you call the <span style="font-family: "Courier New", Courier, monospace;">getMessage</span> method of the <span style="font-family: "Courier New", Courier, monospace;">ExampleController</span> class with the URL:<br />
<br />
<span style="font-family: Courier New;"><em>http://<ip>:<port>/<app name>/<strong>example/controller/message</strong></em></span><br />
<br />
An alternative to implementing the <span style="font-family: "Courier New", Courier, monospace;">getMessage</span> method is to use the <span style="font-family: "Courier New", Courier, monospace;">@ModelAttribute</span> instead the the <span style="font-family: "Courier New", Courier, monospace;">ModelView</span> class as shown below:<br />
<br />
<pre class="brush: java">@RequestMapping(value = "message", method = RequestMethod.GET)
public @ModelAttribute("example") Message getMessage() {
Message message = new Message("Spring MVC Rest Example");
return message;
}
</pre><br />
Another alternative is to use <span style="font-family: "Courier New", Courier, monospace;"><mvc:annotation-driven /></span> which was introduced in Spring 3. By adding it to the servlet's context XML file (in place of the beans <span style="font-family: "Courier New", Courier, monospace;">BeanNameViewResolver</span> and <span style="font-family: "Courier New", Courier, monospace;">MarshallingView</span>), the <span style="font-family: "Courier New", Courier, monospace;">getMessage</span> method can then be implemented as show below:<br />
<br />
<pre class="brush: java">@RequestMapping(value="message", method = RequestMethod.GET)
public @ResponseBody Message getMessage() {
Message message = new Message("Spring MVC Rest Example");
return message;
}
</pre><br />
This is a very simple example that can be built upon to use different RESTful methods. There are also different ways in which XML can be rendered in the view and also different types that can be rendered eg text. It is also worth considering Spring Roo if wanting to implement a RESTful web service. These will hopefully be covered in further posts.Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-89301042092973250592012-01-19T08:11:00.000-08:002012-02-03T06:37:09.488-08:00Using Maven to Generate Wrapped or Non-Wrapped SOAP BindingsFor a given WSDL, there are several different ways to generate Java web service code (CXF, Axis2, etc..). And depending on certain settings within the WSDL file and settings used by the relevant build tool, there are different ways of exposing those services described in the WSDL.<br />
<br />
This post will briefly document the generating of Java code for a WSDL using Maven and the <span style="font-family: "Courier New", Courier, monospace;">jaxws wsimport</span> plugin. It will also show the difference in the services exposed when using wrapped and non-wrapped bindings.<br />
<br />
Below is an extract from a pom.xml to generate the Java code:<br />
<br />
<pre class="brush: xml"><plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>1.10</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlFiles>
<wsdlFile>City81SOAPService.wsdl</wsdlFile>
</wsdlFiles>
<bindingDirectory>${basedir}/src/wsdl</bindingDirectory>
</configuration>
<id>generate-sources</id>
<phase>generate-sources</phase>
</execution>
</executions>
<dependencies>
.........
</dependencies>
<configuration>
<sourceDestDir>
${project.build.directory}/generated-sources/jaxws-wsimport
</sourceDestDir>
<xnocompile>true</xnocompile>
<verbose>true</verbose>
<extension>true</extension>
<catalog>${basedir}/src/jax-ws-catalog.xml</catalog>
</configuration>
</plugin>
</pre><br />
For the below WSDL file, the wsimport plugin will generate the following classes:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">com\city81\soap\Balance.java<br />
com\city81\soap\City81SOAP.java<br />
com\city81\soap\City81SOAPImplService.java<br />
com\city81\soap\CreateCustomer.java<br />
com\city81\soap\CreateCustomerResponse.java<br />
com\city81\soap\CreateCustomerResponseType.java<br />
com\city81\soap\CreateStatus.java<br />
com\city81\soap\ObjectFactory.java<br />
com\city81\soap\package-info.java</span><br />
<br />
<pre class="brush: xml"><?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions name="City81SOAPService" targetNamespace=http://soap.city81.com/ xmlns:ns1=http://schemas.xmlsoap.org/wsdl/soap/http
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://soap.city81.com/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:types>
<xsd:schema>
<xsd:import namespace="http://soap.city81.com/" schemaLocation="City81SOAPService.xsd" />
</xsd:schema>
</wsdl:types>
<wsdl:message name="createCustomer">
<wsdl:part name="params" element="tns:createCustomer"></wsdl:part>
</wsdl:message>
<wsdl:message name="createCustomerResponse">
<wsdl:part name="params" element="tns:createCustomerResponse"></wsdl:part>
</wsdl:message>
<wsdl:portType name="City81SOAP">
<wsdl:operation name="createCustomer">
<wsdl:input message="tns:createCustomer"></wsdl:input>
<wsdl:output message="tns:createCustomerResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="City81SOAPImplServiceSoapBinding" type="tns:City81SOAP">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="createCustomer">
<soap:operation soapAction="http://soap.city81.com/createCustomer" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="City81SOAPImplService">
<wsdl:port binding="tns:City81SOAPImplServiceSoapBinding" name="City81SOAPImplPort">
<soap:address location=http://localhost:8080/city81-soap/soap />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
</pre><br />
For the above settings, the generated <span style="font-family: "Courier New", Courier, monospace;">City81SOAP</span> class will be as below:<br />
<br />
<pre class="brush: java">@WebService(name = "City81SOAP", targetNamespace = "http://soap.city81.com/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
ObjectFactory.class
})
public interface City81SOAP {
@WebMethod(action = "http://soap.city81.com/createCustomer")
@WebResult(name = "createCustomerResponse", targetNamespace = "http://soap.city81.com/", partName = "params")
public CreateCustomerResponse createCustomer(@WebParam(name = "createCustomer", targetNamespace = "http://soap.city81.com/", partName = "params") CreateCustomer params);
}
</pre><br />
The binding style as can be seen from the <span style="font-family: Courier New;">@SOAPBinding</span> annotation at the head of the class is BARE ie non-wrapped. The method's args and return parameters are in each case represented as a single Java object. <span style="font-family: "Courier New", Courier, monospace;">CreateCustomer</span> and <span style="font-family: "Courier New", Courier, monospace;">CreateCustomerResponse</span>.<br />
<br />
This has happened because in the pom.xml file, there is a <span style="font-family: "Courier New", Courier, monospace;">bindingDirectory</span> tag which points to a folder containing a <span style="font-family: "Courier New", Courier, monospace;">binding.xml</span> file. This file, shown below, has an <span style="font-family: "Courier New", Courier, monospace;">enableWrapperStyle</span> tag and the boolean value of false. <br />
<br />
<pre class="brush: xml"><bindings
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
wsdlLocation="City81SOAPService.wsdl"
xmlns="http://java.sun.com/xml/ns/jaxws">
<!-- Disable default wrapper style -->
<enableWrapperStyle>false</enableWrapperStyle>
</bindings>
</pre><br />
If the boolean was true, or if there was no <span style="font-family: "Courier New", Courier, monospace;">bindingDirectory</span> tag in the pom.xml file, then the default SOAP binding style would be used ie <span style="font-family: "Courier New", Courier, monospace;">WRAPPED</span>. This would then result in the below generated <span style="font-family: Courier New;">City81SOAP</span> class:<br />
<br />
<pre class="brush: java">@WebService(name = "City81SOAP", targetNamespace = "http://soap.city81.com/")
@XmlSeeAlso({
ObjectFactory.class
})
public interface City81SOAP {
@WebMethod(action = "http://soap.city81.com/createCustomer")
@RequestWrapper(localName = "createCustomer", targetNamespace = "http://soap.city81.com/", className = "com.city81.soap.CreateCustomer")
@ResponseWrapper(localName = "createCustomerResponse", targetNamespace = "http://soap.city81.com/", className = "com.city81.soap.CreateCustomerResponse")
public void createCustomer(
@WebParam(name = "surname", targetNamespace = "")
String surname,
@WebParam(name = "firstName", targetNamespace = "")
String firstName,
@WebParam(name = "balance", targetNamespace = "")
Balance balance,
@WebParam(name = "customerId", targetNamespace = "", mode = WebParam.Mode.OUT)
Holder<String> customerId,
@WebParam(name = "status", targetNamespace = "", mode = WebParam.Mode.OUT)
Holder<CreateStatus> status);
}
</pre><br />
The method's args are now individual Java objects and the return parameters are each represented as <span style="font-family: "Courier New", Courier, monospace;">Holder</span> objects with a <span style="font-family: "Courier New", Courier, monospace;">WebParam.Mode.OUT</span> value denoting they are return objects. This means that return objects are set as opposed to actually being returned in the method's signature.<br />
<br />
Another way to specify bindings other than using the <span style="font-family: "Courier New", Courier, monospace;">binding.xml</span> file is to embed the <span style="font-family: "Courier New", Courier, monospace;">enableWrapperStyle</span> as a child of the <span style="font-family: "Courier New", Courier, monospace;">portType</span> but if a WSDL is from a third party, then having to change it every time a new version of the WSDL is released is open to errors.<br />
<br />
<pre class="brush: xml"><wsdl:portType name="City81SOAPImplService">
<jaxws:bindings xmlns:jaxws="http://java.sun.com/xml/ns/jaxws">
<jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
</jaxws:bindings>
...
</wsdl:portType>
</pre><br />
Back to the generated interfaces, and these of course need to be implemented. For an interface with a binding type of <span style="font-family: "Courier New", Courier, monospace;">BARE</span>, the implemented class would look like below:<br />
<br />
<pre class="brush: java">@WebService(targetNamespace = "http://soap.city81.com/", name = "City81SOAP", portName = "City81SOAPImplPort", serviceName = "City81SOAPImplService")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class City81SOAPImpl implements City81SOAP {
@Override
public CreateCustomerResponse createCustomer(CreateCustomer createCustomer) {
CreateCustomerResponse createCustomerResponse =
new CreateCustomerResponse();
.....
return createCustomerResponse;
}
}
</pre><br />
<pre class="code-java"><span style="font-family: Arial, Helvetica, sans-serif;">In the case of <span style="font-family: "Courier New", Courier, monospace;">WRAPPED</span> binding style, the <span style="font-family: "Courier New", Courier, monospace;">SOAPBinding</span> annotation would include <span style="font-family: "Courier New", Courier, monospace;">parameterStyle = SOAPBinding.ParameterStyle.WRAPPED</span> and the <span style="font-family: "Courier New", Courier, monospace;">createCustomer</span> method would be as below:
</span></pre><br />
<pre class="brush: java">
public void createCustomer(
String surname,
String firstName,
Balance balance,
Holder<String> customerId,
Holder<CreateStatus> status) {
customerId= new Holder<String>("1");
status = new Holder<CreateStatus>(CreateStatus.CREATE_PENDING);
}
</pre><br />
<pre class="code-java"><span style="font-family: Arial, Helvetica, sans-serif;">This post shows that there are different ways to ultimately achieve the same result.</span></pre><pre class="code-java"><span style="font-family: Arial;"></span> </pre>Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-66192156581717505952011-11-29T06:06:00.000-08:002012-02-06T05:28:56.334-08:00JAX-WS, JAXB and GenericsWhen JAXB 2.1 came along it introduced a new annotation namely <span style="font-family: "Courier New", Courier, monospace;">@XmlSeeAlso</span>. It resolved the problem where at runtime, JAX-WS would only know about classes bound by JAXB and not sub classes of those which have been bound. <br />
<br />
By using <span style="font-family: "Courier New", Courier, monospace;">@XmlSeeAlso</span> on a class, sub types of the bound class can be listed thereby allowing them to be bound also and therefore reachable by JAX-WS when marshalling and unmarshalling.<br />
<br />
It can also be used to overcome the problem of using generics in a JAXB annotated class as the following simple example will describe. Given the below <span style="font-family: "Courier New", Courier, monospace;">LogFile</span> class, it will only be marshalled/unmarshalled if the <span style="font-family: "Courier New", Courier, monospace;">T</span> at runtime is bound. <br />
<br />
<pre class="brush: java">@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class LogFile<T> {
@XmlElement(name="logFileLine")
private List<T> logFileLines;
public LogFile() {
logFileLines = new ArrayList<T>();
}
public LogFile(List<T> logFileLines) {
this.logFileLines = logFileLines;
}
public List<T> getLogFileLines() {
return logFileLines;
}
public void setLogFileLines(List<T> logFileLines) {
this.logFileLines = logFileLines;
}
public void addLogFileLine(T logFileLine) {
this.logFileLines.add(logFileLine);
}
}
</pre><br />
If <span style="font-family: "Courier New", Courier, monospace;">LogFile</span> contains a collection of eg <span style="font-family: "Courier New", Courier, monospace;">Strings</span> then this will work fine but if <span style="font-family: "Courier New", Courier, monospace;">T</span> is a class not bound, eg <span style="font-family: Courier New;">com.city81.domain.LogLine</span> then an error similar to below will be thrown:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">javax.xml.bind.MarshalException - with linked exception: [javax.xml.bind.JAXBException: class com.city81.domain.LogLine nor any of its super class is known to this context.]</span><br />
<br />
To resolve this, the class <span style="font-family: Courier New;">LogLine </span>needs to be included the <span style="font-family: "Courier New", Courier, monospace;">@XmlSeeAlso</span> annotation.<br />
<br />
<pre class="brush: java">
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso(LogLine.class)
public class LogFile<T> {
....
}
</pre><br />
This does of course mean you need to know what potential classes can be T before runtime but at least it means you can use Generics on JAXB annotated classes.Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-40457414501833222732011-11-17T20:09:00.000-08:002012-02-06T05:40:45.778-08:00Using Spring Expression Language for Server Specific Properties<span style="font-family: inherit;">Spring</span> 3.0 introduced <strong>Spring Expression Language</strong> (SpEL). This post will describe how to use SpEL to load property files which are different for each server your application runs on. It also describes how server specific properties can used without having to use -D.<br />
<br />
The problem solved was how can a WAR be deployed onto different servers without having to package up a server specific property file in each archive (or indeed bundle them all in the same WAR file.) Ideally, you would want to drop the WAR file into any environment without having to configure the container or amend the WAR, and if you wanted to change a property, you would change the property file on the server and redeploy the app (or dynamically refresh the cache of properties.)<br />
<br />
In this example, our application needs to access a different remote server registry for each env: Dev, Test and Prod. (For ease in this example, our server names are the same as our envionments!) <br />
<br />
Therefore we have a properties file for each env/server (dev.properties, test.properties and prod.properties). Could have a local.properties file on each server but prefixing them with a server name helps distinguish them. An example property file is shown below:<br />
<br />
rmiRegistryHost=10.11.12.13<br />
rmiRegistryPort=1099<br />
<br />
We have a bean which requires these properties, so it's constructor args contain property placeholders:<br />
<br />
<pre class="brush: xml"><bean id="lookupService" class="com.city81.rmi.LookupService" scope="prototype">
<constructor-arg index="0" value="${rmiRegistryHost}" />
<constructor-arg index="1" value="${rmiRegistryPort}" />
</bean>
</pre><br />
For the above bean to be loaded, the properties need to be loaded themselves and this is done via the <span style="font-family: "Courier New", Courier, monospace;">PropertyPlaceholderConfigurer</span> class. The location and name of the server specific property file is added as one of the locations the configurer uses to search for properties. <br />
<br />
The file is in the same location on each server but in order to know what the name is, SpEL is used. By creating a <span style="font-family: "Courier New", Courier, monospace;">java.net.InetAddress</span> bean, we can access the hostName of the server the application is running on by using SpEL ie <span style="font-family: "Courier New", Courier, monospace;">#{inetAddress.hostName}.</span> Therefore, this config doesn't have to change between environments.<br />
<br />
<pre class="brush: xml">
<bean id="inetAddress" class="java.net.InetAddress" factory-method="getLocalHost">
</bean>
<bean id="propertyBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="false"/>
<property name="ignoreUnresolvablePlaceholders" value="false"/>
<property name="locations">
<list>
<value>file:/home/city81/resources/#{inetAddress.hostName}.properties</value>
</list>
</property>
</bean>
</pre><br />
This is a very specific example where the property files are prefixed with the server names but it shows how SpEL can be used to solve a problem which would have taken a lot more work pre Spring 3.0.Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com1tag:blogger.com,1999:blog-599554868473356802.post-45793972019886205312011-11-16T00:17:00.000-08:002012-02-06T06:01:43.527-08:00Spring MVC - A Bare Essentials Example Using MavenSpring's MVC is a request based framework like Struts but it clearly separates the presentation, request handling and model layers.<br />
<br />
In this post, I'll describe how to get the most simple of examples up and running using Maven, therefore providing a basis upon which to add more features of Spring MVC like handler mappings, complex controllers, commons validator etc..<br />
<br />
Let's start with the <span style="font-family: "Courier New", Courier, monospace;">pom.xml</span> file. This will package up the project as a war file and only requires three dependencies namely the artifacts <span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><span style="font-size: small;">spring-webmvc, servlet-api</span> <span style="font-size: small;"><span style="font-family: "Times New Roman";">and </span>jstl</span></span>. The<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> <span style="font-size: small;">spring-webmvc</span></span> artifact will pull in all the other required spring jars like core, web, etc.<br />
<br />
<pre class="brush: xml"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.city81</groupId>
<artifactId>spring-mvc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.1-beta-1</version>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.0.5.RELEASE</version>
<optional>false</optional>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
</dependencies>
</project>
</pre><br />
Note that the scope of the <span style="font-family: "Courier New", Courier, monospace;">servlet-api</span> is provided and therefore excluded from the war file. If deployed as part of the war, there'll be conflict with the servlet jar of the container, and there'll be an error similar to the one below when deploying to Tomcat:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">INFO: Deploying web application archive spring-mvc-0.0.1-SNAPSHOT.war<br />
15-Nov-2011 16:05:27 org.apache.catalina.loader.WebappClassLoader validateJarFile<br />
INFO: validateJarFile(C:\apache-tomcat-6.0.33\webapps\spring-mvc-0.0.1-SNAPSHOT\WEB-INF\lib\servlet-api-2.5.jar) - jar not loaded. See Servlet Spec 2.3, section<br />
9.7.2. Offending class: javax/servlet/Servlet.class</span><br />
<br />
Next the <span style="font-family: "Courier New", Courier, monospace;">web.xml</span> located in the <span style="font-family: "Courier New", Courier, monospace;">/webapp/WEB-INF</span> folder:<br />
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Spring MVC Example</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>springMVCExample</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVCExample</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>home.jsp</welcome-file>
</welcome-file-list>
</web-app>
</pre>The context loader is a listener class called <span style="font-family: "Courier New", Courier, monospace;">ContextLoaderListener</span>. By default this will load the config in the /<span style="font-family: "Courier New", Courier, monospace;">WEB-INF/applicationContext.xml</span> but you can specify more files by adding a <span style="font-family: "Courier New", Courier, monospace;">contextConfigLocation</span> param and list one or more xml files. For example,<br />
<br />
<pre class="brush: xml"><context-param>
<param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/example-persistence.xml
/WEB-INF/example-security.xml</param-value></context-param>
</pre><br />
If an <span style="font-family: "Courier New", Courier, monospace;">applicationContext.xml</span> file isn't present when not using a context param list, then the WAR won't deploy properly. An example empty <span style="font-family: Courier New;">applicationContext.xml</span> is below:<br />
<br />
<pre class="brush: 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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
</beans>
</pre><br />
The servlet's configuration does not need to be explicitly specified as it can be loaded by following the same naming convention of the servlet, in this case <span style="font-family: "Courier New", Courier, monospace;">springMVCExample-servlet.xml</span>. The servlet is the front controller which delegates requests to other parts of the system. <br />
<br />
The <span style="font-family: "Courier New", Courier, monospace;">servlet-mapping</span> tags in the <span style="font-family: "Courier New", Courier, monospace;">web.xml</span> denote what URLs the <span style="font-family: "Courier New", Courier, monospace;">DispatcherServlet</span> will handle. In this example HTML.<br />
<br />
Also included in the <span style="font-family: "Courier New", Courier, monospace;">web.xml</span> by way of the <span style="font-family: "Courier New"; font-size: x-small;"><span style="font-size: small;">welcome-file</span>, </span>is a default home page. This doesn't have to be included but the page can be used to forward a request as can be seen later in the post.<br />
<br />
As mentioned previously, the servlet's config is in it's own XML file. This describes the mapping between the a URL and the <span style="font-family: "Courier New", Courier, monospace;">Controller</span> which will handle the request. It also contains the a <span style="font-family: "Courier New", Courier, monospace;">ViewResolver</span> which maps the view name in the <span style="font-family: "Courier New", Courier, monospace;">ModelAndView</span> to an actual view. The <span style="font-family: "Courier New", Courier, monospace;">springMVCExample-servlet.xml</span> is shown below:<br />
<br />
<pre class="brush: 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-3.0.xsd">
<bean name="/example.htm" class="com.city81.spring.mvc.ExampleController">
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
</pre><br />
The <span style="font-family: "Courier New", Courier, monospace;">ExampleController</span> class is shown below. It extends <span style="font-family: "Courier New", Courier, monospace;">AbstractController</span> therefore must implement the method <span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"><span style="font-size: small;">handleRequestInternal(HttpServletRequest request, HttpServletResponse response</span>).</span> The return value of this method is a <span style="font-family: "Courier New", Courier, monospace;">ModelAndView</span> object. This object is constructed by passing in the view name (example), the model name (message) and the model object (in this case a String)<br />
<br />
<pre class="brush: java">
package com.city81.spring.mvc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
public class ExampleController extends AbstractController {
protected ModelAndView handleRequestInternal(
HttpServletRequest request, HttpServletResponse response)
throws Exception {
ModelAndView modelAndView = new ModelAndView("example", "message", "Spring MVC Example");
return modelAndView;
}
}
</pre><br />
The view jsp will then have the <span style="font-family: "Courier New", Courier, monospace;">${message}</span> value populated by the model object from the <span style="font-family: "Courier New", Courier, monospace;">ModelAndView</span>. The <span style="font-family: "Courier New", Courier, monospace;">example.jsp</span> is below and resides in the<span style="font-family: "Courier New", Courier, monospace; font-size: x-small;"> <span style="font-size: small;">/webapp/WEB-INF/jsp</span></span> folder:<br />
<br />
<pre class="brush: xml">
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>Spring MVC Example</title>
</head>
<body>
<h2>Welcome to the Example Spring MVC page</h2>
<h3>The message text is:</h3>
<p>${message}</p>
</body>
</html>
</pre><br />
As mentioned previously, a default home page can included in the <span style="font-family: "Courier New", Courier, monospace;">web.xml</span> and instead of displaying html etc., it can be used to redirect requests to another URL. The below <span style="font-family: "Courier New", Courier, monospace;">home.jsp</span> redirects requests to <span style="font-family: "Courier New", Courier, monospace;">example.htm</span>:<br />
<br />
<pre class="brush: xml">
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:redirect url="/example.htm"/>
</pre><br />
Deploying the above to a container like Tomcat should result in a page like the following:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQT0BZ93nNGEPTIFrl44ywFXHg31GZcxd44F7uWgJCJk7X4d_CBp1cbcQxIsyYXOsSANS3Lvz-PRAOmgZg5bhF1saUbDG1UyNWc9DHFwhVg1QAu8iCsb-XRrWEzDZ6enywtA9skhbOCcAL/s1600/SpringMVC.bmp" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="201" nda="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQT0BZ93nNGEPTIFrl44ywFXHg31GZcxd44F7uWgJCJk7X4d_CBp1cbcQxIsyYXOsSANS3Lvz-PRAOmgZg5bhF1saUbDG1UyNWc9DHFwhVg1QAu8iCsb-XRrWEzDZ6enywtA9skhbOCcAL/s400/SpringMVC.bmp" width="400" /></a></div><br />
This is just the very basics of Spring MVC but later posts, will expand on the framework and show how it can be used with, for example, web services like REST.Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com6tag:blogger.com,1999:blog-599554868473356802.post-84759988102243717042011-10-13T08:14:00.000-07:002012-02-06T08:36:44.122-08:00Spring, JMS, Listener Adapters and ContainersIn order to receive JMS messages, Spring provides the concept of message listener containers. These are beans that can be tied to receive messages that arrive at certain destinations. This post will examine the different ways in which containers can be configured.<br />
<br />
A simple example is below where the <span style="font-family: "Courier New", Courier, monospace;">DefaultMessageListenerContianer</span> has been configured to watch one queue (the property <span style="font-family: Courier New;">jms.queue.name</span>) and has a reference to a <span style="font-family: "Courier New", Courier, monospace;">myMessageListener</span> bean which implements the <span style="font-family: "Courier New", Courier, monospace;">MessageListener</span> interface (ie <span style="font-family: "Courier New", Courier, monospace;">onMessage</span>):<br />
<br />
<pre class="brush: xml"><bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destinationName" value="${jms.queue.name}" />
<property name="messageListener" ref="myMessageListener" />
</bean>
</pre><br />
This is all very well but means that the <span style="font-family: "Courier New", Courier, monospace;">myMessageListener</span> bean will have to handle the JMS Message object and process accordingly depending upon the type of <span style="font-family: "Courier New", Courier, monospace;">javax.jms.Message</span> and its payload. For example:<br />
<br />
<pre class="brush: java">if (message instanceof MapMessage) {
// cast, get object, do something
}
</pre><br />
An alternative is to use a <span style="font-family: "Courier New", Courier, monospace;">MessageListenerAdapter</span>. This class abstracts away the above processing and leaves your code to deal with just the message's payload. For example:<br />
<br />
<pre class="brush: xml"><bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destinationName" value="${jms.queue.name}" />
<property name="messageListener" ref="myMessageAdapter" />
</bean>
<bean id="myMessageAdapter" class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<property name="delegate" ref="myMessageReceiverDelegate" />
<property name="defaultListenerMethod" value="processMessage" />
</bean>
</pre><br />
The delegate is a reference to a <span style="font-family: Courier New;">myMessageReceiverDelegate </span><span style="font-family: Times New Roman;">bean which has one or more methods called <span style="font-family: "Courier New", Courier, monospace;">processMessage</span>. It <strong>does not</strong> need to implement the <span style="font-family: "Courier New", Courier, monospace;">MessageListener</span> interface. This method can be overload to handle different payload types. Spring behind the scenes will determine which gets called. For example:</span><br />
<br />
<pre class="brush: java">public void processMessage(final HashMap message) {
// do something
}
public void processMessage(final String message) {
// do something
}
</pre><br />
For the given approach though, only one queue can be tied to the container. Another approach is to tie many listeners (therefore many queues) to the one container, The below Spring XML, using the jms namespace, shows how two listeners for different queues can be tied to one container:<br />
<br />
<pre class="brush: xml"><jms:listener-container container-type="default"
connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="${jms.queue.name1}" ref="myMessageReceiverDelegate" method="processMessage" />
<jms:listener destination="${jms.queue.name2}" ref="myMessageReceiverDelegate" method="processMessage" />
</jms:listener-container>
</pre><br />
The <span style="font-family: "Courier New", Courier, monospace;">myMessageReceiverDelegate </span>bean is treated as an adapter delegate, therefore <strong>does not</strong> need to implement the <span style="font-family: "Courier New", Courier, monospace;">MessageListener</span> interface. Each listener can have a different delegate but for the above example, all messages arriving at the two queues are processed by the one receiver bean ie <span style="font-family: "Courier New", Courier, monospace;">myMessageReceiverDelegate</span>.<br />
<br />
If there is a need to check the message type and extract the payload, then the listener can use a class which implements the <span style="font-family: "Courier New", Courier, monospace;">MessageListener</span> interface (eg the <span style="font-family: "Courier New", Courier, monospace;">myMessageListener</span> bean used in the first example). The <span style="font-family: "Courier New", Courier, monospace;">onMessage</span> method will then be called when messages arrive at the specified destination:<br />
<br />
<pre class="brush: xml">
<jms:listener-container container-type="default"
connection-factory="connectionFactory" acknowledge="auto">
<jms:listener destination="${jms.queue.name1}" ref="myMessageListener" />
<jms:listener destination="${jms.queue.name2}" ref="myMessageListener" />
</jms:listener-container>
</pre>Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com7tag:blogger.com,1999:blog-599554868473356802.post-42102204461520933312011-09-16T02:31:00.000-07:002012-02-07T00:21:12.893-08:00Spring JMS with ActiveMQActiveMq is a powerful open source messaging broker, and is very easy and straightforward to use with Spring as the below classes and XML will prove. The example below is the bar minimum needed to get up and running with transactions and message converters.<br />
<br />
On the sending side, the ActiveMq connection factory needs to be created with the url of the broker. This in turn is used to create the Spring JMS connection factory and as no session cache property is supplied the default cache is one. The template is then used in turn to create the Message Sender class:<br />
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.5.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- Activemq connection factory -->
<bean id="amqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<constructor-arg index="0" value="${jms.broker.url}"/>
</bean>
<!-- ConnectionFactory Definition -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory" />
</bean>
<!-- Default Destination Queue Definition-->
<bean id="defaultDestination" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="${jms.queue.name}"/>
</bean>
<!-- JmsTemplate Definition -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="defaultDestination" ref="defaultDestination" />
</bean>
<!-- Message Sender Definition -->
<bean id="messageSender" class="com.city81.jms.MessageSender">
<constructor-arg index="0" ref="jmsTemplate" />
</bean>
</beans>
</pre><br />
An example sending class is below. It uses the <span style="font-family: "Courier New", Courier, monospace;">convertandSend</span> method of the <span style="font-family: "Courier New", Courier, monospace;">JmsTemplate</span> class. As there is no destination arg, the message will be sent to the default destination which was set up in the XML file:<br />
<br />
<pre class="brush: java">import java.util.Map;
import org.springframework.jms.core.JmsTemplate;
public class MessageSender {
private final JmsTemplate jmsTemplate;
public MessageSender(final JmsTemplate jmsTemplate) {
this.jmsTemplate = jmsTemplate;
}
public void send(final Map map) {
jmsTemplate.convertAndSend(map);
}
}
</pre><br />
On the receiving side, there needs to be a listener container. The simplest example of this is the <span style="font-family: "Courier New", Courier, monospace;">SimpleMessageListenerContainer</span>. This requires a connection factory, a destination (or destination name) and a message listener. <br />
<br />
An example of the Spring configuration for the receiving messages is below:<br />
<br />
<pre class="brush: xml"><?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="http://activemq.apache.org/schema/core"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:context="http://www.springframework.org/schema/context"
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
http://activemq.apache.org/schema/core
http://activemq.apache.org/schema/core/activemq-core-5.5.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<!-- Activemq connection factory -->
<bean id="amqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<constructor-arg index="0" value="${jms.broker.url}"/>
</bean>
<!-- ConnectionFactory Definition -->
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<constructor-arg ref="amqConnectionFactory" />
</bean>
<!-- Message Receiver Definition -->
<bean id="messageReceiver" class="com.city81.jms.MessageReceiver">
</bean>
<bean class="org.springframework.jms.listener.SimpleMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory" />
<property name="destinationName" value="${jms.queue.name}" />
<property name="messageListener" ref="messageReceiver" />
</bean>
</beans>
</pre><br />
The listening/receiving class needs to extend <span style="font-family: "Courier New", Courier, monospace;">javax.jms.MessageListener</span> and implement the onMessage method:<br />
<br />
<pre class="brush: java">import javax.jms.MapMessage;
import javax.jms.Message;
import javax.jms.MessageListener;
public class MessageReceiver implements MessageListener {
public void onMessage(final Message message) {
if (message instanceof MapMessage) {
final MapMessage mapMessage = (MapMessage) message;
// do something
}
}
}
</pre><br />
<span style="font-family: inherit;">To then send a message would be as simple as getting the sending bean from the bean factory as shown in the below code:</span><br />
<br />
<pre class="brush: java">
MessageSender sender = (MessageSender) factory.getBean("messageSender");
Map map = new HashMap();
map.put("Name", "MYNAME");
sender.send(map);
</pre><br />
<span style="font-family: inherit;">Will try to expand and build up JMS and Spring articles with examples of using transactions and other brokers like MQSeries.</span>Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com6tag:blogger.com,1999:blog-599554868473356802.post-13893750655489418542011-06-06T02:26:00.000-07:002012-02-07T00:26:55.687-08:00JUnit, DBUnit and OracleAs previously blogged, DBUnit is a powerful addition to your unit test armoury. Having used it with Oracle, there are a few nuances which are worth writing about and therefore remembering!<br />
<br />
When creating a connection to an Oracle database, DBUnit will populate a Map of table names. By default these will not be prefixed with the schema name. As a result, you can get duplicate table names. An example of an exception raised for the duplicate table WWV_FLOW_DUAL100 is shown below:<br />
<br />
<span style="font-family: "Courier New", Courier, monospace;">org.dbunit.database.AmbiguousTableNameException: WWV_FLOW_DUAL100</span><span style="font-family: "Courier New", Courier, monospace;"> at org.dbunit.dataset.OrderedTableNameMap.add(OrderedTableNameMap.java:198)<br />
at org.dbunit.database.DatabaseDataSet.initialize(DatabaseDataSet.java:231)<br />
at org.dbunit.database.DatabaseDataSet.getTableMetaData(DatabaseDataSet.java:281)<br />
at org.dbunit.operation.AbstractOperation.getOperationMetaData(AbstractOperation.java:80)<br />
at org.dbunit.operation.AbstractBatchOperation.execute(AbstractBatchOperation.java:140)</span><br />
<br />
To resolve this, set the database config property <strong>FEATURE_QUALIFIED_TABLE_NAMES</strong> to be true. This will make sure all tables in the Map are unique. As a consequence of this, the table names in the XML data file will need to be prefixed with the schema name.<br />
<br />
Another useful database config property is <strong>PROPERTY_DATATYPE_FACTORY</strong>. In the XML data file, if there are dates with the time element set then the time element will be ignored unless the database config property <strong>PROPERTY_DATATYPE_FACTORY</strong> is set to <strong>new Oracle10DataTypeFactory()</strong> (or the equivalent data factory for the version of Oracle being used.)<br />
<br />
An example of setting these values in a @BeforeClass annotated JUnit method is shown below:<br />
<br />
<pre class="brush: java">
@BeforeClass
public static void loadDataset() throws Exception {
// database connection
ResourceCache resourceCache = ResourceCache.getInstance();
String driverClassString = resourceCache.getProperty("datasource.driver.class.name");
String databaseURL = resourceCache.getProperty("datasource.url");
String username = resourceCache.getProperty("test.datasource.username");
String password = resourceCache.getProperty("test.datasource.password");
Class driverClass = Class.forName(driverClassString);
Connection jdbcConnection = DriverManager.getConnection(databaseURL, username, password);
connection = new DatabaseConnection(jdbcConnection);
DatabaseConfig config = connection.getConfig();
config.setProperty(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new Oracle10DataTypeFactory());
FlatXmlDataSetBuilder flatXmlDataSetBuilder = new FlatXmlDataSetBuilder();
flatXmlDataSetBuilder.setColumnSensing(true);
dataset = flatXmlDataSetBuilder.build(Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("Test-dataset.xml"));
}
</pre>Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com2tag:blogger.com,1999:blog-599554868473356802.post-64956387859450574442011-05-04T05:42:00.000-07:002012-02-07T00:56:14.961-08:00Using Spring's StoredProcedure class with Oracle Spatial JGeometryThe Spring framework provides a neat wrapper class you can extend when you want to call a stored procedure. Sometimes though you need to extend to use a native connection because, for example, you need to pass an ORACLE Geometry type to the stored procedure.<br />
<br />
The below code wraps a Create_Geometry_Line stored procedure which takes a geometry object. The calling code will use the executeMap method to pass in a Map of in parameters. It converts the list of doubles (which represent the points of the line) to an object of type STRUCT.<br />
<br />
<pre class="brush: java">package uk.co.city81.persistence.dao.geometry;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Map;
import oracle.jdbc.OracleTypes;
import oracle.spatial.geometry.JGeometry;
import oracle.sql.STRUCT;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.SqlOutParameter;
import org.springframework.jdbc.core.SqlParameter;
import org.springframework.jdbc.object.StoredProcedure;
public class CreateGeometryLineDAO extends StoredProcedure {
private Connection nativeConn = null;
public static final String CREATE_GEOMETRY_LINE = "geometry_pkg.Create_Geometry_Line";
// Constructor
public CreateGeometryLineDAO(JdbcTemplate jdbcTemplate) {
setJdbcTemplate(jdbcTemplate);
setFunction(true);
setSQL();
declareParameter(new SqlOutParameter("l_Return", Types.INTEGER));
declareInParameters();
declareOutParameters();
compile();
}
// Get the native connection
protected Connection getNativeConn() throws SQLException {
if ((nativeConn == null) || nativeConn.isClosed()) {
nativeConn = this.getJdbcTemplate().getNativeJdbcExtractor()
.getNativeConnection(this.getJdbcTemplate()
.getDataSource().getConnection());
}
return nativeConn;
}
protected void declareInParameters() {
declareParameter(new SqlParameter("p_geom_data",OracleTypes.STRUCT));
}
protected void declareOutParameters() {
// declare out params
}
protected void setSQL() {
setSql(CREATE_GEOMETRY_LINE);
}
/**
* Execute the stored procedure
*
* @param inParamMap a map of the stored procedure parameters
*/
public Map executeMap(Map inParamMap) {
Map outParamMap = null;
try {
if (inParamMap.get("p_geom_data") != null) {
java.util.List<Double> ordinates
= (java.util.List<Double>) inParamMap.get("p_geom_data");
double[] ordinateDoubles = new double[ordinates.size()];
int count = 0;
for (Double ordinate : ordinates) {
ordinateDoubles[count] = ordinate.doubleValue();
count++;
}
int[] elemInfo = new int[]{1,2,1};
JGeometry j_geom = new JGeometry(
JGeometry.GTYPE_CURVE,8307, elemInfo,ordinateDoubles);
STRUCT obj = JGeometry.store(j_geom, getNativeConn());
inParamMap.put("p_geom_data", obj);
}
outParamMap = super.execute(inParamMap);
} catch (DataAccessException daex) {
// throw exception
} catch (SQLException e) {
// throw exception
}
return outParamMap;
}
}
</pre><br />
The jdbcTemplate can be injected into the DAO's constructor. The extracts from the context xml are below:<br />
<br />
<pre class="brush: xml">
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"
destroy-method="close">
<property name="driverClassName">
<value>oracle.jdbc.OracleDriver</value>
</property>
<property name="url">
<value>jdbc:oracle:thin:@server:port:db</value>
</property>
<property name="username">
<value>username</value>
</property>
<property name="password">
<value>password</value>
</property>
</bean>
<bean id="nativeJdbcExtractor" class="org.springframework.jdbc.support.nativejdbc.SimpleNativeJdbcExtractor"
lazy-init="true"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="datasource" />
</property>
<property name="nativeJdbcExtractor">
<ref bean="nativeJdbcExtractor" />
</property>
</bean>
<bean id="createGeometryLineDAO" class="uk.co.city81.persistence.dao.geometry.CreateGeometryLineDAO">
<constructor-arg ref="jdbcTemplate" />
</bean>
</pre>Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com0tag:blogger.com,1999:blog-599554868473356802.post-33780724653815624762011-04-15T02:31:00.000-07:002012-02-07T01:16:05.753-08:00JAAS, EJB Security and GlassfishWith EJBs you can specify security by using annotations from the <span style="font-family: "Courier New", Courier, monospace;">javax.annotation.security</span> package. The below article describes how to setup security on a bean and access the methods of the bean via an annotation or via JAAS which has been setup on Glassfish.<br />
<br />
The below bean class only allows the <span style="font-family: "Courier New", Courier, monospace;">MANAGER</span> role access to use the services exposed. In this case, <span style="font-family: "Courier New", Courier, monospace;">findCustomerByAccountNumber.</span> (The <span style="font-family: "Courier New", Courier, monospace;">AccessRoles.MANAGER</span> resolves to a string so if the string changes the <span style="font-family: "Courier New", Courier, monospace;">CustomerServiceBean</span> doesn't have to change.)<br />
<br />
<pre class="brush: java">@RolesAllowed(AccessRoles.MANAGER)
@Stateless(mappedName = JndiResourceName.CUSTOMER_SERVICE)
@Remote(CustomerService.class)
public class CustomerServiceBean implements CustomerService {
@Override
public Customer findCustomerByAccountNumber(String accountNumber) {
Customer customer = null;
// do stuff to find customer
return customer;
}
}
</pre><br />
To call the <span style="font-family: "Courier New", Courier, monospace;">findCustomerByAccountNumber</span>, the code can use the <span style="font-family: "Courier New", Courier, monospace;">@RunAs </span>annotation as described below:<br />
<br />
<pre class="brush: java"> @RunAs(AccessRoles.MANAGER)
public void verifyCustomer(String accountNumber) {
// do stuff
Customer customer =
customerService.findCustomerByAccountNumber(String accountNumber);
// do more stuff
}
</pre><br />
But what if the roles calling the verify method can vary ie <span style="font-family: "Courier New", Courier, monospace;">MANAGERS, OPERATORS, ADMIN.</span> In this scenario, we would want to authenticate the 'caller' before accessing the <span style="font-family: "Courier New", Courier, monospace;">findCustomerByAccountNumber</span> method. A solution to this would be to use JAAS (Java Authentication and Authorization Service.)<br />
<br />
The principal of this is to create realms and have users and groups in the realm. There are a few steps involved which are described as follows:<br />
<br />
Firstly, the app server (in this example Glassfish) needs to create a realm and the below describes how to do this using the command line. It assumes connection pools, user and group database tables have been created and populated, and that the <span style="font-family: "Courier New", Courier, monospace;">flexiblejdbcrealm-0.4.jar </span>is in the Glassfish lib dir:<br />
<br />
<div style="font-family: "Courier New", Courier, monospace;">asadmin --host delete-auth-realm customer-realm</div><div style="font-family: "Courier New", Courier, monospace;">asadmin --host create-auth-realm --classname=org.wamblee.glassfish.auth.FlexibleJdbcRealm --property="jaas.context=customerJdbcRealm:datasource.jndi=<br />
jdbc/Customer:sql.password=select password from customeruser where username\=?:sql.groups=select g.groupname from customergroup g inner join user_group ug on g.id\=ug.group_id inner join customeruser u on ug.user_id\=u.id where u.username\=?:password.digest=MD5:password.encoding=BASE64" customer-realm</div><div style="font-family: "Courier New", Courier, monospace;"><br />
</div><div style="font-family: "Courier New", Courier, monospace;">asadmin --host --user admin set server-config.security-service.activate-default-principal-to-role-mapping=true</div><div style="font-family: "Courier New", Courier, monospace;">asadmin --host set-log-level javax.enterprise.system.core.security=INFO</div><div style="font-family: "Courier New", Courier, monospace;">asadmin --host set-log-level org.wamblee.glassfish.auth=INFO</div><div style="font-family: "Courier New", Courier, monospace;"></div><div style="font-family: "Courier New", Courier, monospace;"><br />
</div><div style="font-family: "Courier New", Courier, monospace;"></div><div style="font-family: "Courier New", Courier, monospace;"><i></i></div>The <span style="font-family: "Courier New", Courier, monospace;">login.conf </span>needs to have the below added to it:<br />
<br />
<div style="font-family: "Courier New", Courier, monospace;">customerJdbcRealm {com.mypackage.auth.CustomerLoginModule required;}</div><br />
The <span style="font-family: "Courier New", Courier, monospace;">CustomerLoginModule</span> class extends <span style="font-family: "Courier New", Courier, monospace;">FlexibleJdbcLoginModule </span>and gives us the ability to intercept the login/authentication calls if we so wish. In this case, any login exceptions are being logged:<br />
<br />
<pre class="brush: java">public class CustomerLoginModule extends FlexibleJdbcLoginModule implements LoginModule {
private static final Logger SECURITY_LOGGER = Logger.getLogger("com.mypackage");
@Override
protected void authenticate() throws javax.security.auth.login.LoginException {
try {
super.authenticate();
} catch(LoginException le){
SECURITY_LOGGER.error("Authentication failed for "
+ _username + ". " + le.getMessage());
throw le;
}
}
}
</pre><br />
We can now change the verify method to authenticate before calling the 'secure' <span style="font-family: "Courier New", Courier, monospace;">findCustomerByAccountNumber</span> method:<br />
<br />
<pre class="brush: java">
private ProgrammaticLoginInterface programmaticLogin =
new ProgrammaticLogin();
public void verifyCustomer(String accountNumber) {
Customer customer = null;
boolean loginSuccessful = programmaticLogin.login("manager", "password", "customer-realm", true);
if (loginSuccessful) {
customer = customerService.findCustomerByAccountNumber(String accountNumber);
} else {
// throw exception
}
}
</pre><br />
The call to the <span style="font-family: "Courier New", Courier, monospace;">ProgrammaticLogin</span> instance attempts to use the supplied name and password directly to login to the current realm. If successful, a security context is created for that user and is used by the EJB when checking what roles are allowed to call it.<br />
<br />
For example purposes, the above <span style="font-family: "Courier New", Courier, monospace;">verifyCustomer</span> method has the name and password hard coded but in reality these values could be obtained from a login web page or other such authentication mechanisms.Geraint Joneshttp://www.blogger.com/profile/09112495975196330505noreply@blogger.com2