javakaffee

Just another weblog about (web) development technologies like spring, tapestry, jersey, jsf, hibernate and more

November 15, 2008

How to use spring-aop in jersey - added example resource class to the spring-annotations sample

Filed under: development, java, webdev, REST — martin.grotzke @ 8:40 pm

Yesterday I added another example resource to the spring-annotations sample that shows how to use spring-aop with jersey.


The example contains a resource class SpringAopResource that is created by spring (in this case via autodetection/classpath scanning). There’s an example SecurityAdvice defined with a pointcut matching methods annotated with a custom @Secure annotation. The resource method of the SpringAopResource of course is annotated with this annotation, so that the SecurityAdvice will be applied to this resource method. (The SecurityAdvice in our case does plain stupid logging, this should be changed of course :))


So that spring-aop can come into play our resource class needs to be proxied. This raises the question about subresources. Normally they would be created by the resource class, e.g. some UsersResource.getUserResource(String userId) would return some new UserResource(userId). At this point the UserResource could not be proxied by spring - simply impossible. For this we introduced the ResourceContext (I already blogged about this in the context of the initial jersey-spring integration), so that a resource class can fetch an instance of a subresource class from the IoC container.
This is demonstrated by the subresource locator SpringAopResource.getSubResource() which returns an instance of a SpringAopSubResource fetched from the ResourceContext.


The code is shown below - just too little to believe that this should be all :)


The configuration in applicationContext.xml for aspectj-annotation support, and the configuration of the advice bean.

<beans xmlns="..." etc.>
    ...
    <aop:aspectj-autoproxy/>
    <bean id="securityAdvice" class="com.sun.jersey.samples.springannotations.resources.aop.SecurityAdvice" />
    ...
</beans>


The @Secure annotation and the SecurityAdvice:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Secure {

}

@Aspect
public class SecurityAdvice {
    
    private static final Logger LOGGER = Logger.getLogger( SecurityAdvice.class.getName() );
    
    @Before( "@annotation(com.sun.jersey.samples.springannotations.resources.aop.Secure)" )
    public void check( JoinPoint jp ) {
        /* this might get some authentication/authorization info from the request 
         * and throw a WebApplicationException with a response with status 401 (unauthorized)
         * if the request is not authorized.
         */
        final Signature signature = jp.getSignature();
        LOGGER.info( "Authorized execution of " + signature.getDeclaringTypeName() + "." + signature.getName() );
    }
    
}


The resource and subresource classes:

@Path("/spring-aop")
@Component
@Scope("singleton")
public class SpringAopResource {
    
    @Context
    private ResourceContext _resourceContext;

    @Autowired
    private Item _item;

    @GET
    @Secure
    @Produces("application/xml")
    public Item getItem() {
        return _item;
    }
    
    @Path( "subresource" )
    public SpringAopSubResource getSubResource() {
        return _resourceContext.getResource( SpringAopSubResource.class );
    }
    
}


@Component
@Scope("prototype")
public class SpringAopSubResource {

    @Autowired
    @Qualifier("1")
    private Item2 _item;

    @GET
    @Secure
    @Produces("application/xml")
    public Item2 getItem() {
        return _item;
    }
    
}

That’s all. The Item and Item2 classes are just normal beans injected by spring.


You can pull the full example from subversion or browse it online.

August 31, 2008

Added new jersey sample spring-annotations - how to use jersey and spring/annotations

Filed under: development, java, webdev, REST — martin.grotzke @ 5:00 pm

After I have blogged about the jersey-spring integration (jersey-spring integration mostly complete, jersey-spring and changes now available in the jersey trunk / namespace com.sun.ws.rest renamed to com.sun.jersey) and Paul posted an update on the jersey-spring integration in his blog, I finally added a sample that shows how to use jersey and spring (using annotations provided/supported by spring >= 2.5: @Resource and @Autowired).


One resource class in this sample app also shows how users of spring < 2.5 (e.g. spring 2.0) can use annotation based autowiring, this is achieved using the @Autowire annotation provided by jersey-spring (which I already described in this posting).


This sample is especially useful as it will be up to date in the future: it will reflect configuration, namespace or other changes made in jersey, jersey-spring or even spring, so that there’s not the problem that there will be information that is out of date ;-)

