星期三, 十二月 18, 2013

Create a restful application with AngularJS and Grails(4):Standalone AngularJS application


Standalone AngularJS application

In the real world applications, it is usually required to integrate the third party APIs into the project. Most of case, the third party service is provided as flexible REST APIs for developers.
Imagine the REST API in this sample could sever other applications, such as a mobile app or other website in future, ideally it should be designated as an API centric application.
The AngularJS codes can be moved to a standalone application, and consume the REST web service remotely, like other applications.
Split the original codes into two projects.
/
 /client
 /server
The client is an AngularJS based application. The codes are based on AngularJS Seed sandbox. I copied the app folder in the former Grails application.
The server is nearly no difference from the original Grails part, but the app folder in the web-app folder is moved to client. Additionally, you have to configure CORS in the server side.

Configure CORS

There is a good post from the Spring community to help you understand CORS(Cross-Origin Resource Sharing).
The post provides a solution to resolve the limitation of cross domain resource accessing.
But I would like use a CORS filter from Ebay, I have used it in projects and it has some configuration options.
By default, the Grails application does not includes a web.xml file, it is generated from the default templates at runtime. Use the following command to install the templates for this projects.
grails install-templates
Open the web.xml file under the src/templates/war folder.
Configure CORS filter in the web.xml.
<filter>
 <filter-name>CORS Filter</filter-name>
 <filter-class>org.ebaysf.web.cors.CORSFilter</filter-class>
 <init-param>
  <description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
  <param-name>cors.allowed.origins</param-name>
  <param-value>http://localhost:8000, http://localhost:8080</param-value>
 </init-param>
 <init-param>
  <description>A comma separated list of HTTP verbs, using which a CORS
   request can be made.</description>
  <param-name>cors.allowed.methods</param-name>
  <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
 </init-param>
 <init-param>
  <description>A comma separated list of allowed headers when making a non simple CORS request.</description>
  <param-name>cors.allowed.headers</param-name>
  <param-value>Content-Type,X-Requested-With,Authorization,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
 </init-param>
 <init-param>
  <description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description>
  <param-name>cors.exposed.headers</param-name>
  <param-value></param-value>
 </init-param>
 <init-param>
  <description>A flag that suggests if CORS is supported with cookies</description>
  <param-name>cors.support.credentials</param-name>
  <param-value>true</param-value>
 </init-param>
 <init-param>
  <description>A flag to control logging</description>
  <param-name>cors.logging.enabled</param-name>
  <param-value>true</param-value>
 </init-param>
 <init-param>
  <description>Indicates how long (in seconds) the results of a preflight request can be cached in a preflight result cache.</description>
  <param-name>cors.preflight.maxage</param-name>
  <param-value>10</param-value>
 </init-param>
