Spring Cloud – Rabbit MQ Comprehensive Glance

Reading Time: 6 minutes

Introduction

In this blog post, I’ll dive into Spring Cloud Stream API that is underneath the Spring umbrella. The API is around for some time and has many of beneficial use cases. I felt the need to write this post, because as a typical nature, at work we were in diversion of achieving a stream line and integration among our microservices.

Sample Project

I have come to prepare a good demonstration projects one named “Automation” that will create events and the other is “Pki” that will consume all produced events. Upon successful validation, the event will be persisted in an in-memory database. Automation has a simple REST endpoint that will take a Certificate Order and proceed with the stream. Here is an illustration of the further achievement

Requirements

In order for running this project, you will need to have following setup:

  1. Maven 3,
  2. Java 8,
  3. Docker

Running a Rabbit MQ inside Docker:

docker run -d --hostname my-rabbit --name some-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3-management

Sending a Certification Request to the Automation API:

curl -X POST http://localhost:7000/api/certificates -H "Content-Type: application/json" -d "{\"commonName\":\"tugrulaslan.com\",\"algorithm\":\"sha256\"}" 

Running Tests

Both projects have their Unit and Integration tests. You can have a peek at them to find out how each module works.

Concept

Spring Cloud API allows application code to decouple from heavy burden tight integration-provider-specific code, as well settings and the details of the exchange systems. By utilizing the Spring Cloud Stream API, applications are agnostic to the details and just focused on communication. The API will ensure the queues, and topics in the messaging tool are created and the connection among the modules are achieved.

Application perform business code and transmit/emit the events using the inputs and outputs which we will have a look in the upcoming chapters. Here thedepicted figure from the project documentation demonstrates the integration layout:

SCSt with binder

Communication and Interfaces

As I stated earlier, in the Cloud API we are using just interfaces towards the communication. Since streaming diverts, I am going to conclude all the details in two different chapters on Producer and Consumer.

Furthermore, the API itself, provides a basic way to exchange messages over the default existing interfaces namely; “Sink”, “Source”, and “Processor”. However, I am taking my sample to a next level that will have its own custom interfaces to demonstrate more features.Eventually, the sample code will end up using a Topic Exchange communication with that each consumer will receive the type of the specific events that they like. You can see all the target samples and the Topic exchange type in the reference post[1]

Producer Side

On this side, we have the project Automation that is responsible of producing the events that are triggered via REST API. First of all let’s look at the Programming Side of the API and discover the interface called “CertificateEventStreamSource”

import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;

public interface CertificateEventStreamSource {
    @Output("certificateOrderedChannel")
    MessageChannel certificateOrderedChannel();
}

Let me elaborate the concepts here:

  • @Output: The annotation defines a name for the communication channel as well as points out that the defined interface is a Producer. The given annotation name must match in the configuration file, that we will see soon,
  • MessageChannel: The interface provides ways to send the event to the MQ

For now, this is the most that your application needs to know in terms of the communication. Just a last step, we need to annotate the class that will use this interface shown in the class called “CertificateService”

@EnableBinding(CertificateEventStreamSource.class)

In addition, our next target is the configuration. The configuration steps are very simple. Generally, Spring Boot project provides Automatic Configuration out of the box for many projects, that helps you not to define certain default entries like rabbit local host string, port etc. You can see it in the documentation[2]

application.yaml

spring.cloud.stream.bindings.certificateOrderedChannel.destination=CREDS_EXCHANGE
spring.cloud.stream.rabbit.bindings.certificateOrderedChannel.producer.routing-key-expression='creds.certificate.ordered'

Let’s break the entries down for the explanation:

destination: It points out to the Exchange on the Broker. The name needs to match to the one defined in the Interface’s @Output annotation, then the framework will easily bind this interface. The corresponding value is the name of the Exchange that will appear in the Rabbit MQ,

routing-key-expression: The second and the last entry is for the key for the event. With the help of this entry, Rabbit easily binds this event to this key, later the designated consumers will pull the events by this key.

If you like to know more about the Producer bindings that are available, consult the API documentation[3] . Down to this point, we have easily configured our Automation API to be fully working with the Event Stream. There is no more needed configuration required, and now we can focus on our consumer.

Consumer Side

For the consumption of the events, we will be observing the “PKI ” component which will emit the events, run some validation and then persist the event in database. The Elaboration of this component will vary compared to the Producer Automation, because I have enhanced this consumer with some beneficial use cases that i will explain hereby.

Before diving into the details, I’ll show the Interface then it will follow the configuration and so on. Now let’s look at “CertificateEventStreamSource”

import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;

public interface CertificateEventStreamSource {

    String CERTIFICATE_ORDERED_CHANNEL = "certificateOrderedSubscribableChannel";
    @Input(CERTIFICATE_ORDERED_CHANNEL)
    SubscribableChannel certificateOrdered();
}

