Friday, November 20, 2015

Configuraion for Spring transaction management

Trying to understand the declarative transaction management of Spring. The following is from the document of Spring Release 3.2.1.
<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="
     http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd">

 <!-- this is the service object that we want to make transactional -->
 <bean id="fooService" class="x.y.service.DefaultFooService" />
 <!-- the transactional advice (what 'happens'; see the <aop:advisor/> bean 
  below) -->

 <tx:advice id="txAdvice" transaction-manager="txManager">
  <!-- the transactional semantics... -->
  <tx:attributes>
   <!-- all methods starting with 'get' are read-only -->
   <tx:method name="get*" read-only="true" />
   <!-- other methods use the default transaction settings (see below) -->
   <tx:method name="*" />
  </tx:attributes>
 </tx:advice>

 <!-- ensure that the above transactional advice runs for any execution of 
  an operation defined by the FooService interface -->
 <aop:config>
  <aop:pointcut id="fooServiceOperation"
   expression="execution(* x.y.service.FooService.*(..))" />
   <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation" />
 </aop:config>

 <!-- don't forget the DataSource -->
 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy- method="close">
  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
  <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis" />
  <property name="username" value="scott" />
  <property name="password" value="tiger" />
 </bean>

 <!-- similarly, don't forget the PlatformTransactionManager -->
 <bean id="txManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <property name="dataSource" ref="dataSource" />
 </bean>
 <!-- other <bean/> definitions here -->
</beans>

The central part is the advisor in the <aop:config> section. It takes two arguments "advice-ref" and "pointcut-ref". Roughly speaking, an advisor advices "someone" to do "something". Here pointcut-ref is that "someone". And advice-ref is that "something". Basically what it says is to apply the advices given in "advice-ref" to those classes and/or methods defined in "pointcut-ref". So actually it is a generic thing of AOP. It is not just for transaction management.

A common requirement is to make an entire service layer transactional.The best way to do this is simply to change the pointcut expression to match any operation in your service layer. For example:

<aop:config>
 <aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))" />
 <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods" />
</aop:config>
In this example it is assumed that all your service interfaces are defined in the x.y.service package.

Spring's declarative transaction support is enabled via AOP proxies. The AOP proxy uses a TransactionInterceptor. In the Spring Framework, an AOP proxy will be a JDK dynamic proxy or a CGLIB proxy. So underneath, the implementation uses interceptor. You can actually configure org.springframework.transaction.interceptor.TransactionInterceptor directly in XML for transaction management without using AOP.

AOP expression

Below is from Spring document (see the Reference).

Spring AOP users are likely to use the execution pointcut designator the most often. The format of an execution expression is:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
throws-pattern?)
All parts except the returning type pattern (ret-type-pattern in the snippet above), name pattern, and parameters pattern are optional. The returning type pattern determines what the return type of the method must be in order for a join point to be matched. Most frequently you will use * as the returning type pattern, which matches any return type. A fully-qualified type name will match only when the method returns the given type. The name pattern matches the method name. You can use the * wildcard as all or part of a name pattern. The parameters pattern is slightly more complex: () matches a method that takes no parameters, whereas (..) matches any number of parameters (zero or more). The pattern (*) matches a method taking one parameter of any type, (*,String) matches a method taking two parameters, the first can be of any type, the second must be a String. Consult the Language Semantics section of the AspectJ Programming Guide for more information.

Some examples of common pointcut expressions are given below.

  • the execution of any public method:
    execution(public * *(..))
  • the execution of any method with a name beginning with "set":
    execution(* set*(..))
  • the execution of any method defined by the AccountService interface:
    execution(* com.xyz.service.AccountService.*(..))
  • the execution of any method defined in the service package:
    execution(* com.xyz.service.*.*(..))
  • the execution of any method defined in the service package or a sub-package:
    execution(* com.xyz.service..*.*(..))


Rollback Configuration

Spring by default marks a transaction for rollback when a runtime exception is thrown. However you can customize the behavior to let the rollback happen for checked exceptions. The following is an example.

<tx:advice id="txAdvice" transaction-manager="txManager">
 <tx:attributes>
  <tx:method name="get*" read-only="true" rollback-for="CheckedException1, CheckedException2" />
  <tx:method name="*" />
 </tx:attributes>
</tx:advice>
Note that you use comma-delimited expression in the value for rollback-for. There is another attribute no-rollback-for to mark exceptions that should not trigger rollback.

Using transaction annotation

You can annotate the class with @Transactional. The following is from Spring doc.


// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {
 Foo getFoo(String fooName);
 Foo getFoo(String fooName, String barName);
 void insertFoo(Foo foo);
 void updateFoo(Foo foo);
}

<!-- from the file 'context.xml' -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="
     http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/tx
     http://www.springframework.org/schema/tx/spring-tx.xsd
     http://www.springframework.org/schema/aop
     http://www.springframework.org/schema/aop/spring-aop.xsd">
     
 <!-- this is the service object that we want to make transactional -->
 <bean id="fooService" class="x.y.service.DefaultFooService" />
 
 <!-- enable the configuration of transactional behavior based on annotations -->
 <tx:annotation-driven transaction-manager="txManager" />
 
 <!-- a PlatformTransactionManager is still required -->
 <bean id="txManager"
  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <!-- (this dependency is defined somewhere else) -->
  <property name="dataSource" ref="dataSource" />
 </bean>
 <!-- other <bean/> definitions here -->
