Showing posts with label Spring. Show all posts
Showing posts with label Spring. Show all posts

Wednesday, October 28, 2015

Unit Testing of AngularJS in Spring MVC maven project using Jasmine, PhantomJS, and Jenkins CI

This post is about some links on how to perform unit testing of angularjs in spring MVC project. One typical setup is with Jasmine and phantomjs.

Some general descriptions of these tools: jasmine is a behavior-driven development framework for testing javascript, phantomjs is a headless browser, which can be invoked on Jenkins CI to run unit testing of angularjs (Jenkins CI is a continuous integration server that supports building and testing of software projects)

POM setup


Firstly includes the following in your maven POM file

<properties>
<angularjs.version>1.4.3-1</angularjs.version>
<phantomjs.outputDir>${java.io.tmpdir}/phantomjs</phantomjs.outputDir>
</properties>

<build>
  <pluginManagement>
        <plugins>
            <!--This plugin's configuration is used to store Eclipse m2e settings 
                only. It has no influence on the Maven build itself. -->
            <plugin>
                <groupId>org.eclipse.m2e</groupId>
                <artifactId>lifecycle-mapping</artifactId>
                <version>1.0.0</version>
                <configuration>
                    <lifecycleMappingMetadata>
                        <pluginExecutions>
                            <pluginExecution>
                                <pluginExecutionFilter>
                                <groupId>com.github.klieber</groupId>
              <artifactId>phantomjs-maven-plugin</artifactId>
                                    <versionRange>
                                        [0.7,)
                                    </versionRange>
                                    <goals>
                                        <goal>install</goal>
                                    </goals>
                                </pluginExecutionFilter>
                                <action>
                                    <ignore></ignore>
                                </action>
                            </pluginExecution>
                        </pluginExecutions>
                    </lifecycleMappingMetadata>
                </configuration>
            </plugin>
        </plugins>
    </pluginManagement>

<plugins>

<plugin>
          <groupId>com.github.klieber</groupId>
          <artifactId>phantomjs-maven-plugin</artifactId>
          <version>0.7</version>
          <executions>
            <execution>
              <goals>
                <goal>install</goal>
              </goals>
            </execution>
          </executions>
          <configuration>
            <version>1.9.7</version>
          </configuration>
        </plugin>
   <plugin>
     <groupId>com.github.searls</groupId>
     <artifactId>jasmine-maven-plugin</artifactId>
     <version>2.0-alpha-01</version>
     <executions>
       <execution>
         <goals>
           <goal>test</goal>
         </goals>
       </execution>
     </executions>
     
  
     
     <configuration>
       <additionalContexts>
         <context>
           <contextRoot>/lib</contextRoot>
           <directory>${project.build.directory}/generated-resources/unit/ml/js</directory>
         </context>
       </additionalContexts>
       <skipTests>true</skipTests>
       <preloadSources>
          <source>/webjars/jquery/2.1.3/jquery.min.js</source>
     <source>/webjars/bootstrap/3.3.5/js/bootstrap.min.js</source>
     <source>/webjars/angularjs/${angularjs.version}/angular.min.js</source>
     <source>/webjars/angularjs/${angularjs.version}/angular-route.min.js</source>
     <source>/webjars/angularjs/${angularjs.version}/angular-animate.min.js</source>
    
      <source>/webjars/angularjs/${angularjs.version}/angular-mocks.js</source>
       </preloadSources>
       <jsSrcDir>${project.basedir}/src/main/resources/js</jsSrcDir>
       <jsTestSrcDir>${project.basedir}/src/test/resources/js</jsTestSrcDir>
       <webDriverClassName>org.openqa.selenium.phantomjs.PhantomJSDriver</webDriverClassName>
      <webDriverCapabilities>
     <capability>
      <name>phantomjs.binary.path</name>
      <value>${phantomjs.binary}</value>
     </capability>
    </webDriverCapabilities>
     </configuration>
   </plugin>
  </plugins>

  
<build>  


In the <plugins> section two plugins, namely jasmine and phantomjs maven plugins are added. The jasmine plugin is for jasmine to be used for unit testing and the phantomjs will download the phantomjs executable into a tmp folder so that it can be invoked to run the unit testing by Jenkins. The phantomjs maven plugin is very useful in that when the project is fetched by Jenkins CI to perform testing, the machine running Jenkins CI may not have phantomjs pre-installed. With the phantomjs maven plugin and the "install" goal specified in it, the Jenkins will search locally whether a copy of phantomjs is available in the specified phantomjs.outputDir folder, if not, it will download from the internet and put it in the phantomjs.outputDir folder, and after that the plugin set the phantomjs.binary parameter automatically, so that Jenkins CI knows where to find the phantomjs executable.

The org.eclipse.m2e lifecycle-mapping specified in the <pluginManagement> is used to stop Eclipse from complaining m2e cannot under the "install" goal specified in the phantomjs maven plugin. It does not have any effect on maven when it builds and run the project.

Implement Jasmine and spring unit testing codes


For this, there is already a nice article on how to do it here at:

https://spring.io/blog/2015/05/19/testing-an-angular-application-angular-js-and-spring-security-part-viii

Therefore I won't repeat it.

Tuesday, October 27, 2015

Building Asynchronous RESTful Services With Spring MVC and Guava

Recently I was working some asynchronous RESTful services in the Spring MVC framework in which i am thinking of using Guava to reduce the effort in development. After failing to find any good reference on using Guava with Spring MVC's asynchronous RESTful operation, I decide to do it by trial and error. In the end, it turned out to be quite easy. This post shows how to develop asynchronous RESTful services with spring mvc and google's Guava library.

Firstly includes the dependencies for Guava in your spring MVC project.

Implementation using Guava in Spring MVC


Now write a simple spring service something like the one below:


import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MyLongRunningServiceImpl extends MyLongRunningService {
   private ListeningExecutorService service;
 
   public MyLongRunningService(){
     service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
   }

   public ListenableFuture<Date> doLongRunningProcess(final int milliseconds){
 ListenableFuture<date> future = service.submit(new Callable<date>() {
            public Date call() throws Exception {
                Thread.sleep(milliseconds
                return new Date();
            }
        });

 return future;
   }
}

As shown in the code above the service has a method which delay a number user-specified milliseconds before returning a Date object. Next write a simple controller that autowires with the service:


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.request.async.DeferredResult;


@Controller
public class MyLongRunningController {
  @Autowired
  private MyLongRunningService service;

  @RequestMapping(value="/longRun", method = RequestMethod.GET)
 public @ResponseBody DeferredResult<Date> doLongRunningProcess(){
  
  DeferredResult<Date> deferredResult = new DeferredResult<>();

   
  logger.info("start long running process");
  
  
  ListenableFuture<Date> future = service.doLongRunningProcess(60000);
  
  Futures.addCallback(future, new FutureCallback<Date>(){

   @Override
   public void onFailure(Throwable throwable) {
    logger.error("long running process failed", throwable);

   }

   @Override
   public void onSuccess(Date res) {
    logger.info("long running process returns");
    
     
    deferredResult.setResult(res);
   }
   
  });
  
  
  return deferredResult;
 }
}

This completes the coding part. There are two notes apart from the above implementation in order to make the asynchronous RESTful service to work:

<async-supported>true</async-supported>


The first thing is that the user needs to add in the following XML element into their web.xml configuration

<async-supported>true</async-supported>

This should be put under both <servlet> section (for the servlet which contains the spring controller above) as well as the <filter> section of the "org.springframework.web.filter.DelegatingFilterProxy"

asyncTimeout

If you are using Tomcat server as the servlet and http container for your spring MVC, that the asyncTimeout need to be added into the <Connector> element of the /conf/server.xml in tomcat directory, so that async services won't be terminated before tomcat's timeout, e.g.,

<Connector asyncTimeout="60000" ... >

If you are using javascript to interact with the asynchronous RESTful services, you may also need to specify the timeout property (e.g., in the $http of angularjs) so that the http call will not terminate before the asynchronous service call is completed.

Saturday, October 17, 2015

Eclipse Tomcat: class path resource [properties/server-${spring.profiles.active}.properties] cannot be opened because it does not exist

Today I encounter this error when working on a spring project in eclipse when trying to start the tomcat server on the spring mvc project:

"class path resource [properties/server-${spring.profiles.active}.properties] cannot be opened because it does not exist"

The issues turned out to be that the spring project has two properties files: namely server-dev.properties and server-production.properties. The project define a property "spring.profiles.active" which need to be supplied to the tomcat server when launching the spring mvc project so that the proper properties file can be loaded. The problem occurred because i was did not specify the argument when launching the project. To resolve this, double click the tomcat server instance in the "Servers" window in Eclipse and click the "Overview" tab. In the "Overview" tab, click "Open launch configuration" link. In the "Edit Configuration" dialog opened, click the "Arguments" tab, and append the following to the "VM arguments" textbox:

-Dspring.profiles.active=dev


Wednesday, June 17, 2015

Deploy spring mvc application in cloud

After login to the cloud computing instance, run either the "uname -a" or "cat /etc/redhat-release" to discuss the linux os version of the instance.

Follows the following link to install and run tomcat server:
http://tecadmin.net/install-tomcat-8-on-centos-rhel-and-ubuntu


If your spring mvc uses MySQL for database backend, follows the following link to install and run mysql:

http://www.rackspace.com/knowledge_center/article/installing-mysql-server-on-centos
(for centos 7): https://devops.profitbricks.com/tutorials/install-mysql-on-centos-7/

Once you have the environment setup, follow the link below to deploy your Spring MVC framework into the cloud computing instance:

link: http://www.mkyong.com/maven/how-to-deploy-maven-based-war-file-to-tomcat/


Wednesday, May 27, 2015

Spring: AngularJS login integration with Spring Security (Spring Security 3 and Spring Security 4)

This post shows how to use angularjs for login to spring mvc with spring security set to custom <form-login>

Spring security 3

Below is the login.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head ng-app="login-module">
<script src="angular.min.js"></script>
<script src="login.js"></script>
</head>
<body ng-controller="MainController">
<form>
<input type="text" name="username" ng-model="myusername" />
<input type="password" name="password" ng-model="mypassword" />
<button ng-click="login('<c:url value="/" />', myusername, mypassowrd)" />
</form>
</body>
</html>

The login.js looks like the following:

(function(){
 var MainController = function($scope, $http, $log){
  
  var encode4form = function(data){
   var result="";
   var first = true;
   for(var key in data)
   {
    if(first){
     first=false;
    }
    else{
     result+="&"
    }
    result+=(key + "=" + data[key]);
   }
   $log.info(result);
   return result;
  };
  
  $scope.login = function(myspringappname, myusername, mypassword){
   $http(
     {
      url: "/"+myspringappname+"/j_spring_security_check", 
      method:"POST",
      data: encode4form({
       j_username: myusername,
       j_password: mypassword
       }),
      headers: 
      {
       "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
      }
     }
   ).success(function(response){
    $log.info(response);
   });
  };
  
  
  var onError = function(reason){
   $log.error(reason);
   alert(reason);
  };
  
  
 };
 
 var module=angular.module("login-module", []);
 module.controller("MainController", ["$scope", "$http", "$log", MainController]);
}());

Spring Security 4

Below is the login.jsp:


<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head ng-app="login-module">
<script src="angular.min.js"></script>
<script src="login.js"></script>
</head>
<body ng-controller="MainController">
<form>
<input type="text" name="username" ng-model="myusername" />
<input type="password" name="password" ng-model="mypassword" />
<button ng-click="login('<c:url value="/" />', myusername, mypassowrd, '${_csrf.token}')" />
</form>
</body>
</html>

The login.js looks like the following:

(function(){
 var MainController = function($scope, $http, $log){
  
  var encode4form = function(data){
   var result="";
   var first = true;
   for(var key in data)
   {
    if(first){
     first=false;
    }
    else{
     result+="&"
    }
    result+=(key + "=" + data[key]);
   }
   $log.info(result);
   return result;
  };
  
  $scope.login = function(myspringappname, myusername, mypassword, mycsrf){
   $http(
     {
      url: "/"+myspringappname+"/login", 
      method:"POST",
      data: encode4form({
       username: myusername,
       password: mypassword,
       _csrf: mycsrf
       }),
      headers: 
      {
       "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
      }
     }
   ).success(function(response){
    $log.info(response);
   });
  };
  
  
  var onError = function(reason){
   $log.error(reason);
   alert(reason);
  };
  
  
 };
 
 var module=angular.module("login-module", []);
 module.controller("MainController", ["$scope", "$http", "$log", MainController]);
}());


Spring: Migrating from spring security 3.2.6 to spring security 4.0.0

In this post, i document some changes i went through to successfully migrate from security 3.2.6 to spring security 4.0.0

Changes in <http> in security-config.xml 

In security-config.xml, if you have the <http> section set to:

<http auto-config="true">

For spring security 3.2.6, the following is implied:

  • <http auto-config="true"> is same as <http auto-config="true" use-expressions="false">
For spring security 4.0.0, the following is implied instead:

  • <http auto-config="true"> is same as <http auto-config="true" use-expressions="true"> 
Therefore, need to be careful if you do not use expressions, as in that case you need to set use-expressions="false" in the <http> element

Changes in JSP views 

In spring security 4.0.0, the csrf is enabled by default, which is equivalent to:

<http auto-config="true">
<csrf disabled="false" />
...
</http>

Therefore, some changes must be made in your jsp views as well as ajax calls, as the _csrf fields must be posted back to the spring controller for the codes to work if you are using spring security 4.0.0 instead of spring security 3. Suppose that when using the security 3, I have the following form submit in my jsp view for login:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<html>
<head>
</head>
<body>
<form name="f" action="j_spring_security_check" method="post">
<table>
<tr><td>Username:</td>
<td>
<input type="text" value="j_username" />
</td></tr>

<tr><td>Password: </td>
<td>
<input type="password" value="j_password" />
</td></tr>

<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>
</body>
</html>

Then in spring security 4.0.0, I need to change it to:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" />
<html>
<head>
</head>
<body>
<form name="f" action="" method="post">

<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<table>
<tr><td>Username:</td>
<td>
<input type="text" value="username" />
</td></tr>

<tr><td>Password: </td>
<td>
<input type="password" value="password" />
</td></tr>


<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>
</body>
</html>

In other words, the following changes must be made:

  • "j_username" changed to "username"
  • "j_password" changed to "password"
  • "j_spring_security_check" changed to "<c:url value="/login" />" 
  • add in a line in the form for
    csrf: <input type="hidden" name="${_csrf.parameterName}" value="$_csrf.token}" />
Then in each of my jsp views, if any form post action, the following hidden field must be included:
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />

Similarly, in spring security 3.2.6, i can logout using a <a> link like this:

<a href="j_spring_security_logout">Logout</a>

Now in sprig security 4.0.0, I need to do the following instead:

<form action="<c:url value="/logout" />" method="post">
 <input type="submit" value="Logout" />
 
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>