Let’s look into what we have here and give some light:

  • @Input: The annotation defines a name for the communication channel as well as points out that the defined interface is a Consumer. The given name in the annotation must correspond to the binding in the property,
  • MessageChannel: The interface provides ways to emit the event from the MQ

These two are semantically same to the Producer’s interface. Additionally, we need to annotate the class “CertificateOrderedListener” with:

@EnableBinding(CertificateEventStreamSource.class)

So far we let our application to programmatically integrate with the API. Now we’ll move onto the configuration which will give the Cloud API the guidance on how to manage our stream and some failure scenarios:

application.yaml

spring.cloud.stream.bindings.certificateOrderedSubscribableChannel.destination=CREDS_EXCHANGE

spring.cloud.stream.rabbit.bindings.certificateOrderedSubscribableChannel.consumer.binding-routing-key=creds.certificate.ordered

spring.cloud.stream.rabbit.bindings.certificateOrderedSubscribableChannel.consumer.bind-queue=true

spring.cloud.stream.bindings.certificateOrderedSubscribableChannel.group=certificateOrderedQueue

spring.cloud.stream.rabbit.bindings.certificateOrderedSubscribableChannel.consumer.auto-bind-dlq=true

spring.cloud.stream.rabbit.bindings.certificateOrderedSubscribableChannel.consumer.republishToDlq=true

spring.cloud.stream.bindings.certificateOrderedSubscribableChannel.consumer.max-attempts=2

Let’s dive into the detail;, first of all notice the repetitive “certificateOrderedSubscribableChannel” definitions after each “bindings” entry, that points out to the input value in the @Input annotation. These two entries must match, otherwise we will never be able to bind the consumer properly. Now let’s move onto the each definition:

destination: It defines the exchange that we will connect to,

binding-routing-key: this key is defined bidirectionally, as we saw in the Producer, it indicates to the Event mapping. The more details are given in the Producer’s section,

bind-queue: sets queues for the given routing key,

group: grouping is a very vital feature, and deserves a bit longer explanation. By setting this value up, you define a strategy of each designated consumer receives one message at a time, it is so-called “robin round” fashion. If the grouping is not defined, then each consumer will get every message. I believe the explanation might confuse you, so let me visualize it

More information and available settings are in the documentation[4]

auto-bind-dlq: It sets up a DLQ and configures the original queue to forward rejections into this queue. In the following chapters, I’ll give an example from the application code,

republishToDlq: The binder forwards the message to the DLQ with the exception information in the header,

max-attempts: It sets maximum attempts for the application to receive the message upon errors,

You can find more about the available use cases for the Exceptions and the retry mechanisms in the documentation[5]

Exception Handling

The Spring Cloud API allows you to only define a strategy for the failure cases in your application, the rest of the details will be taken care. When exceptions are thrown by your applications, depending on your configuration, the API will wrap it up and handle the situation. In the above configuration, I have defined some strategies with the Retry Attempt and the Dead Letter Queue.

In the PKI application, I have a minor demonstration case that will achieve the mentioned following case with the below Certification case:

curl -X POST http://localhost:7000/api/certificates -H "Content-Type: application/json" -d "{\"commonName\":\"tugrulaslan.com\",\"algorithm\":\"sha1\"}" 

After PKI receives such event, it will retry twice and move it to the Dead Letter Queue “CREDS_EXCHANGE.certificateOrderedQueue.dlq

Benefits

I have populated some of the benefits, that I personally believe the Cloud API will bring into your projects;

  • Applications will be kept apart from heavy settings,
  • Abstraction from the inner workings of the exchange communication and specific API implementations,
  • Yet another abstraction benefit, while changing the Message Broker, you can easily change one broker to another, and your application will not be aware, list of binders[6],
  • Easy management on the exception cases land, retrieval strategies,
  • Spring Cloud Sleuth API is enabled by default, you can easily trace the messages,
  • Since its a Spring project other native projects can be easily hooked up,
  • Automatic marshaling and unmarshaling in the event exchange right out of the box without any prior configuration

References

  1. https://www.cloudamqp.com/blog/2015-09-03-part4-rabbitmq-for-beginners-exchanges-routing-keys-bindings.html
  2. https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-auto-configuration-classes.html
  3. https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/_configuration_options.html#_producer_properties
  4. https://docs.spring.io/spring-cloud-stream/docs/current/reference/html/_configuration_options.html#_consumer_properties
  5. https://docs.spring.io/spring-cloud-stream/docs/current/reference/htmlsingle/#spring-cloud-stream-overview-error-handling
  6. https://cloud.spring.io/spring-cloud-stream/spring-cloud-stream.html#_binder_implementations

Spring Security JSF showing content depending on user role