</beans>

Comparing this annotation method against the AOP XML method, you may ask what are the things corresponding to "someone" and "something" of the advisor? The annotation seems to solve the problems altogether in a completely different way. The annotation location indicates the "someone" part. And the annotation name itself indicates that transaction management needs to be carried out, which is "something".

References

  1. http://docs.spring.io/spring/docs/3.2.1.RELEASE/spring-framework-reference/pdf/spring-framework-reference.pdf

Wednesday, November 11, 2015

Notes on using the Spring annotation

Assuming that Spring 3.2.1.Release or above is used in the following notes.
  1. You can use <context:annotation-config/>. It will look for annotations on the properties and methods of a bean, but not the bean class itself.
  2. You use <context:component-scan base-package="org.example" /> to automatically detect classes and register bean definitions. The use of this implicitly enables the functionality of <context:annotation-config>. Also be aware of the following.
    • When <context:component-scan/> is used, the java classes involved need to be annotated with @Component, @Service, etc. Otherwise they would not be recognized.
    • The annotated classes are put into the Spring IoC container. You need to get a bean from this container to get the beans with all the injected properties. Outside this container, the instances of those classes are just plain instances. The annotations have no effect on them.
    • An interesting case is about the servlet. Below is an example.
              @Component
              public class myServlet extends HttpServlet {
                 private @Autowired FooService fooService;
              }
              
      Even though this class is annotated with @Component, the fooService will still be null when this servlet is called in the web application. I think this is because the servlet instance used here is from the Web container. It is NOT from the Spring IoC container. The Spring IoC container may have a copy of this class with fooService injected. But it is not used. So how to still use annotation in a servlet? First of all, the @Component annotation can be removed on servlet. It is not needed since the servlets follow the standard Web container life cycle. The servlet that gets called is from the Web container instead of Spring IoC container. Inside the servlet, you can make annotation work by overriding the init() method as in the following:
         public void init(ServletConfig config) throws ServletException {
            super.init(config);
            SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,config.getServletContext());
        }
      

      Or you can just declare fooService as a plain non-annotated field:

            private FooService fooService;
          
      Then in the code inside the servlet, you can get this object from Spring IoC container as below:
            ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
      
            FooService service = (FooService)applicationContext.getBean("fooService");
        
  3. Annotation injection is performed before XML injection. So the latter configuration will override the former for properties wired through both approaches. You can inject some properties using annotations and other properties using XML. For example, you can have the following:
      public class Foo{
        private @Autowired  Bar bar;
        private DataSource dataSource;
    
      }
    
    
    You can use XML to inject dataSource.
  4. You can use @Configuration class so no XML configuration file is needed. But a cost is that you have to create new java classes with the @Configuration annotation.
  5. To use a @Configuration class, you use AnnotationConfigApplicationContext to include the class. Say that AppConfig is annotated with @Configuration, you can use the following when the application is started.
         public static void main(String[] args){
             ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
             MyService myService = ctx.getBean(MyService.class);
             myService.doStuff();
         }
    
    AnnotationConfigApplicationContext actually is more versatile than that. It can also be used to scan annotated classes as this: ctx.scan("com.sample"). For more information, see Spring documentation.

    In the Web application, you use AnnotationConfigWebApplicationContext. The web.xml file can be configured as below:

      <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext instead of
            the default XmlWebApplicationContext -->
     <context-param>
         <param-name>contextClass</param-name>
         <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
     </context-param>
     
     <!-- Configuration location must consist of one or more comma- or space-delimited fully-qualified @Configuration classes. 
     Fully-qualified packages may also be specified for component-scanning -->
     <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.myapp.AppConfig</param-value>
     </context-param>
     
     <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
     </listener>
    
    If you look at the above code snippet, you may wonder how the parameter name "contextClass" is used. It is declared but not referenced anywhere. I think the secret lies in the comment above that parameter. This parameter is implicitly used by the Spring ContextLoaderListener class. As that comment says, ContextLoaderListener uses XmlWebApplicationContext as the contextClass by default. Now we are not using the Spring XML bean definition files, so we change this to AnnotationConfigWebApplicationContext!
  6. There are debates about which way is better, annotation or XML? Both actually have their own pros and cons. Spring's @Configuration class support does not aim to be a 100% complete replacement for Spring XML. You can choose to use "XML-centric" way or java "Annotation-centric" way.