April 28, 2008

jersey-spring and changes now available in the jersey trunk / namespace com.sun.ws.rest renamed to com.sun.jersey

Filed under: development, java, webdev, REST — martin.grotzke @ 11:57 pm

The jersey-spring integration that I described in my previous posting is now merged into the jersey trunk, as well as the changes that were made for better integration of spring and IoC-frameworks in general in the spring-integration branch.

One thing that was changed today is that the namespace of jersey is changed from com.sun.ws.rest to com.sun.jersey, this includes these changes in detail:

  • packages com.sun.ws.rest.api and com.sun.ws.rest.spi are renamed to com.sun.jersey.api and com.sun.jersey.spi
  • configuration namespace of properties/features com.sun.ws.rest.config is renamed to com.sun.jersey.config (e.g. com.sun.ws.rest.config.property.resourceConfigClass is now com.sun.jersey.config.property.resourceConfigClass)
  • the jersey-spring package com.sun.ws.rest.spring is renamed to com.sun.jersey.spring, e.g. the SpringServlet is now com.sun.jersey.spring.SpringServlet
  • the groupId of jersey and jersey-spring are changed from jersey to com.sun.jersey


If you want to use the spring-integration that I blogged about, remember to change the import section of your classes, web.xml and maven pom.xml accordingly.

April 21, 2008

jersey-spring integration mostly complete

Filed under: development, webdev, REST — martin.grotzke @ 1:48 am

Hi,

after jersey 0.7 was released on friday, I just finished writing tests for the spring-integration stuff.
The jersey-spring-integration is based on the SpringComponentProvider blogged by Paul Sandoz and adds some nice things like annotation based injection of IoC-container managed beans (useful for all IoC-frameworks) and annotation based autowiring support even for spring-2.0 users.
Some extensions were made to jersey itself, which are useful for integration of IoC-containers in general (like the mentioned annotation based injection of beans).

The jersey-spring-integration is developed in a separate branch and is going to be part of jersey release 0.8. If you want to use it before jersey 0.8 is there, you can checkout the branch, build jersey, then spring and use the built jars (and configure your web.xml accordingly as described below).

So what does the jersey-spring-integration provide?

  • Integration of spring-2.0 or spring-2.5 with jersey (what else 8-))
  • jersey resources can be managed by spring (pulled from spring’s bean-factory)
  • jersey resources can use spring managed beans via the @Inject annotation that is now provided by jersey (also useful for integration of other IoC-containers)
  • jersey resources can be marked with the @Autowire annotation (that is provided by the jersey-spring-integration), such resources then are created by spring and dependencies injected accordingly
  • jersey resources can use annotation based configuration that comes with spring-2.5
  • jersey now provides an AnnotationInjectable, that can be provided for some annotation, so that the injectable is asked for an instance of a class if a field of some resource is annotated with the specified annotation
  • jersey now provides a ResourceContext, that can be used to get an instance of some subresource from the IoC-container and therfore can use features like e.g. AOP provided by the IoC-container also for subresources

Integration of spring with jersey

After you built both jersey and jersey-spring from the spring-integration branch and configured them as dependencies for your project, you only have to register the SpringServlet in your web.xml (I’m asuming that you have spring already configured therein):

<servlet>
    <servlet-name>Jersey Spring</servlet-name>
    <servlet-class>com.sun.ws.rest.spring.SpringServlet</servlet-class>
    <init-param>
        <param-name>com.sun.ws.rest.config.property.resourceConfigClass</param-name>
        <param-value>com.sun.ws.rest.api.core.PackagesResourceConfig</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.ws.rest.config.property.packages</param-name>
        <param-value>your.resource.package</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>Jersey Spring</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>

Use resources managed by spring

If you want to get your resource created by spring you simply have to define it in your applicationContext.xml. Only bear in mind, that the scope in your applicationContext.xml matches the scope of your resource class (jersey-Singleton == spring-singleton, jersey-PerRequest == spring-prototype).


For example you might have this resource:

@Path( "springifiedsingleton" )
@Singleton
public class SpringifiedSingletonRootResource {

    private String _value;