Reading Time: 2 minutesSpring is a very powerful framework, its security framework offers a splendid mechanism and security. It also integrates with other frameworks well too. In this post I’ll share an example of how you can show the content of a page depending on user’s role. I am assuming that you already have a spring security setup with spring security expressions are enabled in the config file. Now let’s start out;

1. create a file called “springsecurity.taglib.xml” underneath WEB-INF folder,

<?xml version="1.0"?>
<!DOCTYPE facelet-taglib PUBLIC
  "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
  "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
<facelet-taglib>
  <namespace>http://www.springframework.org/security/tags</namespace>
  <tag>
    <tag-name>authorize</tag-name>
    <handler-class>org.springframework.faces.security.FaceletsAuthorizeTagHandler</handler-class>
  </tag>
  <function>
    <function-name>areAllGranted</function-name>
    <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
    <function-signature>boolean areAllGranted(java.lang.String)</function-signature>
  </function>
  <function>
    <function-name>areAnyGranted</function-name>
    <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
    <function-signature>boolean areAnyGranted(java.lang.String)</function-signature>
  </function>
  <function>
    <function-name>areNotGranted</function-name>
    <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
    <function-signature>boolean areNotGranted(java.lang.String)</function-signature>
  </function>
  <function>
    <function-name>isAllowed</function-name>
    <function-class>org.springframework.faces.security.FaceletsAuthorizeTagUtils</function-class>
    <function-signature>boolean isAllowed(java.lang.String, java.lang.String)</function-signature>
  </function>
</facelet-taglib>

2. Register the taglib file in the web.xml file,

<context-param>
    <param-name>javax.faces.FACELETS_LIBRARIES</param-name>
    <param-value>/WEB-INF/springsecurity.taglib.xml</param-value>
</context-param>

3. Include required dependencies,

<properties>
 <spring-security.version>3.1.2.RELEASE</spring-security.version>
 <spring-faces.version>2.4.1.RELEASE</spring-faces.version>
</properties>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>${spring-security.version}</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.springframework.webflow</groupId>
    <artifactId>spring-faces</artifactId>
    <version>${spring-faces.version}</version>
    <scope>compile</scope>
</dependency>

Now up to this point we are all set to use the implementation. From now on we can use this solution for;

a)Showing a nested content conditionally depending on roles and some other metrics;

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:sec="http://www.springframework.org/security/tags">

  <sec:authorize ifAllGranted="ROLE_FOO, ROLE_BAR">
    Lorem ipsum dolor sit amet
  </sec:authorize>

  <sec:authorize ifNotGranted="ROLE_FOO, ROLE_BAR">
    Lorem ipsum dolor sit amet
  </sec:authorize>

  <sec:authorize ifAnyGranted="ROLE_FOO, ROLE_BAR">
    Lorem ipsum dolor sit amet
  </sec:authorize>

</ui:composition>

b)Using the role as a metric to hide/show some components depending on the role;

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html"
  xmlns:sec="http://www.springframework.org/security/tags">

  <!-- Rendered only if user has all of the listed roles -->
  <h:outputText value="Lorem ipsum dolor sit amet" rendered="#{sec:areAllGranted('ROLE_FOO, ROLE_BAR')}"/>	
  
  <!-- Rendered only if user does not have any of the listed roles -->
  <h:outputText value="Lorem ipsum dolor sit amet" rendered="#{sec:areNotGranted('ROLE_FOO, ROLE_BAR')}"/>	
  
  <!-- Rendered only if user has any of the listed roles -->
  <h:outputText value="Lorem ipsum dolor sit amet" rendered="#{sec:areAnyGranted('ROLE_FOO, ROLE_BAR')}"/>	
  
  <!-- Rendered only if user has access to given HTTP method/URL as defined in Spring Security configuration -->
  <h:outputText value="Lorem ipsum dolor sit amet" rendered="#{sec:isAllowed('/secured/foo', 'POST')}"/>	

</ui:composition>

References

https://docs.spring.io/spring-webflow/docs/current/reference/html/spring-faces.html

http://docs.spring.io/autorepo/docs/webflow/2.3.x/reference/html/spring-faces.html#spring-faces-security-taglib

https://stackoverflow.com/a/15378140/1958683

http://keylesson.com/index.php/2015/06/18/spring-security-authorize-tag-example-1993/

 

Spring Task Example

Reading Time: < 1 minutepom.xml

[code]

<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/xsd/maven-4.0.0.xsd”>
<modelVersion>4.0.0</modelVersion>

<groupId>com.tugrulaslan</groupId>
<artifactId>SpringScheduledTaskExample</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>SpringScheduledTaskExample</name>
<url>http://maven.apache.org</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>3.1.2.RELEASE</spring.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

[/code]

batch.xml in src>java>resources

[code]

<?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:task=”http://www.springframework.org/schema/task”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd”>