</filter>
<filter-mapping>
 <filter-name>CORS Filter</filter-name>
 <url-pattern>/*</url-pattern>
</filter-mapping>
Run the server project as a Grails application from command line or IDE. Now it works as a REST API producer and severs client applications.
And then run the client project as a NodeJS application.
node scripts\web-server.js

Sample codes

Create a restful application with AngularJS and Grails(3): Authentication and Authorization


Authentication and Authorization

Grails provides a series of built-in authentication solutions, such as Form, Basic, Digest etc. And there are several additional plugins which provides CAS, OAuth authentication, please search them from the official Grails.org website.
For API centric applications, Basic is the simplest authentication.

Configure Basic authentication

By default, Form based authentication is enabled, it is easy to configure Basic authentication in Grails application.
Includes the following line in the Config.groovy file.
grails.plugin.springsecurity.useBasicAuth = true
Basic authentication includes a specific basicExceptionTranslationFilter, so the general-purpose exceptionTranslationFilter can be excluded.
grails.plugin.springsecurity.filterChain.chainMap = [
 '/api/**':'JOINED_FILTERS,-exceptionTranslationFilter',
 '/**':JOINED_FILTERS,-basicAuthenticationFilter,-basicExceptionTranslationFilter'
 ]
All resources matched /api/** will be protected and require authentication.
Try access the a protected resource, for example, http://localhost:8080/angularjs-grails-sample/api/books.json. There is a browser prompt popup for requiring username and password.

Stateless API

By default, Grails will create session to store the client principle, it is useful for a web application. For a REST API, it is usually designated as stateless.
Spring security provides a stateless option in http element. In Grails, you could have to configure it yourself.
In the resources.groovy file, declare a SecurityContextRepository andSecurityContextPersistenceFilter bean.
statelessSecurityContextRepository(NullSecurityContextRepository) {}

statelessSecurityContextPersistenceFilter(SecurityContextPersistenceFilter, ref('statelessSecurityContextRepository')) { }
The SecurityContextPersistenceFilter is responsible for session creation, and it delegates the real work to SecurityContextRepository bean.NullSecurityContextRepository is an implementation of SecurityContextRepository which does not create the user data in HttpSession, it is suitable for stateless case.
Apply it in Config.groovy.
grails.plugin.springsecurity.filterChain.chainMap = [
 '/api/**': 'statelessSecurityContextPersistenceFilter,logoutFilter,authenticationProcessingFilter,customBasicAuthenticationFilter,securityContextHolderAwareRequestFilter,rememberMeAuthenticationFilter,anonymousAuthenticationFilter,basicExceptionTranslationFilter,filterInvocationInterceptor',
 ]
In the above, all filters used for /api/ url pattern are listed one by one.
There are some options for the configuration of the filters.
  • If the value includes a JOINED_FILTERS, it is indicates it will includes all default filters. You can append -filterName to exclude the filter from the default filter list. For example,
   JOINED_FILTERS,-basicExceptionTranslationFilter
It will include all filters but excludes basicExceptionTranslationFilter.
  • If the value is none, security will skip the url pattern.
  • You can specify the filters one by one.
Note: The exclusion can be used only with JOINED_FILTERS option.
I also create a custom BasicAuthenticationEntryPoint.
public class CustomBasicAuthenticationEntryPoint extends
  BasicAuthenticationEntryPoint {

 private static Logger log = LoggerFactory
   .getLogger(CustomBasicAuthenticationEntryPoint.class);

 @Override
 public void commence(HttpServletRequest request,
   HttpServletResponse response, AuthenticationException authException)
   throws IOException, ServletException {
  // TODO Auto-generated method stub
  // super.commence(request, response, authException);
  log.debug("call @ commence...");
  response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
 }

}
The purpose is simple, it maps all authentication and authorization exception to 401 status. This will simplify the frontend AngluarJS processing work.
Configure this AuthenticationEntryPoint in resources.groovy.
customBasicAuthenticationEntryPoint(CustomBasicAuthenticationEntryPoint) {
 realmName = SpringSecurityUtils.securityConfig.basic.realmName // 'Grails Realm'
}

customBasicAuthenticationFilter(BasicAuthenticationFilter, ref('authenticationManager'), ref('customBasicAuthenticationEntryPoint')) {
 authenticationDetailsSource = ref('authenticationDetailsSource')
 rememberMeServices = ref('rememberMeServices')
 credentialsCharset = SpringSecurityUtils.securityConfig.basic.credentialsCharset // 'UTF-8'
}

basicAccessDeniedHandler(AccessDeniedHandlerImpl)

basicRequestCache(NullRequestCache)

basicExceptionTranslationFilter(ExceptionTranslationFilter, ref('customBasicAuthenticationEntryPoint'), ref('basicRequestCache')) {
 accessDeniedHandler = ref('basicAccessDeniedHandler')
 authenticationTrustResolver = ref('authenticationTrustResolver')
 throwableAnalyzer = ref('throwableAnalyzer')
}

Sample codes

Create a restful application with AngularJS and Grails(2): Secure the backend REST API


Secure the backend REST API

In Spring application, Spring Security is usually used to secure the application. Grails has a builtin Spring Security based plugin to integrate Spring Security into Grails applications.

Install SpringSecurity core plugin

Open BuildConfig.groovy file, add spring-security-core plugin.
plugins {
 ...
 compile ":spring-security-core:2.0-RC2"
}
Run the following command in the project root folder to initialize the spring security plugin.
grails compile --non-interactive --refresh-dependencies
And use the built-in s2-quickstart script from this plugin to create the essential domain classes.
grails s2-quickstart Person Authority Requestmap
When it is done, the basic security configuration is added in Config.groovy.
grails.plugin.springsecurity.userLookup.userDomainClassName = 'com.hantsylabs.grails.example.security.Person'
grails.plugin.springsecurity.userLookup.authorityJoinClassName = 'com.hantsylabs.grails.example.security.PersonAuthority'
grails.plugin.springsecurity.authority.className = 'com.hantsylabs.grails.example.security.Authority'
grails.plugin.springsecurity.requestMap.className = 'com.hantsylabs.grails.example.security.Requestmap'
grails.plugin.springsecurity.securityConfigType = 'Annotation'
grails.plugin.springsecurity.controllerAnnotations.staticRules = [
 '/':                              ['permitAll'],
 '/index':                         ['permitAll'],
 '/index.gsp':                     ['permitAll'],
 '/**/js/**':                      ['permitAll'],
 '/**/css/**':                     ['permitAll'],
 '/**/images/**':                  ['permitAll'],
 '/**/favicon.ico':                ['permitAll']
 ]