    public SpringifiedSingletonRootResource String value ) {
        _value = value;
    }
    
    @GET
    @ProduceMime("text/plain")
    public String getValue() {
        return _value;
    }
    
}

Define the resource in your applicationContext.xml:

<bean id="singletonRootResource" class="spring.examples.SpringifiedSingletonRootResource"
    scope="singleton">
    <constructor-arg value="foo" />
</bean>

That’s it, now your resources will be provided by spring.


If you don’t want to define each new resource in your applicationContext, but simply want to use your existing spring managed beans/services, you can use the following approach using the @Inject annotation.

@Inject spring managed beans/services into your resources

The @Inject annotation is now provided by jersey and is useful for integration of several IoC-containers, not only for spring. A field that is annotated with @Inject is initialized with an instance (of the fields type), that is pulled from the ComponentProvider, and in this case from spring.


Just to have an example:

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.ProduceMime;

import com.sun.ws.rest.spi.resource.Inject;
import com.sun.ws.rest.spi.resource.Singleton;

@Path( "injectingsingleton" )
@Singleton
public class InjectingSingletonRootResource {

    @Inject
    private SomeService _someService;
    
    @GET
    @ProduceMime("text/plain")
    public String getValue() {
        return _someService.getSomething();
    }
    
}

Your applicationContext.xml now only has to contain the bean definition for your SomeService


The instance of SomeService is retrieved from spring by its type, so if there are more than one bean definitions for SomeService the injection is not going to work. If this would be a requirement we should use another annotation that allows to set the bean-name (like e.g. @Resource).

Use @Autowire to autowire your resources with spring-2.0

If you want to get your resource class autowired, you can annotate it with @Autowire, which is provided by the jersey-spring-integration package. Resource classes annotated with @Autowire are created by spring (also spring BeanPostProcessors are applied). The @Autowire also allows to specify the AutowireMode (one of AUTODETECT, BY_NAME, BY_TYPE, CONSTRUCTOR, see AutowireCapableBeanFactory) and whether to perform a dependency check for objects (which is not applicable to autowiring a constructor, thus ignored there).


The example is really simple:

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.ProduceMime;

import com.sun.ws.rest.spi.resource.Inject;
import com.sun.ws.rest.spi.resource.Singleton;
import com.sun.ws.rest.spring.annotations.Autowire;

@Path( "injectingsingleton" )
@Singleton
@Autowire
public class AutowiringSingletonRootResource {

    @Inject
    private SomeService _someService;
    
    @GET
    @ProduceMime("text/plain")
    public String getValue() {
        return _someService.getSomething();
    }
    
}

Your applicationContext.xml still has to contain the bean definition for your SomeService. As this AutowiringSingletonRootResource is created by spring it can make use of all spring features, but you don’t have to define each resource in your applicationContext.xml.

Retrieve your subresources from the ResourceContext

If you have your root resource classes created by spring, you’re perhaps happy that you can use features provided by spring like AOP, transaction-handling or caching. But what to do when your root resource must return some sub-resource (sub-resource locator), but this sub-resource shall also be created by spring? Until now the sub-resource was created using new() and therefore it could not be created by spring and therefore was not proxied - no AOP, transaction-handling or caching…


This can now be achieved using the ResourceContext, that can be used to retrieve an instance of some sub-resource:

import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.Context;

import spring.examples.UserService.User;

import com.sun.ws.rest.api.NotFoundException;
import com.sun.ws.rest.api.core.ResourceContext;
import com.sun.ws.rest.spi.resource.Inject;
import com.sun.ws.rest.spi.resource.Singleton;

@Path( "users" )
@Singleton
public class UsersResource {

    private final UserService _userService;
    
    @Context
    private ResourceContext _resourceContext;
    
    public UsersResource( UserService userService ) {
        _userService = userService;
    }
    
    @Path( "{username}" )
    public UserResource getValue( @PathParam( "username" ) String username ) {
        final User user = _userService.findByUsername( username );
        if ( user == null ) {
            throw new NotFoundException( "User " + username + " not found!" );
        }
        final UserResource result = _resourceContext.getResource( UserResource.class );
        result.setUser( user );
        return result;
    }
    
}