<context:component-scan base-package=”com.tugrulaslan.scheduling”/>
<task:annotation-driven/>
<bean id=”taskBean” class=”com.tugrulaslan.scheduling.TaskBean”/>
<task:scheduled-tasks>
<!– for every second: 0/1 * * * * ? –>
<!– for every minute: 0 0/1 * * * ? –>
<!– for every hour: 0 0 0/1 * * ? –>
<task:scheduled ref=”taskBean” method=”runTask” cron=”0 0/1 * * * ?”/>
</task:scheduled-tasks>

</beans>

[/code]

TaskBean.java in com.tugrulaslan.scheduling

[code]

package com.tugrulaslan.scheduling;

public class TaskBean {

public void runTask(){
System.out.println(“running the task: ” + new java.util.Date());
}
}

[/code]

App.java in com.tugrulaslan

[code]

package com.tugrulaslan;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext(“batch.xml”);
}
}

[/code]

Spring Batch Cronjob Expression Dilemma

Reading Time: 1 minuteIn one of the projects that I’ve assigned to has given me the trouble of synchronization of batches to carry all data from one location to another remote location. The story is that we have a few of batches some of them scheduled to be launched every two minutes or 2 hours, but we’ve come to realize that they all work endlessly.

I did dig information on internet and finally have come up with a permanent solution on creating Spring cron job expressions.

Normally a simple Spring cron job expression consists of 6 digits of slots and each slots corresponds to a time frame.

*                *                  *              *                                    *                *

Second     Minute      Hour      Day of the month     Month     Days of a week

In this given structure you do define the job at a specific time that it’s being fired.

What I entered before

	<task:scheduled-tasks scheduler="orderScheduler">
		<task:scheduled ref="orderBatchRunScheduler" method="run"
			cron="* */3 * * * *" />
	</task:scheduled-tasks>

How I altered

	<task:scheduled-tasks scheduler="orderScheduler">
		<task:scheduled ref="orderBatchRunScheduler" method="run"
			cron="0 */3 * * * *" />
	</task:scheduled-tasks>

So * all caused the tasks to run endlessly, to observe the indication of symbols

*    : matches any

/    : every

?    : for no specific values

using 0 instead of * has enabled batch to run only at its given specific time, not run every single second. because * meets the criteria of any so that i was being fired up every single time.

 

Further reading

http://stackoverflow.com/questions/26147044/spring-cron-expression-for-every-day-101am

https://docs.spring.io/spring/docs/4.3.x/javadoc-api/org/springframework/scheduling/support/CronSequenceGenerator.html

Enabling auto reconnect in mysql hibernate spring

Reading Time: < 1 minutein your spring config file append the url entry with the below sample

 

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
          destroy-method="close">
        <property name="driverClassName" value="${database.driverClassName}" />
        <property name="url" value="${database.url}?characterEncoding=UTF-8&amp;autoReconnect=true"/>
        <property name="username" value="${database.user}" />
        <property name="password" value="${database.password}" />
    </bean>

Spring ZKoss Customized Login, Logout, Authorization and Authentication

Reading Time: 2 minutesCustomAuthenticationFilter.java

public class CustomAuthenticationFilter extends
		UsernamePasswordAuthenticationFilter {

	@Autowired
	private xxService xService;
	
	static final Logger logger = Logger.getLogger(CustomAuthenticationFilter.class);

	


	@Override
	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {

		
		String username = request.getParameter(getUsernameParameter());
		String password = request.getParameter(getPasswordParameter());
		String server = request.getParameter("server");
		
		
		if(username.trim().length() == 0 || password.trim().length() == 0){
			logger.error("Error empty credentials entered " + username + password + server);
			throw new BadCredentialsException("Error empty credentials entered!");
		}
		
		return logonToBO(request, response, username, password, server);
	}
	
	public Authentication logonToBO(HttpServletRequest request, HttpServletResponse response, String username, String password, String server){
		
		List<GrantedAuthority> authorities = collectAuthorities(username, password, server);
		
		UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password, authorities);		
		
		if(xService.checkUserEnterpriseLogOn(username, password,server)){
			logger.debug("Access granted " + username+ password + server + token);
			return token;
		}else{
			throw new BadCredentialsException("Error wrong credentials entered!");
		}
	}
	
	public List<GrantedAuthority> collectAuthorities(String username, String password, String server){
		
		List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
		
		String userAuth = xService.acquireUserAuthorityGroup(username, password, server);

		if(userAuth.equals("YOUR_CUSTOM_AUTH_VALUE")){
			auths.add(new GrantedAuthorityImpl("ROLE_USER"));
			
		}
		
		if(userAuth.equals("") || userAuth == ""){
			logger.error("Unauthorized login " + username);
			throw new BadCredentialsException("You aren't authorized beyond this point!");
		}		
		return auths;
	}
}