Configure securityConfigType

There are three securityConfigType supported by this spring security plugin.
  • Annotation
  • InterceptUrlMap
  • Requestmap
By default, the Annotation type is configured.
grails.plugin.springsecurity.controllerAnnotations.staticRules is use for configuring the protection rule for the static resources. It is a map, the key is the url, the value is the configuration attribute which is a list and can accept the Spring security constants or Spring expression, eg. IS_AUTHENTICATED, isFullyAuthenticated(). If you have some experience of Spring security before, it is easy to understatnd.
Besides these, in your Java codes, you can use Grails or Spring Security specific @Securedannotation on methods in a Controller to apply the security restrict rules.
If you select InterceptUrlMap, all resources are protected by url intercepting only.
grails.plugin.springsecurity.securityConfigType = 'InterceptUrlMap'
grails.plugin.springsecurity.interceptUrlMap  = [
 '/':                              ['permitAll'],
 '/index':                         ['permitAll'],
 '/index.gsp':                     ['permitAll'],
 '/**/js/**':                      ['permitAll'],
 '/**/css/**':                     ['permitAll'],
 '/**/images/**':                  ['permitAll'],
 '/**/favicon.ico':                ['permitAll']
 ]
For Requestmap, it is easy to understand, it store the url intercepting mapping rules into database.
grails.plugin.springsecurity.securityConfigType = 'Requestmap'
There is a Requestmap class already generated for this project.
class Requestmap {

 String url
 String configAttribute
 HttpMethod httpMethod

 static mapping = {
  cache true
 }

 static constraints = {
  url blank: false, unique: 'httpMethod'
  configAttribute blank: false
  httpMethod nullable: true
 }
}
In the BootStrap.groovy class, you can add some codes to initialize the Requestmap.
def init = { servletContext ->
 ...
  for (String url in [
   '/', '/index', '/index.gsp', '/**/favicon.ico',
   '/**/js/**', '/**/css/**', '/**/images/**',
   '/login', '/login.*', '/login/*',
   '/logout', '/logout.*', '/logout/*']) {
   new Requestmap(url: url, configAttribute: 'permitAll').save()
   }

}
In this sample, InterceptUrlMap is used as example.
grails.plugin.springsecurity.securityConfigType = 'InterceptUrlMap'
grails.plugin.springsecurity.interceptUrlMap  = [
 '/':                              ['permitAll'],
 '/index':                         ['permitAll'],
 '/index.gsp':                     ['permitAll'],
 '/**/js/**':                      ['permitAll'],
 '/**/css/**':                     ['permitAll'],
 '/**/images/**':                  ['permitAll'],
 '/**/favicon.ico':                ['permitAll'],
 '/login/**':                 ['permitAll'],
 '/logout/**':                 ['permitAll'],
 '/**':      ['isFullyAuthenticated()']
 ]
The security plugin provides a LoginController and LogoutController for login and logout actions.

Run the project

Open BootStrap.groovy file, add some sample user data for test purpose.
def init = { servletContext ->
  
 def person =new Person(username:"test", password:"test123")
 person.save()
  
 def roleUser=new Authority(authority:"ROLE_USER")
 roleUser.save()
  
 new PersonAuthority(person:person, authority:roleUser).save()
}
In Eclipse IDE(Spring ToolSuite), select Run as-> Grails Command(run-app) in the project context menu,
Or in the command line, run the following command in the project root folder to run the this project.
grails run-app
Try to access the protected REST API resources, for example,http://localhost:8080/angluarjs-grails-sample/books.json. It will redirect to a login page. Login as test/test123, it will show the protected resources.

Sample codes

星期一, 十二月 16, 2013