In this example, I asume that both the UsersResource and the UserResource are defined in your applicationContext.xml (and the UserService of course also) and therefore created by spring, the ResourceContext is injected by jersey.

Using spring-2.5 features

Just to mention, it’s also possible to use annotation driven bean configuration as it came with spring-2.5. This is an example for a resource class, also notice that both scopes must match:

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.ProduceMime;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.sun.ws.rest.spi.resource.PerRequest;

@Path( "injectingsingleton" )
@PerRequest
@Component
@Scope( "prototype" )
public class AnnotatedPerRequestResource {

    @Autowired
    private SomeService _someService;
    
    @GET
    @ProduceMime("text/plain")
    public String getValue() {
        return _someService.getSomething();
    }
    
}

That spring discovers this resource class, the applicationContext.xml must contain the , as it’s described in the spring documentation.

March 8, 2008

Jersey is fun - exploring RESTful webservices - subtitle: @Springify your resources

Filed under: development, java, webdev, REST — martin.grotzke @ 6:14 am

Hi,

my last post is nearly years ago and of course I wanted to write about this and that. But right now I had so much fun that I have to share this.

Fun with… jersey, the reference implementation of the upcoming jsr311 that specifies how to build RESTful web services in java.

Now I was just playing around with jersey and had a look at the sources and found out how easy it is to define an annotation and inject spring beans based on this annotation. The spring integration itself is described here, it shows a SpringServlet that loads beans based on the class from springs application context.

Now the part that made me happy:

First you define an annotation @SpringBean:


@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface SpringBean {

}

Then, in your SpringServlet you implement a base SpringInjectable for springified beans (of course you can make this public, but’s it’s not that important, just for conveniance…):


    private static abstract class SpringInjectable<V> extends Injectable<SpringBean, V> {
        public Class<SpringBean> getAnnotationClass() {
            return SpringBean.class;
        }
    }

and finally register the spring beans that you want to publish to your resource classes within a method like this (still in the SpringServlet):


    protected void initiate(ResourceConfig rc, WebApplication wa) {
        // get spring's applicationContext
        ApplicationContext springContext = WebApplicationContextUtils.
                getRequiredWebApplicationContext(getServletContext());
        // register your spring beans - this is new
        addInjectables( wa, springContext, SpringService1.class, SpringService2.class ); 
        // now let jersey do the rest
        wa.initiate(rc, new SpringComponentProvider(springContext));
    }

    private void addInjectables( WebApplication wa, final ApplicationContext springContext, Class<?> ... injectables ) {
        for ( final Class<?> injectable : injectables ) {
            wa.addInjectable( injectable, new SpringInjectable() {

                @Override
                public Object getInjectableValue( Annotation a ) {
                    return springContext.getBean( getBeanName( injectable, springContext ) );
                }
                
            });
            
        }
    }

After this rather heavy setup phase you can start to inject your spring beans using the @SpringBean annotation:


public class SomeResource {

    private @SpringBean SomeService _service;

    ...

}

Fairly easy, isn’t it? Just define an annotation and define how to resolve beans to that - really straightforward!

Of course, you’re right, the shortcoming here is that you must define (know) which spring beans shall be provided to your resources - consider this to be a security feature ;)

Finally, it was playing around, looking here and there, exploring, and finding out how easy things are - really nice!

And not to forget - jersey 0.6 was released today, as you may also read here.

Now I’m going back to jersey,
cheers,
Martin

September 12, 2006

JUnit test spring managed and proxy’ed beans

Filed under: development, java — martin.grotzke @ 9:00 am

When you have some spring managed bean MyBean and use spring features like e.g. declarative transaction management, spring will create a proxy object for your bean instance.
When you use springs beanfactory in junit and try to downcast the object to the bean class itself (and not to some implemented interface), you’ll get a ClassCastException (telling you that you have s.th. like $Proxy$39).
Some example code: MyBean myBean = (MyBean)beanFactory.getBean("myBean");. The ClassCastException is probably caused by junits dynamic classloading together with the proxy object.

The solution is to use an interface like MyInterface that is implemented by MyBean. Then you can downcast the proxy object to the interface: MyInterface myBean = (MyInterface)beanFactory.getBean("myBean");.