CustomAuthenticationProvider.java

public class CustomAuthenticationProvider implements AuthenticationProvider{

	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {

		return authentication;
	}	


	public boolean supports(Class<?> arg0) {
		return true;
	}
	
}

CustomLogoutHandler.java

	@Autowired
        private XXService XService;

	public void logout(HttpServletRequest request,
			HttpServletResponse response, Authentication authentication) {

		//log out of BO Server
		XService.terminateEnterpriseSession();
		//return the values and log off from spring security as well
		super.logout(request, response, authentication);
	}

applicationContext.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
	xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.zkoss.org/2008/zkspring/core http://www.zkoss.org/2008/zkspring/core/zkspring-core.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        

	<http auto-config="false" entry-point-ref="loginUrlAuthenticationEntryPoint">

		<!-- ZK au has to be accessed anonymously -->
		<intercept-url pattern="/zkau/**" access="IS_AUTHENTICATED_ANONYMOUSLY"
			requires-channel="any" />

		<!-- allowing access to css resources -->
		<intercept-url pattern="/css/**" access="IS_AUTHENTICATED_ANONYMOUSLY"
			requires-channel="any" />
			

		<!-- allowing access to images resources -->
		<intercept-url pattern="/images/**" access="IS_AUTHENTICATED_ANONYMOUSLY"
			requires-channel="any" />

		<!-- allowing access to layout resources -->
		<intercept-url pattern="/layout/**" access="IS_AUTHENTICATED_ANONYMOUSLY"
			requires-channel="any" />

		<!-- allowing access to login page -->
		<intercept-url pattern="/login.zul" access="IS_AUTHENTICATED_ANONYMOUSLY" />
		<intercept-url pattern="/sectest.zul" access="IS_AUTHENTICATED_ANONYMOUSLY" />

		<!-- After defining other resources secure all pages and links -->
		<intercept-url pattern="/**" access="ROLE_USER" />

		<!-- Custom Login Filter -->
		<custom-filter ref="customAuthenticationFilter"
			position="FORM_LOGIN_FILTER" />

		<!-- Custom Logout Filter -->
		<custom-filter ref="customLogoutFilter" position="LOGOUT_FILTER" />
	</http>

	<!-- Custom Authentication Filter -->
	<beans:bean id="customAuthenticationFilter"
		class="com.tugrulaslan.security.CustomAuthenticationFilter">
		<beans:property name="authenticationManager" ref="authenticationManager" />
		<beans:property name="authenticationFailureHandler"
			ref="failureHandler" />
		<beans:property name="authenticationSuccessHandler"
			ref="successHandler" />
	</beans:bean>

	<!-- Custom Authentication Filter -->
	<authentication-manager alias="authenticationManager">
		<authentication-provider ref="customAuthenticationProvider" />
	</authentication-manager>

	<!-- Custom Authentication Provider For details check the regarding class -->
	<beans:bean id="customAuthenticationProvider"
		class="com.tugrulaslan.security.CustomAuthenticationProvider" />

	<!-- Successful login handler -->
	<beans:bean id="successHandler"
		class="org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler">
		<beans:property name="defaultTargetUrl" value="/index.zul" />
	</beans:bean>

	<!-- Failure login handler -->
	<beans:bean id="failureHandler"
		class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
		<beans:property name="defaultFailureUrl" value="/login.zul?login_error=1" />
	</beans:bean>

	<!-- Custom Logout Handler -->
	<beans:bean id="customLogoutHandler" class="com.tugrulaslan.security.CustomLogoutHandler" />
	<beans:bean id="customLogoutFilter"
		class="org.springframework.security.web.authentication.logout.LogoutFilter">
		<beans:constructor-arg value="/login.zul" />
		<beans:constructor-arg>
			<beans:list>
				<beans:ref bean="customLogoutHandler" />
			</beans:list>
		</beans:constructor-arg>
		<beans:property name="filterProcessesUrl" value="/j_spring_security_logout" />
	</beans:bean>

	<!-- Access Denied Handler -->
	<beans:bean id="accessDeniedHandler"
		class="org.springframework.security.web.access.AccessDeniedHandlerImpl">
		<beans:property name="errorPage" value="/accessDenied.zul" />
	</beans:bean>

	<!-- Customized Login Entry Point -->
	<beans:bean id="loginUrlAuthenticationEntryPoint" scope="prototype"
		class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
		<beans:property name="loginFormUrl" value="/login.zul" />
	</beans:bean>

</beans:beans>

login.zul