References

  • https://www.mkyong.com/spring3/spring-3-and-jsr-330-inject-and-named-example
  • http://stackoverflow.com/questions/18387993/spring-jsf-integration-how-to-inject-a-spring-component-service-in-jsf-managed
  • http://www.beyondjava.net/blog/integrate-jsf-2-spring-3-nicely
  • Friday, October 23, 2015

    Maven phases and goals

    Maven has a life cycle in its build process. The key concept is "Phase". Do not be confused by another concept "goal". There are different but related. For example, "package" is a phase. It is not a goal.

    Maven can support a number of different life cycles. But the mostly used one is the default Maven life cycle.

    The default life cycle has the following phases (For a more detailed description, see reference[1]). And they are stepped through in order until it reaches at the phase that is specified in the Maven command.

    1. process-resources
    2. compile
    3. process-classes
    4. process-test-resources
    5. test-compile
    6. test
    7. prepare-package
    8. package
    9. install

    Maven delegates the work to Maven plugins.

    Plugin goals can be attached to a life cycle phase. When Maven moves through the phases, it executes the goals attached to each phase. Each phase can have zero or more goals bound to it.

    A phase may mean different things to different projects. For example, for the package phase, a JAR project will produce a JAR file, while a web application will produce a WAR file.

    If no plugin is specified in the pom file, Maven seems to use its default plugins. See reference[2].

    You can run Maven by specifying a phase as in "mvn install". You can also run Maven by specifying the actual goals as in "mvn resources:resources compiler:compile".

    References

    [1] https://maven.apache.org/ref/3.3.3/maven-core/lifecycles.html
    [2] https://maven.apache.org/ref/3.3.3/maven-core/default-bindings.html

    Wednesday, October 21, 2015

    Spring session scoped bean and HTTP session attribute

    A simple JSF application app has a jsf file a.faces and a jsp file b.jsp. The jsp file has the following:
    <%
        HttpSession sess = rquest.getSession();
        FooBean foo = (FooBean)sess.getAttribute("fooBean");
        foo.someMethod();
    %>
    
    And the jsf file has the following:
    <ice:form onsubmit="#{fooBean.doAction}">
    
    Here the tag ice is used because it is using icefaces. The name fooBean is for a Spring bean defined in applicationContext.xml as below:
    <bean id="fooBean" class="FooBean" scope="session">
       <constructor-arg><ref bean="x" /> <constructor-arg>
       <constructor-arg><ref bean="y" /> <constructor-arg>
    </bean>
    
    <bean id="x" class="X"/>
    <bean id="y" class="Y" scope="session"/>
    
    And in the faces-config.xml, there is the following:
    <faces-config>
     <application>
      <variable-resolver>
       org.springframework.web.jsf.DelegatingVariableResolver
      </variable-resolver>
     </application>
    </faces-config>
    

    The application is accessed by app/a.faces. And then you can access the jsp file app/b.jsp without any problem. But if you access the application using app/b.jsp as the first step, it will give NullPointerException when calling foo.someMethod() because foo is null.

    The tricky thing here is how the "fooBean" is put into the session as an attribute. The answer is in the Spring DelegatingVariableResolver class and DefaultListableBeanFactory class.

    When user types app/a.faces, the resolver sees #{fooBean.doAction}. It checks the applicationContext.xml and finds the bean definition. So it creates the bean x, y, and then fooBean. The bean x is a singleton. It is already created at the application startup. So the resolver only needs to get the cached instance of x. But the bean y has a scope of session. So the resolver calls DefaultListableBeanFactory and creates a brand new instance of y. And it puts it as an attribute into the HTTP Session object. After both x and y are created, a new fooBean is created and put into the session as an attribute since its scope is also session. So these session beans are created lazily when there are referenced.

    Now if you access app/b.jsp without firstly accessing app/a.faces, the Spring resolver is not invoked. The session object has no attribute named "fooBean". And you will get a null object for this attribute.

    The following is the method stacks showing the Spring bean is resolved and set into the HTTP session as an attribute.

    owns: InterceptingServletSession  (id=15648) 
     MyAttributeListener.attributeAdded(HttpSessionBindingEvent) line: 13 
     EventsManager.notifySessionAttributeChange(HttpSession, String, Object, Object) line: 302 
     MemorySessionContext(SessionContext).notifySessionAttributeChange(HttpSession, String, Object, Object) line: 1479 
     MemorySessionData(SessionData).setAttribute(String, Object, boolean) line: 1121 
     MemorySessionData(SessionData).setAttribute(String, Object) line: 959 
     InterceptingServletSession(ProxyHttpSession).setAttribute(String, Object) line: 107 
     ServletSessionAttributeMap.setAttribute(String, Object) line: 20 
     ServletSessionAttributeMap(AbstractAttributeMap).put(Object, Object) line: 157 
     FacesRequestAttributes.setAttribute(String, Object, int) line: 108 
     SessionScope(AbstractRequestAttributesScope).get(String, ObjectFactory) line: 44 
     SessionScope.get(String, ObjectFactory) line: 90 
     DefaultListableBeanFactory(AbstractBeanFactory).doGetBean(String, Class, Object[], boolean) line: 298 
     DefaultListableBeanFactory(AbstractBeanFactory).getBean(String, Class, Object[]) line: 185 
     DefaultListableBeanFactory(AbstractBeanFactory).getBean(String) line: 164 
     XmlWebApplicationContext(AbstractApplicationContext).getBean(String) line: 881 
     DelegatingVariableResolver.resolveSpringBean(FacesContext, String) line: 136 
     DelegatingVariableResolver.resolveVariable(FacesContext, String) line: 109 
     NamedValue.evaluate(ExpressionInfo) line: 145 
     ComplexValue.evaluate(ExpressionInfo) line: 166 
     ExpressionEvaluatorImpl.evaluate(ExpressionInfo) line: 263 
     ValueBindingImpl.getValue(FacesContext, String) line: 160 
     ValueBindingImpl.getValue(FacesContext) line: 143 
     HtmlForm(HtmlForm).getOnsubmit() line: 501 
    

    Monday, September 28, 2015

    Lunar Eclipse

    There was the super moon lunar eclipse last night. But it was raining and very cloudy in Pittsburgh. So we could only see the dark sky.

    Friday, January 30, 2015

    Tomcat7 Spring Annotation

    The following is the list of the related files and the related contents.

    pom.xml

                    <properties>
       <org.springframework.version>3.1.4.RELEASE</org.springframework.version>
             </properties>
    
                    <!--   SpringFramework  -->
                    <dependency>
       <groupId>org.springframework.security</groupId>
       <artifactId>spring-security-core</artifactId>
       <version>${org.springframework.version}</version>
      </dependency>
    
      <dependency>
       <groupId>org.springframework.security</groupId>
       <artifactId>spring-security-web</artifactId>
       <version>${org.springframework.version}</version>
      </dependency>
      <dependency>
       <groupId>org.springframework.security</groupId>
       <artifactId>spring-security-config</artifactId>
       <version>${org.springframework.version}</version>
      </dependency>
    
      <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-web</artifactId>
       <version>${org.springframework.version}</version>
      </dependency>
    
      <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-core</artifactId>
       <version>${org.springframework.version}</version>
      </dependency>
      <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-beans</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-context-support</artifactId>
       <version>${org.springframework.version}</version>
      </dependency>
    
      <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-expression</artifactId>
       <version>${org.springframework.version}</version>
      </dependency>
      
      
      <!-- JSR-330 and CDI -->
      <dependency>
       <groupId>javax.inject</groupId>
       <artifactId>javax.inject</artifactId>
       <version>1</version>
      </dependency>
      
      <dependency>
       <groupId>javax.enterprise</groupId>
       <artifactId>cdi-api</artifactId>
       <version>1.2</version>
      </dependency>
    

    Note that the dependency cdi-api is included to test the use of the annotations from CDI. The tests will show that it does not work. The annotation @javax.enterprise.context.SessionScoped is from CDI. But the annotations @Named and @Inject are from JSR330.

    Note that another name of CDI is JSR299. Though the number 299 is less than 330, JSR299 is actually on top of JSR330.

    web.xml

     <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/spring-security.xml,
                      /WEB-INF/application-context.xml
                    </param-value>
     </context-param>
    
     <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
     </listener>
    

    Note that two xml files are included. The file spring-security.xml has mostly the security URL configurations. It also has some bean declarations. The file application-context.xml will scan the beans with annotations. It also has some bean declarations.

    faces-config.xml

           <faces-config 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-facesconfig_2_1.xsd"
     version="2.1">
     
     <application>
      <el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
     </application>
    

    spring-security.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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.springframework.org/schema/beans 
              http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
              http://www.springframework.org/schema/security 
              http://www.springframework.org/schema/security/spring-security-3.1.xsd">
    
     <authentication-manager alias="authenticationManager">
      <authentication-provider user-service-ref='omsUserDetailsService' />
     </authentication-manager>
    
     <beans:bean id="omsUserDetailsService"
      class="com.lakexy.oms.security.OmsUserDetailService">
      <beans:property name="userDao" ref="userDao" />
     </beans:bean>
    
     <beans:bean id="userDao" class="com.lakexy.oms.dao.security.UserDaoImpl">
      <beans:property name="dataSource" ref="omsDataSource" />
     </beans:bean>
    
     <http auto-config="true">
      <intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY" />
      <intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY" />
      <logout logout-success-url="/index.jsp" />
    
     </http>
    
    </beans:beans>
    

    application-context.xml

    <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"
     xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.1.xsd">
    
     <context:component-scan base-package="com.lakexy" />
     
     <bean id="omsDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
      <property name="jndiName" value="java:comp/env/jdbc/inventory" />
     </bean>
    
     
     <!-- *********************************************************** -->
     <!--            T R A N S A C T I O N  S E T U P                 -->
     <!-- *********************************************************** -->
    
    
     <!--
      Transaction Interceptor set up to do PROPAGATION_REQUIRED on all
      methods
     -->
     <!--
      <bean id="omsTransactionManager"
      class="org.springframework.transaction.jta.JtaTransactionManager">
      </bean>
     -->
    
     <bean id="omsTransactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource">
       <ref local="omsDataSource" />
      </property>
     </bean>
    
     <bean id="matchAllWithPropReq"
      class="org.springframework.transaction.interceptor.MatchAlwaysTransactionAttributeSource">
      <property name="transactionAttribute">
       <value>PROPAGATION_REQUIRED,-OmsCheckedException</value>
      </property>
     </bean>
     <bean id="matchAllTxInterceptor"
      class="org.springframework.transaction.interceptor.TransactionInterceptor">
      <property name="transactionManager">
       <ref bean="omsTransactionManager" />
      </property>
      <property name="transactionAttributeSource">
       <ref bean="matchAllWithPropReq" />
      </property>
     </bean>
     <!--
      One BeanNameAutoProxyCreator handles all beans where we want all
      methods to use PROPAGATION_REQUIRED
     -->
     <bean id="autoProxyCreator"
      class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
      <property name="interceptorNames">
       <list>
        <idref bean="matchAllTxInterceptor" />
       </list>
      </property>
      <property name="beanNames">
       <list>
        <idref bean="customerBo" />
        <idref bean="locationBo" />
        <idref bean="orderBo" />
        <idref bean="omsUserDetailsService" />
        <idref bean="shipmentBo" />
        <idref bean="invoiceBo" />
       </list>
      </property>
     </bean>
    
    </beans>
    

    Notes:

    1. application-context.xml mixed the component-scan and the explicit bean declaration for those beans that are used in transaction management.
    2. The base-package is "com.lakexy" in component-scan. But that does not mean that any classes in the package com.lakexy will be registered as a bean in the spring container. A class will be registered in the spring container only when it has the annotation such as @Named.

    Lastly, the actual java classes with annotations.

    Example:

    import javax.inject.Inject;
    import javax.inject.Named;
    import org.springframework.context.annotation.Scope;
    
    @Named
    // @SessionScoped
    @Scope("session")
    // @RequestScoped
    public class CustomerBean {
    
     private String customerName;
     private List<Customer> customers;
     private CustomerTableData customersTableData;
     @Inject
     private ICustomer customerBo;
    ...
    }
    

    Notes

    1. @Named is from standard java annotation. But nevertheless, spring recognize this annotation.
    2. By default, the bean scope in Spring is singleton. So if @Named is the only annotation, this CustomerBean will be a singleton, which essentially make it an Application scoped bean.
    3. I tested the use of different scope annotations. Confusingly, there are several variations of session scope.The @SessionScoped can mean one of the followings:
      javax.faces.bean.SessionScoped
      javax.enterprise.context.SessionScoped;
      
      But nevertheless, the tests show that this annotation does not have effects. The same CustomerBean instance is used even if you use the application in different browsers. So it acts like a singleton just as when only @Named is used. But the spring annotaion @Scope("session") as in the above code works. The tests do show that it acts as a session bean. So it looks like that Spring supports JSR330 but not CDI. The annotations @Named and @Inject are from JSR330. The annotation javax.enterprise.context.SessionScoped is from CDI. I did some search on internet and did find articles saying that Spring3 supports JSR330 but not JSR299. And there is a way to use JSR299 in Spring3.
    4. When @Inject is used, no need to write the getter and setter for the annotated field.
    5. Injection is type-based. So in the example above, it will search for a bean of the type ICustomer. The name of the bean does not necessarily have to be "customerBo".

    References

    1. http://www.mkyong.com/jsf2/jsf-2-0-spring-integration-example
    2. https://www.mkyong.com/spring3/spring-3-and-jsr-330-inject-and-named-example
    3. http://stackoverflow.com/questions/18387993/spring-jsf-integration-how-to-inject-a-spring-component-service-in-jsf-managed
    4. http://www.beyondjava.net/blog/integrate-jsf-2-spring-3-nicely

    Thursday, January 15, 2015

    Spring Security Filter Name and Bean Name

    Name Matching

    I read some code of an application that uses Spring security library. It has a class to implement the standard javax.servlet.Filter class. And this filter is declared as a bean in the application context xml files for Spring. The bean name is just assumed to be "xyz" here. But this filter is NOT declared in the web.xml file. Normally, in order for a filter class to be invoked, it has to be declared in the web.xml file. But in this application, the web.xml file only declares a filter with the name "xyz" for org.springframework.web.filter.DelegatingFilterProxy. The surprising thing is that the bean "xyz" in the application context IS invoked. After doing some searching, I found the following document that explains the puzzle.

    When using servlet filters, you obviously need to declare them in your web.xml, or they will be ignored by the servlet container. In Spring Security, the filter classes are also Spring beans defined in the application context and thus able to take advantage of Spring's rich dependency-injection facilities and lifecycle interfaces. Spring's DelegatingFilterProxy provides the link between web.xml and the application context.

    When using DelegatingFilterProxy, you will see something like this in the web.xml file:

      <filter>
        <filter-name>myFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
      </filter>
    
      <filter-mapping>
        <filter-name>myFilter</filter-name>
        <url-pattern>/*</url-pattern>
      </filter-mapping>
    

    Notice that the filter is actually a DelegatingFilterProxy, and not the class that will actually implement the logic of the filter. What DelegatingFilterProxy does is delegate the Filter's methods through to a bean which is obtained from the Spring application context. This enables the bean to benefit from the Spring web application context lifecycle support and configuration flexibility. The bean must implement javax.servlet.Filter and it must have the same name as that in the filter-name element. Read the Javadoc for DelegatingFilterProxy for more information

    References

    1. http://docs.spring.io/spring-security/site/docs/3.0.x/reference/security-filter-chain.html

    Friday, January 9, 2015

    Use JMX to change the log level dynamically

    Use JMX to Change the Log level dynamically

    In this note, we will create a program that can change the log level dynamically on the local or remote server. We will use Spring JMX exporter. Log4j is used. The applicaiton server is Weblogic 10.3.2. On the remote side, the application is deployed to a cluster of two weblogic managed servers weblogic01 and weblogic02. Note that on later versions of Weblogic such as version 11, the MBean server configurations may be different.

    There are several files needed for this.

    What are needed on the application side

    1. In the application, create the following classes:

    (1) IAppLogUtils.java

    package com.yourcompany.app.server.utils;
    
    public interface IAppLogUtils {
     public void updateAllLogLevels(String s);
    }
    
    (2) AppLogUtils.java
    package com.yourcompany.app.server.utils;
    
    import java.util.Enumeration;
    
    import org.apache.log4j.Level;
    import org.apache.log4j.LogManager;
    import org.apache.log4j.Logger;
    
    public class AppLogUtils implements IAppLogUtils {
     public void updateAllLogLevels(String s) {
      Enumeration enumeration = LogManager.getCurrentLoggers();
      do {
       if (!enumeration.hasMoreElements())
        break;
       Logger logger = (Logger) enumeration.nextElement();
       logger.setLevel(Level.toLevel(s));
      } while (true);
     }
    }
    
    (3) In the application context xml file, add the following to use the Spring JMX exporter.
    <bean id="jmxServerRuntime" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="java:comp/env/jmx/runtime"/>
    </bean>
    
    <bean id="appLogUtils" class="com.yourcompany.app.server.utils.AppLogUtils" />
      </bean>
     
     <bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
      <property name="beans">
       <map>
        <entry key="APP:name=appLogUtils" value-ref="appLogUtils" /> 
       </map>
      </property>
       <property name="registrationBehaviorName" value="REGISTRATION_IGNORE_EXISTING"/>
      <property name="server" ref="jmxServerRuntime"/>
     </bean>
    
    Two important notes here.

    (a) A JVM can have multiple MBean servers. We will register our JMX bean on the weblogic runtime mbean server. Later on when we create the JMX client program to change the log level, we will connect to this mbean server. A test shows that if we do not specify the server property as in the above, Spring MBeanExporter will export the MBean to the JVM platform mbean server. On local machine, the jconsole program will detect this JVM platform mbean server. It does not need to have the username/password to access it.

    (b) The value for the property "registrationBehaviorName" of the MBeanExporter is set. The default value is REGISTRATION_FAIL_ON_EXISTING, which will give error if Spring registers the Mbean with the same name twice. The error message is like this: "javax.management.InstanceAlreadyExistsException".

    What are needed on the client side to invoke the JMX bean

    It is relatively easy if the weblogic server is running locally. If the servers are remote, the program is still similar but a little bit more complex. The following program has code for both cases.

    In the program, we assume that the two managed weblogic servers have the following host name and port number:

    host1  14110
    host2  14110
    

    Note that the port numbers are the same because they are in the same cluster of weblogic managed servers. The weblogic admin server has a different port number. You can also connect to the admin server to get its JMX information. You need to use the username/password to connect to the admin server. Interestingly, you need to use the same username/password to connect to the managed weblogic servers for the JMX connection.

    import java.io.IOException;
    import java.util.Hashtable;
    import java.util.Set;
    
    import javax.management.MBeanServerConnection;
    import javax.management.ObjectName;
    import javax.management.remote.JMXConnector;
    import javax.management.remote.JMXConnectorFactory;
    import javax.management.remote.JMXServiceURL;
    
    import com.bea.core.repackaged.springframework.util.Assert;
    
    public class WeblogicJMXClient {
    
            // this method changes the log level to "DEBUG" on the locally running weblogic server.
     public void testLocT3() throws Exception {
      JMXConnector jmxCon = null;
    
      try {
       JMXServiceURL serviceUrl = new JMXServiceURL("t3", "localhost",
         7001, "/jndi/weblogic.management.mbeanservers.runtime");
    
       System.out.println("Connecting to: " + serviceUrl);
       Hashtable env = new Hashtable();
       env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
         "weblogic.management.remote");
       env.put(javax.naming.Context.SECURITY_PRINCIPAL, "username");
       env.put(javax.naming.Context.SECURITY_CREDENTIALS, "password");
    
       jmxCon = JMXConnectorFactory.newJMXConnector(serviceUrl, env);
       jmxCon.connect();
       MBeanServerConnection con = jmxCon.getMBeanServerConnection();
    
       Set<ObjectName> mbeans = con.queryNames(new ObjectName(
         "APP:name=appLogUtils"), null);
       ObjectName logService = (ObjectName) mbeans.iterator().next();
    
       Object result = con.invoke(logService, "updateAllLogLevels",
         new Object[] { "DEBUG" }, new String[] { String.class
           .getName() });
      } finally {
       if (jmxCon != null)
        jmxCon.close();
      }
     }
    
            
            /**
             * This method changes the log level to the specified value "INFO" or "DEBUG" on the remote 
             * weblogic server cluster
             */
     public void changDevLog(String logLevel) {
      Assert.isTrue("DEBUG".equals(logLevel) || "INFO".equals("logLevel"));
      JMXConnector jmxCon = null;
      // change on weblogic01
      try {
       jmxCon = getJMXConnector("t3", "host1",
         14110, "username", "password");
       changeLogLevel(jmxCon, logLevel);
      } catch (Exception e) {
       e.printStackTrace();
      } finally {
       if (jmxCon != null) {
        try {
         jmxCon.close();
        } catch (Exception ex) {
         ex.printStackTrace();
        }
       }
      }
      // change on weblogic02
      try {
       jmxCon = getJMXConnector("t3", "host2",
         14110, "username", "password");
       changeLogLevel(jmxCon, logLevel);
      } catch (Exception e) {
       e.printStackTrace();
      } finally {
       if (jmxCon != null) {
        try {
         jmxCon.close();
        } catch (Exception ex) {
         ex.printStackTrace();
        }
       }
      }
     }
    
    
     private JMXConnector getJMXConnector(String protocol, String host,
       int port, String username, String password) throws IOException {
      JMXConnector jmxCon = null;
      JMXServiceURL serviceUrl = new JMXServiceURL(protocol, host, port,
        "/jndi/weblogic.management.mbeanservers.runtime");
      System.out.println("Connecting to: " + serviceUrl);
      Hashtable env = new Hashtable();
      env.put(JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES,
        "weblogic.management.remote");
      env.put(javax.naming.Context.SECURITY_PRINCIPAL, username);
      env.put(javax.naming.Context.SECURITY_CREDENTIALS, password);
    
      jmxCon = JMXConnectorFactory.newJMXConnector(serviceUrl, env);
      return jmxCon;
     }
    
     private void changeLogLevel(JMXConnector jmxCon, String level)
       throws Exception {
      jmxCon.connect();
      MBeanServerConnection con = jmxCon.getMBeanServerConnection();
      Set<ObjectName> mbeans = con.queryNames(new ObjectName(
        "APP:name=appLogUtils"), null);
      ObjectName logService = (ObjectName) mbeans.iterator().next();
      Object result = con
        .invoke(logService, "updateAllLogLevels",
          new Object[] { level }, new String[] { String.class
            .getName() });
     }
    
     public static void main(String[] args) throws Exception {
      WeblogicJMXClient c = new WeblogicJMXClient();
      //c.testLocT3();
             c.changDevLog("DEBUG");
      
     }
    }
    
    

    MBean Server on Weblogic

    The following is about Weblogic 10.

    At the core of any JMX agent is the MBean server, which acts as a container for MBeans.

    In Weblogic, the JVM for an Administration Server maintains three MBean servers provided by BEA and optionally maintains the platform MBean server, which is provided by the JDK itself. The JVM for a Managed Server maintains only one BEA MBean server and the optional platform MBean server.

    The three MBean servers provided by BEA are:

    1. Domain Runtime MBean Server. Only the Administration Server hosts an instance of this MBean server. Its INDI name is "weblogic.management.mbeanservers.domainruntime".
    2. Runtime MBean Server. Each server in the domain hosts an instance of this MBean server. Its JNDI name is "weblogic.management.mbeanservers.runtime".
    3. Edit MBean Server. Only the Administration Server hosts an instance of this MBean server. Its JNDI name is "weblogic.management.mbeanservers.edit".

    The JVM's platform MBean server is provided by the JDK that contain monitoring information for the JVM itself. You can register custom MBeans in this MBean server, but BEA recommends that you register them in its Runtime MBean Server.

    You can also configure the WebLogic Server Runtime MBean Server to be the platform MBean server, in which case the platform MBean server provides access to JVM MBeans, Runtime MBeans, and active configuration MBeans that are on a single server instance.

    Register an MBean on Weblogic

    Local clients can access a WebLogic Server instance’s Runtime MBean Server through the JNDI tree instead of constructing a JMXServiceURL object. Only the Runtime MBean Server registers itself in the JNDI tree.

    If the classes for the JMX client are located at the top level of an enterprise application (that is, if they are deployed from the application’s APP-INF directory), then the JNDI name for the Runtime MBean Server is: java:comp/jmx/runtime

    If the classes for the JMX client are located in a Java EE module, such as an EJB or Web application, then the JNDI name for the Runtime MBeanServer is: java:comp/env/jmx/runtime

    In our case for the bean AppLogUtils, we use the JNDI name "java:comp/env/jmx/runtime". This bean AppLogUtils is a spring bean and is used in a web module deployed on the Weblogic server. So according to the above stated, this bean is registered at the Weblogic runtime MBean server. And in our subsequent code we do see that the JMX client connects to the runtime MBean server to manage this bean because it uses the JNDI name "/jndi/weblogic.management.mbeanservers.runtime".

    One thing that may be misleading is the JNDI name "java:comp/env/jmx/runtime". This name looks like a java standard since it does not contain any thing about Weblogic. But it may just be a proprietary name used by Weblogic for the java platform MBean server. As stated before, all the three Weblogic MBean servers ( Domain Runtime MBean server, Runtime MBean server, Edit MBean server ) have their JNDI name and the client can connect to them programmatically using these JNDI names remotely. But there does not seem to be a JNDI name for the platform MBean server for the remote client to connect to. The JNDI name "java:comp/env/jmx/runtime" is only used locally. The following is from Oracle document about how to access the JVM platform MBean server remotely:
    "Remote access to the platform MBean server can be secured only by standard JDK 1.5 security features (see http://java.sun.com/j2se/1.5.0/docs/guide/management/agent.html#remote). If you have configured the WebLogic Server Runtime MBean Server to be the platform MBean server, enabling remote access to the platform MBean server creates an access path to WebLogic Server MBeans that is not secured through the WebLogic Server security framework."

    JVM Platform MBean Server

    Someone on the internet says the following: "Note that the Platform MBean Server is always present and is created by the JVM during startup." But I am not sure about the meaning of "always present" here. It seems to me that by default, JVM will not create the MBean server during the startup. I did a simple test by using JDK1.7. I created a simple class Temp1.java that just calls the Thread.sleep method so it will not stop immediately after being executed. Then if I simply run the class using the command "java Temp1", jconsole will fail to connect to it. Only if I use the command "java -Dcom.sun.management.jmxremote Temp1", will the jconsole be able to connect to it. After doing more searching, I found the following from java7 doc:

    In the Java SE 6 platform, it is no longer necessary to set this system property. Any application that is started on the Java SE 6 platform will support the Attach API, and so will automatically be made available for local monitoring and management when needed.

    In the above, the "system property" refers to "com.sun.management.jmxremote". For remote access, the document is the following:

    To enable monitoring and management from remote systems, you must set the following system property when you start the Java VM.
    com.sun.management.jmxremote.port=portNum

    In the property above, portNum is the port number through which you want to enable JMX RMI connections. Be sure to specify an unused port number. In addition to publishing an RMI connector for local access, setting this property publishes an additional RMI connector in a private read-only registry at the specified port using a well known name, "jmxrmi".

    The Attach API mentioned above is worth studying. Ref[4] has some example code about the Attach API. The main ideas are the following.

    1. The Attach API is provided in the tools.jar file from JDK. The main class is VirtualMachine.
    2. The VirtualMachine class represents a specific Java virtual machine(JVM) instance. You connect to a JVM by providing the VirtualMachine class with the process id, and then you load a management agent to do your customized behavior.
    3. After you load the agent with loadAgent, you should call the detach method.
    4. A JMX agent exists in the managment-agent.jar file that comes with the JDK found in the same directory as tools.jar. The sample code is the following:
      VirtualMachine vm = VirtualMachine.attach(args[0]);
          String connectorAddr = vm.getAgentProperties().getProperty(
            "com.sun.management.jmxremote.localConnectorAddress");
          if (connectorAddr == null) {
            String agent = vm.getSystemProperties().getProperty(
              "java.home")+File.separator+"lib"+File.separator+
              "management-agent.jar";
            vm.loadAgent(agent);
            connectorAddr = vm.getAgentProperties().getProperty(
              "com.sun.management.jmxremote.localConnectorAddress");
          }
      
          JMXServiceURL serviceURL = new JMXServiceURL(connectorAddr);
          JMXConnector connector = JMXConnectorFactory.connect(serviceURL); 
          MBeanServerConnection mbsc = connector.getMBeanServerConnection(); 
          ObjectName objName = new ObjectName(
            ManagementFactory.THREAD_MXBEAN_NAME);
          Set mbeans = mbsc.queryNames(objName, null);
          for (ObjectName name: mbeans) {
            ThreadMXBean threadBean;
            threadBean = ManagementFactory.newPlatformMXBeanProxy(
              mbsc, name.toString(), ThreadMXBean.class);
            long threadIds[] = threadBean.getAllThreadIds();
            for (long threadId: threadIds) {
              ThreadInfo threadInfo = threadBean.getThreadInfo(threadId);
              System.out.println (threadInfo.getThreadName() + " / " +
                  threadInfo.getThreadState());
            }
      
      
      
      In the above, args[0] should be the process ID of the target JVM.

    It looks like that lots of operating system level functions are needed in the back of the scene for the code to work. You run the code containing the VirtualMachine class in your JVM to connect to the target JVM whose process ID is known to you. At the level of operating system, this is the communication between two processes. There is no port number involved in the above code. There is no TCP/IP in the above code.

    One interesting consequence of the Attach API is this. Say that you run a program such as jconsole to try to connect to a JVM to get the JMX MBean server. Suppose that the connection works. Can you conclude from this that the MBean server has been started when the JVM is started? The answer is "NO". This is because that the MBean sever may have been started by your client program by using the Attach API!

    References

    1. http://java.dzone.com/articles/taming-jmx-weblogic-server
    2. http://docs.spring.io/spring/docs/2.0.x/reference/jmx.html
    3. http://docs.oracle.com/cd/E11035_01/wls100/jmx/understandWLS.html#MBeanServers
    4. http://www.javaworld.com/article/2071330/the-attach-api.html

    Tuesday, January 6, 2015

    Order Management System

    Order Management System (OMS) is a new software application that has been developed to help companies to manage orders, customers, product inventory, order shipment, etc. It is an excellent product that can greatly improve business. For details, see the following link: http:www.lakexy.com

    Java Annotation Retention

    Annotation Retention Policy

    Java annotation works by adding some code to the java file or the compiled java class file. The notation used is the @Retention tag.

    The following is the overall picture:
    Source File( A.java) --> Compiled bytecode(A.class) --> Runtime memory after loaded by classloader

    There are 3 Retention policies. In the following, we use a '*' to indicate that some annotation code has been inserted.

    @Retention(RetentionPolicy.SOURCE)
    A*.java --> A.class --> A-runtime

    @Retention(RetentionPolicy.CLASS)
    A*.java --> A*.class --> A-runtime
    This is the default policy.

    @Retention(RetentionPolicy.RUNTIME)
    A*.java --> A*.class --> A*-runtime.
    This is generally used for customer annotations.

    Java Annotation Implementation

    Java annotation is not part of the java standard edition. You can see that the package is javax.annotation. So a java server container such as Weblogic server and Tomcat serfver is generally needed for the annotation to work. The server container has to implement the annotation artifacts so it knows how to parse, compile and run the java classes with the annotations. Of course, you can also put the needed library for annotation on the classpath to run the java programs with annotations successfully without using a sever container.