Another solution is described in this posting in the spring forum: it suggests to disable junits dynamic classloading by extending the with those classes that shouldn’t be dynamically loaded.

Some more information about junits dynamic classloading can be found in the junit FAQ.

August 24, 2006

JMXtend your Spring application…

Filed under: development, java — martin.grotzke @ 11:53 pm

…with both own annotated beans and Hibernates StatisticsService.

I just managed to export an annotation based (Spring managed) bean to JMX. This is fairly simple and can even be done using the “autodetection” mechanism of springs MBeanExporter.

The following snipplet shows the relevant part of the applicationContext.xml:

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
  <property name="assembler">
    <!-- will create management interface using annotation metadata -->
    <bean class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
      <property name="attributeSource" ref="jmxAttributeSource"/>
    </bean>
  </property>
  <property name="namingStrategy">
    <!-- will pick up ObjectName from annotation -->
    <bean id="namingStrategy"
        class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
      <property name="attributeSource" ref="jmxAttributeSource"/>
    </bean>
  </property>
  <property name="autodetect" value="true"/>
</bean>

<bean id="jmxAttributeSource"
  class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>


The java class is defined as follows:

@ManagedResource(objectName="org.company.project:name=MailService", description="Mail Service",
  log=true, logFile="jmx.log", currencyTimeLimit=15, persistPolicy="OnUpdate",
  persistPeriod=200, persistLocation="foo", persistName="bar")
  public final class MailServiceImpl {
  ...
  @ManagedAttribute(description="Get the number of queued mail deliveries.")
  public int getCountQueuedEmails() {
    return _queue.size();
  }
}

This is everything one has to do to expose a Spring bean via JMX.

If you want to check if it’s working just run jconsole (it’s distributed with Suns jvm) and connect to the Bootstrap process.
But stop - if you’re running tomcat, you should add to the catalina.sh|bat the following catalina (java) options (when you’re using startup/shutdown scripts, export the variable in startup.sh|bat):

CATALINA_OPTS="-Dcom.sun.management.jmxremote
   -Dcom.sun.management.jmxremote.port=8099
   -Dcom.sun.management.jmxremote.ssl=false
   -Dcom.sun.management.jmxremote.authenticate=false"

(You can also just use the JAVA_OPTS variable)

Now lets proceed and export the StatisticsService of Hibernate to JMX (also using the MBeanExporter). For this it’s necessary to turn the MBeanExporters autodetection off, otherwise he would complain that the StatisticsService has no ManagedResource annotation. The formerly autodetected bean (mailService) in consequence must be declared via the beans property. After this has been changed, a new exporter (using method name based assembly) for the StatisticsService can be declared.

Then the spring configuration is the following:

<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter">
  <property name="assembler">
    <!-- will create management interface using annotation metadata -->
    <bean class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
      <property name="attributeSource" ref="jmxAttributeSource"/>
    </bean>
  </property>
  <property name="namingStrategy">
    <!-- will pick up ObjectName from annotation -->
    <bean id="namingStrategy"
        class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
      <property name="attributeSource" ref="jmxAttributeSource"/>
    </bean>
  </property>
  <property name="autodetect" value="false"/>
  <property name="beans">
    <map>
      <entry key="foo1">
        <ref local="mailService" />
      </entry>
    </map>
  </property>
</bean>

<bean id="jmxAttributeSource"
  class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
  
<bean id="methodNameBasedExporter" class="org.springframework.jmx.export.MBeanExporter">
  <property name="beans">
    <map>
      <entry key="org.hibernate:name=StatisticsService">
        <bean class="org.hibernate.jmx.StatisticsService">
          <property name="sessionFactory" ref="sessionFactory"/>
          <property name="statisticsEnabled">
            <value>true</value>
          </property>
        </bean>
      </entry>
    </map>
  </property>
  <property name="assembler">
    <bean class="org.springframework.jmx.export.assembler.MethodNameBasedMBeanInfoAssembler">
      <property name="methodMappings">
        <props>
          <prop key="bean:name=StatisticsService" />
        </props>
      </property>
    </bean>
  </property>
</bean>

July 4, 2006

JSF/Acegi authentication with a backing bean