<?page title="Login" contentType="text/html;charset=UTF-8"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<zk>
	<div style="width: 700px; margin-left: auto; margin-right: auto;">
		<div height="90px" width="600px"
			style="margin-left: auto; margin-right: auto;">

			
			<label value="Login page"
				style="font-size:16px; font-weight:bold; color:red" />
		</div>
		<window title="User Login Screen" border="normal"
			width="600px">
			<html:form id="loginForm" name="loginForm"
				action="j_spring_security_check" method="POST"
				xmlns:html="native">
				<grid>
					<rows>
						<row>
							<label value="Username" />
							<textbox id="username" name="j_username" width="162px" />
						</row>
						<row>
							<label value="Password" />
							<textbox id="password" type="password"
								name="j_password" width="162px" />
						</row>
						
						<row>
							<label value="Server" />
							<combobox id="server" name="server"
								readonly="true" onCreate="self.setSelectedIndex(0)">
									<comboitem value="SERVER 1"
									label="SERVER 1" />
									<comboitem value="SERVER 2"
									label="SERVER 2" />									
							</combobox>
						</row>
						<row>
							<label />

							<button id="login" type="submit"
								label="Giris" />
						</row>
					</rows>
				</grid>

				<html style="color:red"
					if="${not empty param.login_error}">
					<!-- Here spring failure messages printed -->
			<![CDATA[Hata:
					${SPRING_SECURITY_LAST_EXCEPTION.message} ]]>			
			</html>
			</html:form>
		</window>
	</div>
</zk>

Switching Between Hibernate’s and Spring’s Transaction

Reading Time: < 1 minuteUncomment the below lines to hand the activation down to Spring

pom.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.tugrulaslan</groupId>
    <artifactId>WebApp</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>BlogWebApp Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project-java.version>1.7</project-java.version>
        <maven-compiler-plugin.version>3.1</maven-compiler-plugin.version>
        <junit.version>4.11</junit.version>
        <mysql-connector.version>5.1.34</mysql-connector.version>
        <hibernate.version>4.3.8.Final</hibernate.version>
        <javax-persistance-api.version>1.0.2</javax-persistance-api.version>
        <spring.version>4.0.6.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector.version}</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>${hibernate.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
    <build>
        <finalName>BlogWebApp</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin.version}</version>
                <configuration>
                    <source>${project-java.version}</source>
                    <target>${project-java.version}</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

applicationContext.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:p="http://www.springframework.org/schema/p"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context.xsd
  http://www.springframework.org/schema/tx
  http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:property-placeholder location="classpath:hibernate.properties"/>

    <!-- Hibernate connection configuration -->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${orm.connection.driver_class}"/>
        <property name="url" value="${orm.connection.url}"/>
        <property name="username" value="${orm.connection.username}"/>
        <property name="password" value="${orm.connection.password}"/>
    </bean>

    <!-- Hibernate configuration settings -->
    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="com.tugrulaslan.entity"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${orm.dialect}</prop>
                <prop key="hibernate.show_sql">${orm.show_sql}</prop>
                <prop key="hibernate.hbm2ddl.auto">${orm.hbm2ddl.auto}</prop>
              <!-- Enabling this will trade transaction management with Hibernate--> 
                <prop key="current_session_context_class">thread</prop>
            </props>
        </property>
    </bean>

    <!-- Spring Transaction Management
    <bean id="transactionManager"
          class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/> -->

    <context:component-scan base-package="com.tugrulaslan"/>
</beans>

hibernate.properties

orm.connection.driver_class = com.mysql.jdbc.Driver
orm.connection.url = jdbc:mysql://localhost:3306/app
orm.connection.username = root
orm.connection.password = root
orm.dialect = org.hibernate.dialect.MySQLDialect
orm.show_sql = true
orm.hbm2ddl.auto = create

DAO

public interface AppDAO {
 public void saveObject(Object object);
}

DAOImpl

@Repository
public class AppDAOImpl implements AppDAO {

