Thursday, December 16, 2010

No dynamic filters in servlet spec 2.4 you say?

I had a requirement recently to be able to dynamically control CAS security filters in a web application (default CAS security to off for development and allow it to be turned on by external configuration post-deployment).  Unfortunately, servlet spec 2.4 does not allow one to programatically add new servlet filters (at least that's the prevailing theory).  This is a feature added/being added to the servlet 3.0 API.

My friend Google said there were a number of others who wanted to do the same thing but they were being pointed to servlet 3.0.  Unfortunately, servlet 3.0 and J2EE 6 were not an option for me, so it was looking like a tough nut to crack.

Then it struck me, what if I created a generic, conditional servlet filter that took the name of the class of the real filter as an init param?  And, what if I passed in the condition that was to be evaluated to determine whether or not to create and/or invoke the real filter?  Then, in the conditional filter, I could examine the condition and, as necessary, dynamically create an instance of the wrapped filter class.

Turns out it worked like a charm.  Here's how.  First the filter definition in web.xml:

    CAS Authentication Filter
    my.org.security.servlet.ConditionalFilter
    
        condition
        cas/enabled
    
    
        wrapped-class
        
            org.jasig.cas.client.authentication.AuthenticationFilter
        
    


public class ConditionalFilter implements Filter {

    // instance of the actual filter being wrapped
    private Filter _wrappedFilter;

    // are we to ignore the wrapped filter?
    private boolean _ignore = true;

    public ConditionalFilter() {
    } // constructor

    public void init(FilterConfig filterConfig) throws ServletException {
        // the 'condition' init param tells us whether or not 
        // the wrapped filter is active
        _ignore = !checkCondition(filterConfig.getInitParameter("condition"));

        try {
            if (!_ignore) {
                // the wrapped filter is active so we create an instance 
                // of it and initialize it
                _wrappedFilter = getFilterInstance(
                    filterConfig.getInitParameter("wrapped-class")
                );
                _wrappedFilter.init(filterConfig);
            }
        } catch (Exception e) {
            throw new ServletException(e);
        }
    } // init()

    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain filterChain)
        throws IOException, ServletException {
        if (!_ignore) {
            // the wrapped filter is active so we let it do its work
            _wrappedFilter.doFilter(request, response, filterChain);
        } else {
            // wrapped filter is inactive so simply move on to the next filter
            filterChain.doFilter(request, response);
        }
    }  // doFilter()

    public void destroy() {
        if (_ignore) {
            _wrappedFilter.destroy();
        }
    }  // destroy()

    private Filter getFilterInstance(String className)
        throws ClassNotFoundException, InvalidClassException,
               InvocationTargetException, IllegalAccessException,
               InstantiationException, NoSuchMethodException {
        // try to create an instance of the wrapped filter 
        // with the given class name
        Class filterClass = Class.forName(className);
        java.lang.reflect.Constructor constructor = filterClass.getConstructor();
        Object filter = constructor.newInstance();

        if (!(filter instanceof Filter)) {
            throw new InvalidClassException(
                String.format("'%s' is not an instance of Filter", className)
            );
        }
        return (Filter)filter;
    } // getFilterInstance()

    /*
     * looks up the configured 'condition' via JNDI to determine 
     * whether or not the wrapped filter is active
     */
    private boolean checkCondition(String condition) {
        boolean result = false;

        try {
            InitialContext context = new InitialContext();
            String path = String.format("java:comp/env/%s", condition);
            result =(Boolean)context.lookup(path);
        } catch (final NamingException e) {
            System.out.println(
                "unable to load condition from JNDI"
            );
        }

        return result;
    } // checkCondition()

} // class ConditionalFilter

Friday, April 2, 2010

One Thumb Up for Pair Programming

Pair programming is one of the characteristics of extreme programming and is, frankly, something I have not been a particularly strong advocate of. The idea of two developers sitting side-by-side, sharing one keyboard and working the exact same problem seems terribly inneficient to me. However, there are two reasons why, for short periods of time, that it would be beneficial to engage in pair programming.

The first one would be for test driven development. For a particular functional area under development one developer would write the unit/integration tests and one would write the code. To me, this would be the most efficient use of pair programming.

The second reason why I think it would be beneficial to perform short stints of pair programming would be to gain insight into the work practices, processes and procedures of one's teammates. For me personally, I could see how my teammates work and glean some ideas on how I could be more productive and efficient. What tools do they use? How do they use them? Do they have any shortcuts or time-savers? Likewise, it would be an opportunity for me to help my teammates improve their efficiency by offering suggestions based on the things that I do that help me.

Tuesday, March 9, 2010

jboss plugin for auto-deploying artifact during build

This is VERY handy for automatically deploying your artifact/war after a maven build is completed. Simply add the mvn goal jboss:hard-deploy to your maven command.
<plugin>
   <groupId>org.codehaus.mojo</groupId>
   <artifactId>jboss-maven-plugin</artifactId>
   <version>1.4</version>
   <configuration>
      <jbossHome>${jboss.home}</jbossHome>
      <serverName>default</serverName>
      <fileName>target/my-app.war</fileName>
   </configuration>
</plugin>

Saturday, March 6, 2010

Tunneling PUT and DELETE from ExtJS to Jersey ReST

Here is how you can invoke AJAX POSTs in ExtJS that map to PUT and/or DELETE methods in your Jersey ReST services.

The first step is to configure Jersey to allow this:
<init-param>
    <param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
    <param-value>com.sun.jersey.api.container.filter.PostReplaceFilter</param-value>
</init-param>
The next step is to issue the AJAX request (in this case we're going to issue a POST but tell Jersey to invoke the PUT mapped method instead):
Ext.Ajax.request({
    headers : {
        'X-HTTP-Method-Override' : 'PUT'
    },
    method: 'POST',
    url: '/my-api/some-service',
    params: {
        name : someObj.name,
        date : someObj.date,
        amount : someObj.amount
    },
    success: this.onSaveSuccess.createDelegate(this),
    failure: this.onSaveFailure.createDelegate(this)
});

Friday, March 5, 2010

CSS for flowing boxes in a DataView

Here is some CSS that can be used to flow/float boxes inside an ExtJS DataView:

.dataViewNode {
   width: 10em;
   float: left;
   height: auto;
   overflow: hidden;
   position: relative;
   margin: 4px;
   z-index: 5;
   text-align: center;
   padding: 2px 0 0 0;
   font-size: 0.8em;
}  

Thursday, January 28, 2010

InputStream from URL BufferedImage

Here is how you can make an InputStream for a BufferedImage:

    URL url = new URL("http://www.google.com/intl/en_ALL/images/logo.gif");
    BufferedImage image = ImageIO.read(url);
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    ImageIO.write(image, "gif", os);
    InputStream is = new ByteArrayInputStream(os.toByteArray());