Filed under: development, java, security — martin.grotzke @ 10:40 am

Thanx to this blog post i managed to integrate Acegi 1.0.1 with JSF. Some minor modifications were necessary, because in this version of Acegi some things have changed.

The basic idea of this approach is to use a JSF backing bean that is responsible for authentication (that processes the “login” request from the user). This allows you not only to send the user to a success/error page, but you are also able to send him to a custom page if some condition is met.

The backing bean looks like the following:


package com.freiheit;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.acegisecurity.Authentication;
import org.acegisecurity.AuthenticationManager;
import org.acegisecurity.context.HttpSessionContextIntegrationFilter;
import org.acegisecurity.context.SecurityContext;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import org.acegisecurity.ui.WebAuthenticationDetails;
import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Required;

public final class AuthenticationController {

 private static final Log LOG = LogFactory.getLog( AuthenticationController.class );

 private String _username;
 private String _password;

 // injected properties
 private AuthenticationManager _authenticationManager;

 public String getPassword() {
     return _password;
 }

 public void setPassword( String password ) {
     _password = password;
 }

 public String getUsername() {
     return _username;
 }

 public void setUsername( String userName ) {
     _username = userName;
 }

 @SuppressWarnings("unchecked")
 public String authenticate() {
     String outcome = "failure";

     try {
         final String userName = getUsername();
         final String password = getPassword();
         final UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(
                 userName, password );

         final HttpServletRequest request = getRequest();
         authReq.setDetails( new WebAuthenticationDetails( request ) );

         final HttpSession session = request.getSession();
         session.setAttribute(
                         AuthenticationProcessingFilter.ACEGI_SECURITY_LAST_USERNAME_KEY,
                         userName );

         /* perform authentication
          */
         final Authentication auth = getAuthenticationManager().authenticate( authReq );
      
         /* initialize the security context.
          */
         final SecurityContext secCtx = SecurityContextHolder.getContext();
         secCtx.setAuthentication( auth );
         session.setAttribute( HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY, secCtx );
      
         outcome = "success";
      
     } catch ( Exception e ) {
         outcome = "failure";
         FacesContext.getCurrentInstance().addMessage( null, new FacesMessage( e.getMessage() ) );
     }
  
     return outcome;
 }

 public void logout( ActionEvent e ) {

     final HttpServletRequest request = getRequest();
     request.getSession( false ).removeAttribute( HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY );
  
     /* simulate the SecurityContextLogoutHandler
      */
     SecurityContextHolder.clearContext();
  
     request.getSession( false ).invalidate();
 }

 private HttpServletRequest getRequest() {
     return (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
 }

 public AuthenticationManager getAuthenticationManager() {
     return _authenticationManager;
 }

 @Required
 public void setAuthenticationManager(
         AuthenticationManager authenticationManager ) {
     _authenticationManager = authenticationManager;
 }

}


The spring configuration (applicationContext.xml) has the following entries (note that this is spring-2, this introduces new scopes like e.g. “session”):