    @Autowired
    private SessionFactory sessionFactory;
@Override
    public void saveObject(Object object) {
        
        //Spring's session transaction management use
        //sessionFactory.getCurrentSession().saveOrUpdate(object);
        
        Session session = sessionFactory.openSession();
        Transaction transaction = session.beginTransaction();
        try {
            session.saveOrUpdate(object);
            transaction.commit();
        } catch (HibernateException e) {
            System.err.println(e);
            transaction.rollback();
        } finally {
            session.close();
        }
    }

Service

public interface AppService {
void saveObject(Object object);
}

ServiceImpl

@Service
public class AppServiceImpl implements AppService {
@Override
    //@Transactional
    public void saveObject(Object object) {
        appDAO.saveObject(object);
    }
}

 

 

Spring Junit DAO Test Transaction Rollback Issue

Reading Time: < 1 minuteFor a long while i have been having this crazy incident in Spring transaction which cause me headaches while conducting tests for backend development. The Issue i face is that I’ve dozen of test methods which test different functionality of my Database methods, firstly creation methods are being conducted and I do carry out other editing deletion test, but I need data for it.

So after the data is created next steps failed because in spring test transaction is whether successfully ended up or not it is rolled back, so after I’ve checked it ended up with the real solution. First of all you can directly set it off with the “TransactionConfiguration” annotation and in each method you define you can set the rollback as I share the code below, the rest depends on your choice

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
@Transactional
@TransactionConfiguration(defaultRollback = false)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class AppDAOTest {

    @Autowired
    private AppService appService;

    private final static String parentCatName = "TESTPARENTCATEGORY";
    private final static String childCatName = "TESTCHILDCATEGORY";
    private final static String grandChildCatName = "TESTGRANDCHILDCATEGORY";
    private final static String postName = "TESTPOST";
    private final static String userName = "TESTUSER";
    private final static String userName2 = "TESTUSERTEST";
    private Date date = new Date();

    private static long prantCatId;
    private static long childCatId;
    private static long grandChildCatId;

    @Before
    public void setUp() throws Exception {

    }

    @After
    public void tearDown() throws Exception {
        //Delete the parent category
        //appService.deleteCategory(appService.getCategoryByName(parentCatName));
    }

    @Test
    @Rollback(false)
    public void stage01_CreateParentCategoryTest() {
        //Create the parent category
        appService.createCategory(new Category(parentCatName, date, null, null, null));

        //Fetch the parent category
        Category category = appService.getCategoryByName(parentCatName);

        //Check whether the object is not null
        assertNotNull(category);

        //Check the parent category name does match
        assertEquals(parentCatName, category.getCategoryName());
    }
}

Spring JUnit and Mockito Integration/Configuration and Mock Test

Reading Time: 2 minutesIn this post roll, I’d like to show how to combine Spring, JUnit and Mockito to test a target application. Simply mocking in my definition is to set dummy data for DAO objects. The target source may have accurate data for us to test depending on given data set, in this case where the mocking plays important role in software testing. You can find further readings on the internet for the concepts. I am more interested in exposing the configuration and conducting a simple test case. First of all I’ll give you sample config of my application set, and explain further steps. I’ll walk through giving the source code.

The project hierarchy as follows;

  • src/main/java: where all the interfaces stay
  • src/test/java: where the test classes stay
  • src/test/resources: where spring context configuration stays

Maven Dependency

<dependency>
	<groupId>org.mockito</groupId>
	<artifactId>mockito-all</artifactId>
	<version>1.9.5</version>
</dependency>

DatabaseDAO Interface

public interface DatabaseDAO {	
	public String acquireUserUnitDescription(String usernumber);
}

DatabaseDAOImpl Class

@Override
	public String acquireUserUnitDescription(String usernumber) {
			...
		return unitDescription;
	}

DatabaseService Interface

public interface DatabaseService {	
	public String acquireUserUnitDescription(String usernumber);
}

DatabaseServiceImpl Class

@Autowired
DatabaseDAO databaseDAO;
	public String acquireUserUnitDescription(String usernumber) {
		return databaseDAO.acquireUserUnitDescription(usernumber);
 }

DatabaseDaoTest Class

package com.test.dao;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.when;

import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.akbank.service.DatabaseService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:*applicationContext-test.xml")
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class DatabaseDAOTest {
	
	@Autowired
	@Mock
	DatabaseService dbService;
	
	@Before
	public void setUp() throws Exception {
	MockitoAnnotations.initMocks(this);
	when(dbService.acquireUserUnitDescription("999332822")).thenReturn("Development");
	}

	@After
	public void tearDown() throws Exception {
	}
	
	@Test
	public void testMethod(){
		assertEquals("Development", dbService.acquireUserUnitDescription("999332822"));
	}
}

Output

SpringJUnitMockito

Here as you I mocked the object and the method “acquireUserUnitDescription” called with “999332822” value, then the returned value will always be “Development”

You don’t have to set the when case in the setup area, you can define it in your method as well.

Spring MVC Form Example

Reading Time: 3 minutesIn this tutorial I will show you how to create a simple form using Spring 3 MVC Web framework. I have checked other examples regarding creation of forms in Spring MVC Framework, there are many ways of achieving it. With the simplicity  of Spring MVC version 3, we are easing our forms to be implemented on forms. Especially we enjoy coding forms in spring avoiding definition of each command name or anything on xml configuration file. So let’s get started to Spring forms! We are creating a simple project adds and lists as many users as you enter. Also the project is on my Github as well, you may download the entire project

First of all we need essentially our POJO class, the below we are creating one

User.java

package com.tugrulaslan.domain;

/**
 * Created by Tugrul on 19.02.2014.
 */
public class User {

    private String firstName;
    private String lastName;
    private String email;
    private Integer age;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                '}';
    }
}

MainController.java

package com.tugrulaslan.controller;

import com.tugrulaslan.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Tugrul on 19.02.2014.
 */
@Controller
public class MainController {