Spring 4: Groovy DSL bean definition


Spring 4: Groovy DSL bean definition

In Spring 2.x, script language is supported in Spring via the Java scripting engine.
In Spring 4.0, Groovy is a first class citizen in Spring. Groovy can be used as an alternative for configuring bean definition.

Groovy DSL bean definition

As a Spring developer, you could be very familiar with XML based or/and Java annotation based bean definition.
The following is an example of XML bean definition.
<jdbc:embedded-database id="dataSource" type="H2">
</jdbc:embedded-database>

<bean
 class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
 id="entityManagerFactory">
 <property name="persistenceUnitName" value="persistenceUnit" />
 <property name="dataSource" ref="dataSource" />
 <property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence"></property>
 <property name="packagesToScan">
  <array>
   <value>com.hantsylabs.example.spring.model</value>
  </array>
 </property>
 <property name="jpaProperties">
  <value>
   hibernate.format_sql=true
   hibernate.show_sql=true
   hibernate.hbm2ddl.auto=create
  </value>
 </property>
</bean>

<bean class="org.springframework.orm.jpa.JpaTransactionManager"
 id="transactionManager">
 <property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
The following is the equivalent bean definition using Java annotation.
@Configuration
@ComponentScan(basePackages = { "com.hantsylabs.example.spring.dao",
  "com.hantsylabs.example.spring.jpa" })
@EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
public class JpaConfig {

 @Bean
 public DataSource dataSource() {
  return new EmbeddedDatabaseBuilder().setType(EmbeddedDatabaseType.H2).build();
 }

 @Bean
 public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
  LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
  emf.setDataSource(dataSource());
  emf.setPackagesToScan("com.hantsylabs.example.spring.model");
  emf.setPersistenceProvider(new HibernatePersistence());
  emf.setJpaProperties(jpaProperties());
  return emf;
 }

 private Properties jpaProperties() {
  Properties extraProperties = new Properties();
  extraProperties.put("hibernate.format_sql", "true");
  extraProperties.put("hibernate.show_sql", "true");
  extraProperties.put("hibernate.hbm2ddl.auto", "create");
  return extraProperties;
 }

 @Bean
 public PlatformTransactionManager transactionManager() {
  return new JpaTransactionManager(entityManagerFactory().getObject());
 }

}
The following content defines these beans in Groovy DSL way.
import org.apache.commons.dbcp.BasicDataSource
import org.springframework.orm.jpa.JpaTransactionManager
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
import com.hantsylabs.example.spring.jpa.JpaConferenceDaoImpl

beans {
     dataSource(BasicDataSource) {   
   driverClassName = "org.h2.Driver"
         url = "jdbc:h2:mem:spring4-sandbox"
         username = "sa"
         password = ""
     }
  
  entityManagerFactory(LocalContainerEntityManagerFactoryBean){
   persistenceProviderClass="org.hibernate.ejb.HibernatePersistence"
   dataSource=dataSource
   persistenceUnitName="persistenceUnit"
   packagesToScan=["com.hantsylabs.example.spring.model"]
   jpaProperties=[
    "hibernate.format_sql":"true",
    "hibernate.show_sql":"true",
    "hibernate.hbm2ddl.auto":"create"
    ]
  }
  
  transactionManager(JpaTransactionManager){
   entityManagerFactory=entityManagerFactory
  }
  
  conferenceDao(JpaConferenceDaoImpl){
  }

 }
If you have some experience of Grails, you could have recognized this feature is similar with the Grails resources.groovy.
Add groovy as a dependency in your Maven pom.xml.
<dependency>
 <groupId>org.codehaus.groovy</groupId>
 <artifactId>groovy-all</artifactId>
 <version>2.1.8</version>
</dependency>
Now you can write some test codes.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:/com/hantsylabs/example/spring/config/JpaConfigGroovy.groovy", loader = GenericGroovyContextLoader.class)
@TransactionConfiguration
public class GroovyJpaConferenceDaoImplTest {

 public static class GenericGroovyContextLoader extends
   AbstractGenericContextLoader {

  @Override
  protected BeanDefinitionReader createBeanDefinitionReader(
    GenericApplicationContext context) {
   return new GroovyBeanDefinitionReader(context);
  }

  @Override
  protected String getResourceSuffix() {
   return ".groovy";
  }

 }
 