 <bean id="acegiFilterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
  <property name="filterInvocationDefinitionSource">
   <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /**=httpSessionContextIntegrationFilter,securityRequestFilter,exceptionTranslationFilter,filterSecurityInterceptor
   </value>
  </property>
  <!-- 
   /**=httpSessionContextIntegrationFilter,requestWrapper,filterSecurityInterceptor
  -->
 </bean>
 
 <bean id="httpSessionContextIntegrationFilter" class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
  <property name="context">
   <value>org.acegisecurity.context.SecurityContextImpl</value>
  </property>
 </bean>
 
 <bean id="securityRequestFilter" class="org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter" />
 
 <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
  <property name="authenticationEntryPoint">
   <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
    <property name="loginFormUrl">
     <value>/login.jsf</value>
    </property>
    <property name="forceHttps"><value>false</value></property>
   </bean>
  </property>
  <property name="accessDeniedHandler">
   <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">
    <property name="errorPage">
     <value>/accessDenied.jsf</value>
    </property>
   </bean>
  </property>
 </bean>
 
 <bean id="filterSecurityInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
  <property name="authenticationManager"><ref bean="authenticationManager"/></property>
  <property name="accessDecisionManager">
   <!--
    The AffirmativeBased voter allows access if at least one voter votes
    to grant access. Use the UnanimousBased voter if you only want to
    grant access if no voter votes to deny access. -->
   <bean class="org.acegisecurity.vote.AffirmativeBased">
    <property name="decisionVoters">
     <list>
      <bean class="org.acegisecurity.vote.RoleVoter">
       <!--  Reset the role prefix to "", default is ROLE_ -->
       <property name="rolePrefix">
        <value></value>
       </property>
      </bean>
      <!--
       The authenticated voter grant access if e.g.
       IS_AUTHENTICATED_FULLY is an attribute -->
      <bean class="org.acegisecurity.vote.AuthenticatedVoter" />
     </list>
    </property>
   </bean>
  </property>
  <property name="objectDefinitionSource">
   <value>
    CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
    PATTERN_TYPE_APACHE_ANT
    /pages/**=IS_AUTHENTICATED_FULLY
    /pages/company/**=/permissions/permission1
    /pages/**=/permissions/permission01
   </value>
  </property>
 </bean> 

 <bean id="authenticationManager"
  class="org.acegisecurity.providers.ProviderManager">
  <property name="providers">
   <list>
    <ref local="daoAuthenticationProvider" />
   </list>
  </property>
 </bean>
 
 <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
  <property name="userDetailsService">
   <bean class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
    <property name="userMap">
     <value>
      mgrotzke=test123,/permissions/permission1,/permissions/permission01
      skaiser=test123,/permissions/permission01
     </value>
    </property>
   </bean>
  </property>
 </bean>
 
 <bean id="authenticationController" class="com.freiheit.AuthenticationController" scope="session">
  <property name="authenticationManager"><ref bean="authenticationManager"/></property>
 </bean>


The authenticationController bean is the backing bean (see above) that is called from the (jsp/facelets) page. It can be defined in the spring applicationContext.xml because the faces-config contains an entry for springs DelegatingVariableResolver:


     <application>
        <variable-resolver>
            org.springframework.web.jsf.DelegatingVariableResolver
        </variable-resolver>
    </application>


The web.xml has the following filter entry for acegi:


 <filter>
  <filter-name>Acegi Filter Chain Proxy</filter-name>
  <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
   <param-name>targetBean</param-name>
   <param-value>acegiFilterChainProxy</param-value>
  </init-param>
 </filter>

 <filter-mapping>
      <filter-name>Acegi Filter Chain Proxy</filter-name>
      <servlet-name>Faces Servlet</servlet-name>
      <dispatcher>FORWARD</dispatcher>
      <dispatcher>REQUEST</dispatcher>
  </filter-mapping>


The faces-config.xml contains the following navigation-rules for login and logout:


<navigation-rule>
 <from-view-id>/login.xhtml</from-view-id>
 <navigation-case>
  <from-action>#{authenticationController.authenticate}</from-action>
  <from-outcome>success</from-outcome>
  <to-view-id>/pages/index.xhtml</to-view-id>
  <redirect/>
 </navigation-case>
 <navigation-case>
  <from-action>#{authenticationController.authenticate}</from-action>
  <from-outcome>failure</from-outcome>
  <to-view-id>/login.xhtml</to-view-id>
 </navigation-case>
</navigation-rule>
<navigation-rule>
 <from-view-id>*</from-view-id>
 <navigation-case>
  <from-action>logout</from-action>
  <to-view-id>/login.xhtml</to-view-id>
  <redirect/>
 </navigation-case>
</navigation-rule>


The login page using facelets essentially has the following content:


<form jsfc="h:form" id="loginForm">
 <span jsfc="h:messages"/><br/>
 Username: <input jsfc="h:inputText" id="inputUsername" value="#{authenticationController.username}" /><br/>
 Password: <input jsfc="h:inputSecret" value="#{authenticationController.password}" /><br/>
 <input jsfc="h:commandButton" action="#{authenticationController.authenticate}"
     value="Login" />
</form>


The logout button should be defined in an overall template, and would look like the following:


<a href="#" jsfc="h:commandLink" action="logout"
    actionListener="#{authenticationController.logout}">#{msgs.logout}</a>

Powered by WordPress