    private List<User> allUserList = new ArrayList<User>();

    @RequestMapping(value = "/user-form")
    public ModelAndView personPage(){
        return new ModelAndView("user-page", "userCommand", new User());
    }

    @RequestMapping(value = "/addUser")
    public ModelAndView processPerson(@ModelAttribute User user){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("user-result-page");
        modelAndView.addObject("user", user);
        allUserList.add(user);
        return modelAndView;
    }

    @RequestMapping(value = "/listUsers")
    public ModelAndView listAllPerson(){
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("user-list");
        modelAndView.addObject("users",allUserList);

        return modelAndView;
    }
}

Here is the important point what we need to focus on “userCommand” in “personPage”, we need to combine and link our controller to the desired form area, also the form variables need to be hooked up with the domain object, on the 3rd parameter we are sending a new class of User POJO the below evaluate the

user-page.jsp

<%--
  Created by IntelliJ IDEA.
  User: Tugrul
  Date: 19.02.2014
  Time: 11:19
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>

<html>
<head>
    <title>Person Form</title>
</head>
<body>
<form:form method="post" commandName="userCommand" action="addUser.html">
    <table>
        <tbody>
        <tr>
            <td><form:label path="firstName">Firstname: </form:label></td>
            <td><form:input path="firstName" /></td>
        </tr>
        <tr>
            <td><form:label path="lastName">Lastname: </form:label></td>
            <td><form:input path="lastName" /></td>
        </tr>
        <tr>
            <td><form:label path="email">Email: </form:label></td>
            <td><form:input path="email" /></td>
        </tr>
        <tr>
            <td><form:label path="age">Age: </form:label></td>
            <td><form:input path="age" /></td>
        </tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Add User" />
            </td>
        </tr>
        </tbody>
    </table>
</form:form>

</body>
</html>

As we see the simple form here, we have combined our controller and User POJO class with each other to provide the communication.

user-list.jsp

<%--
  Created by IntelliJ IDEA.
  User: Tugrul
  Date: 19.02.2014
  Time: 11:40
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Person List</title>
</head>
<body>
<h1>User List</h1>
<c:if test="${not empty users}">
    <table border="1">
        <tr>
            <td>Firstname</td>
            <td>Lastname</td>
            <td>Email</td>
            <td>Age</td>
        </tr>
        <c:forEach var="element" items="${users}">
            <tr>
                <td>${element.firstName}</td>
                <td>${element.lastName}</td>
                <td>${element.email}</td>
                <td>${element.age}</td>
            </tr>
        </c:forEach>
    </table>
</c:if>
<a href="/">Index</a><br />
</body>
</html>

Here we are listing all registered and stored users in our list defined in our controller class

user-result-page.jsp

<%--
  Created by IntelliJ IDEA.
  User: Tugrul
  Date: 19.02.2014
  Time: 11:23
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Person Result Page</title>
</head>
<body>
<h1>Created User Details</h1>
<p><b>First Name:</b> ${user.firstName}</p>
<p><b>Last Name:</b> ${user.lastName}</p>
<p><b>Email:</b> ${user.email}</p>
<p><b>Age:</b> ${user.age}</p>
<a href="/">Index</a>
</body>
</html>

where we show the outcome what the user has entered

index.jsp

<%--
  Created by IntelliJ IDEA.
  User: Tugrul
  Date: 19.02.2014
  Time: 11:40
  To change this template use File | Settings | File Templates.
--%>
<html>
<body>
<h2>===Main Menu===</h2>
</body>
<a href="/user-form">Add a New User</a><br />
<a href="/listUsers">List All Users</a>
</html>

Web.xml

<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>Archetype Created Web Application</display-name>
    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
</web-app>

mvc-dispatcher-servlet.xml

<beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
               xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
               xmlns:util="http://www.springframework.org/schema/util" xmlns:jee="http://www.springframework.org/schema/jee"
               xmlns:lang="http://www.springframework.org/schema/lang" xmlns:mvc="http://www.springframework.org/schema/mvc"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc.xsd
                        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
        				http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd
        				http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        				http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

<context:component-scan
        base-package="com.tugrulaslan.controller" />

<bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix">
        <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
        <value>.jsp</value>
    </property>
</bean>

<mvc:annotation-driven />

</beans>

pom.xml

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         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.tugrulaslan</groupId>
    <artifactId>SpringFormExample</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SpringFormExample Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <org.springframework.version>3.2.6.RELEASE</org.springframework.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.1</version>
        </dependency>

        <dependency>
            <groupId>jstl</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>taglibs</groupId>
            <artifactId>standard</artifactId>
            <version>1.1.2</version>
        </dependency>


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>


        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${org.springframework.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${org.springframework.version}</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>
    <build>
        <finalName>SpringFormExample</finalName>
    </build>
</project>