 // test codes
}
I've tried to load the Groovy bean definition resource through @ContextConfigurationannotation, but it does not work. By default, the locations and value are ready for loading XML bean definition. Spring 4.0 includes a GroovyBeanDefinitionReader for reading and parsing Groovy bean definition. It is easy to write a custom context loader for loading the Groovy bean definition.
The Conference, ConferenceDao, JpaConferneceDaoImpl, and the CRUD test cases are no difference from my before posts.
In a web application, you can load the Groovy bean configuration in your bootstrap class(WebApplicationIntializer) via a Groovy specific GenericGroovyApplicationContext.
ApplicationContext ctx=new GenericGroovyApplicationContext("classpath:/com/hantsylabs/example/spring/config/JpaConfigGroovy.groovy");

Create Spring Bean in Groovy way

Create a simple ConferenceService bean, but use Groovy, put it under src/main/groovyfolder.
package com.hantsylabs.example.spring.service

import com.hantsylabs.example.spring.dao.ConferenceDao

class ConferenceService {
 
 def conferenceDao
 
 def findConferenceBySlug(String slug) {
  conferenceDao.findBySlug(slug)
 }
 
}
Declare it as a Spring bean in JpaConfigGroovy.groovy file.
conferenceService(ConferenceService){
 conferenceDao=conferenceDao
}
Test it.
package com.hantsylabs.example.spring.dao;

//other imports are omitted
import com.hantsylabs.example.spring.service.ConferenceService;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(value = "classpath:/com/hantsylabs/example/spring/config/JpaConfigGroovy.groovy", loader = GenericGroovyContextLoader.class)
@TransactionConfiguration
public class GroovyConferenceServiceTest {
 //all duplicated codes are omitted
 @Autowired
 ConferenceService conferenceService;

 @Test
 @Transactional
 public void retrieveConference() {
  //all duplicated codes are omitted
  // query by slug
  conference = (Conference) conferenceService.findConferenceBySlug("jud-2013");

  assertTrue(conference != null);
 }
}
Groovy files are put in src/main/groovy, you need to configure the java compiler to compile groovy files.
<plugin>
 <artifactId>maven-compiler-plugin</artifactId>
 <!-- 2.8.0-01 and later require maven-compiler-plugin 3.1 or higher -->
 <version>3.1</version>
 <configuration>
  <compilerId>groovy-eclipse-compiler</compilerId>
  <!-- set verbose to be true if you want lots of uninteresting messages -->
  <!-- <verbose>true</verbose> -->
 </configuration>
 <dependencies>
  <dependency>
   <groupId>org.codehaus.groovy</groupId>
   <artifactId>groovy-eclipse-compiler</artifactId>
   <version>2.8.0-01</version>
  </dependency>
  <!-- for 2.8.0-01 and later you must have an explicit dependency on 
   groovy-eclipse-batch -->
  <dependency>
   <groupId>org.codehaus.groovy</groupId>
   <artifactId>groovy-eclipse-batch</artifactId>
   <version>2.1.8-01</version>
   <!-- or choose a different compiler version -->
   <!-- <version>1.8.6-01</version> -->
   <!-- <version>1.7.10-06</version> -->
  </dependency>
 </dependencies>
</plugin>
<plugin>
 <groupId>org.codehaus.mojo</groupId>
 <artifactId>build-helper-maven-plugin</artifactId>
 <version>1.5</version>
 <executions>
  <execution>
   <id>add-source</id>
   <phase>generate-sources</phase>
   <goals>
    <goal>add-source</goal>
   </goals>
   <configuration>
    <sources>
     <source>src/main/groovy</source>
    </sources>
   </configuration>
  </execution>
  <execution>
   <id>add-test-source</id>
   <phase>generate-test-sources</phase>
   <goals>
    <goal>add-test-source</goal>
   </goals>
   <configuration>
    <sources>
     <source>src/test/groovy</source>
    </sources>
   </configuration>
  </execution>
 </executions>
</plugin>
build-helper-maven-plugin plugin will add src/main/groovy as a compilation source folder, and compiler plugin with groovy-eclipse-compiler configuration will compile groovy into java classes.
If you are using Eclispe IDE or Spring ToolSuite, do not forget install Grails/Groovy plugin from Spring IO, or download a copy of Grails/Groovy Suite for groovy development.

Sample codes

The samples codes is hosted on my github.com account.