Loading...

Friday, February 27, 2009

Conditional display of text in GSP file in Grails

Grails contains so many useful features I encounter one (at least) each day. Today I wanted to add Google Analytics code to my site. But the Javascript code only is necessarry in the production environment. Well Grails makes it so easy:

<g:if env="production">
...JS code for Google Analytics...
</g:if>

The if tag has a env attribute. And if the Grails applications run in the specified enviornment, then the code in the tag is added to the page.

Show HTML as HTML in Grails

Starting with Grails on a little project I already learned something. In a domain object, Wish, I had a String property, description, which can contain HTML code. For example we can use the following value for the description property: This description is<br />two lines..

Following the Grails reference documentaiton I created a GSP file and used ${fieldValue(bean: wish, property: 'description'} to output the value. When I look a the output I got:

This description is <br />two lines.

The HTML was already encoded and the < and > brackets where replaced by &lt; and &gt; automatically.

I changed the GSP file and used ${wish.description} and I got what I wanted:

This description is
two lines.

We can use encodeAsHTML() and decodeHTML() methods to get the same effect. So for example if we use ${wish.property.encodeAsHTML() the < and > brackets are automatically replaced again.

Tuesday, February 17, 2009

Use Spring Configurator to support different dev, test and production environments with Spring configuration files (Part 2)

In the previous part we learned about the Spring Configurator. In this part we learn how to create properties for different environments (or running modes) and how to use them.

First we add a simple String property with the name text to our Sample class:

package com.mrhaki.spring.mavenapp;

import org.apache.cocoon.configuration.Settings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Sample {

    private Settings settings;

    private String text;

    @Autowired
    public void setSettings(Settings settings) {
        this.settings = settings;
    }

    public void setText(String name) {
        this.text = name;
    }

    @Override
    public String toString() {
        return "Running in [" + settings.getRunningMode() + "] mode. "
                + "Text = [" + text + "].";
    }
}

Notice how we changed the toString method so we can see the value for the text property. Next we add the bean definition for the Sample class in our applicationContext.xml. Therefore we add the following lines after <configurator:settings/>:

<bean name="sample" class="com.mrhaki.spring.mavenapp.Sample">
 <property name="text" value="${sample.text}"/>
</bean>

At line 2 we assign the text property a variable value, which is not set yet. The value will be set if we run the application and is read from a property file. We can now use the Spring Configurator to define a different value for sample.text for every running mode we want to support. For this example we assume a dev and test running mode. If we read the Spring Configuration manual we notice we can place the property files at many locations. This is what makes the Spring Configurator so flexible and useful.

First we create in the src/main/resources directory the following directories: META-INF/cocoon/properties/dev and META-INF/cocoon/properties/test. We create a sample.properties file in the src/main/resources/META-INF/cocoon/properties/dev directory. In the file we define:

sample.text=We are developing!

We save the file and if we run mvn test -Dorg.apache.cocoon.mode=dev we get the following output:

Running in [dev] mode. Text = [We are developing!].

The Spring Configurator has replaced our variable sample.text with the value from the property file. We also create a sample.properties file in the src/main/resources/META-INF/cocoon/properties/test directory and give a different value for the property:

sample.text=Ready for testing!

We run the test again, but now use the test running mode:mvn test -Dorg.apache.cocoon.mode=test. And we get this output:

Running in [test] mode. Text = [Ready for testing!]

Finally we create a sample.properties in the src/main/resources/META-INF/cocoon/properties directory with a default value, which is used by the default running mode (prod):

sample.text=We are alive!

We run mvn test and we see in the output:

Running in [prod] mode. Text = [We are alive!].

So in this part we have learned how to use property files for different running modes to replace variables in the Spring configuration files. In the next part we learn how override properties of beans defined in Spring configuration files.

Use Spring Configurator to support different dev, test and production environments with Spring configuration files (Part 1)

We develop an application usually on a development environment: our computer. Then the application gets deployed to a test environment to be tested by users. And finally we deploy the application to the production environment so the application is live. This scenario is the most simple one and can of course be more complicated with extra environments for integration testing or other things.

The Spring configuration files are usually different for each of the environments. For example we can define a database JDBC URL in the Spring configuration files for a development database, but that is different from the database JDBC URL in the production enviroment. Spring provides some kind of support with PropertyPlaceHolderConfigurer and PropertyOverrideConfigurer to define properties. But the Spring Configurator provides transparent support for Spring configuration in different environments or running modes.

Let's start with a simple example to get the Spring Configurator working. We create a new Maven project with the QuickStart archetype (mvn archetype:generate, choose the QuickStart archetype, groupId is com.mrhaki.spring.mavenapp and artifactId is springconfapp). We add the Spring configurator to the pom.xml dependencies section:

<dependency>
 <groupId>org.apache.cocoon</groupId>
 <artifactId>cocoon-spring-configurator</artifactId>
 <version>2.0.0</version>
</dependency>

Next we add a basic Spring configuration file to the src/main/resources directory with the name applicationContext.xml and the following contents:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:configurator="http://cocoon.apache.org/schema/configurator"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://cocoon.apache.org/schema/configurator http://cocoon.apache.org/schema/configurator/cocoon-configurator-1.0.1.xsd">

    <context:component-scan base-package="com.mrhaki.spring.mavenapp"/>
    <configurator:settings/>
</beans>

Notice at line 11 we set-up Spring to autodetect components in the com.mrhaki.spring.mavenapp package. And in line 12 we create the Spring Configurator settings object. We create a new Java class Sample in the com.mrhaki.spring.mavenapp package:

package com.mrhaki.spring.mavenapp;

import org.apache.cocoon.configuration.Settings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Sample {

    private Settings settings;

    @Autowired
    public void setSettings(Settings settings) {
        this.settings = settings;
    }

    @Override
    public String toString() {
        return "Running in [" + settings.getRunningMode() + "] mode.";
    }
    
}

For the example we add the Spring Configurator settings object as a property to the Sample class. In the toString() method we return the current environment that is used. Now we change the AppTest class and use our Sample class and display which running mode is used:

package com.mrhaki.spring.mavenapp;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppTest extends TestCase {

    public AppTest(String testName) {
        super(testName);
    }

    public static Test suite() {
        return new TestSuite(AppTest.class);
    }

    public void testApp() {
        final ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        System.out.println(appContext.getBean("sample"));
    }
}

Now if we run the test (mvn test) we get the following output:

Running in [prod] mode.

The prod running mode is the default running mode for the Spring Configurator if we don't do anything else. We can change the running mode by using the environment property org.apache.cocoon.mode. For example if we run the test again, but now use mvn test -Dorg.apache.cocoon.mode=dev we get the following output:

Running in [dev] mode.

This way we can easily change the running mode to be used. This is part 1 of the Spring Configurator. In the next part we will see how we can define and use properties for different environments.

Saturday, February 14, 2009

Enable JSP editor features for Maven webapp project in NetBeans

When we create a new Maven webapp project in NetBeans the JSP editing features are not enabled. If we open a JSP file we see the following error: Servlet API classes are not on the classpath, some scriplet editing features are disabled.

We need to add the Servlet API classes ourselves to the dependencies of our project. When the classes are in the classpath of our project we get complete code completion in our JSP editor. So how do we add the API classes? First we go to Window | Other | | Maven Repository Browser. We click on the Find icon on the right to search for the Servlet API. In the search dialog window we type javax.servlet and press the OK button:

NetBeans shows the search results in the Maven Repository Browser:

We need at least javax.servlet:servlet-api. We open this node and select versions 2.5[jar]. We right-click with the mouse and select Add Dependency to:

NetBeans opens a dialog window where we select our Maven webapp project and click the Add button.

This is enough to get some code completion in the JSP editor. To also get support for EL expressions we add the following libraries: javax.servlet.jsp:jsp-api and javax.servlet:jstl. Now when we return to our JSP editor we see how we can use code completion:

Finally to we can edit our pom.xml and set the scope of the added libaries to provided, because the application server we deploy the application to will already have these classes in the classpath.

Friday, February 13, 2009

Skip tests with Maven

Sometimes we just don't want to run the test of our projects. We can easily bypass the test with Maven. We must use the system property skipTests and that is it. So if we invoke

mvn install -DskipTests=true
then the testing phase will be skipped.

Wednesday, February 11, 2009

Unset main project in NetBeans

In NetBeans we can set a project to be a Main Project. We can use shortcut keys to run or debug a main project even if we are working on another project. To unset the Main Project we must go to Run | Set Main Project | None.

Dutch: Nieuwe klassieke muziek en cultuur portal van de AVRO

De AVRO heeft een nieuwe kunst- en klassieke muziek portal. Via deze portal kunnen we op zoek gaan naar evenementen via de cultuurgids. We kunnen ook audio- en videofragmenten bekijken van concerten en AVRO programma's die te maken hebben met kunst en klassieke muziek.

AVRO kunst- en klassieke muziek portal

Use Jetty to run Maven web applications in NetBeans

Jetty is a great web server. It is fast to start up and that makes it very useful during development. Jetty has a Maven plugin we can use in our Maven web application project. This way we can use Jetty to test our JSP files. We can change the JSP file and hit the Refresh button of our browser to see the result immediately. We can even compile a Java class file and Jetty will restart so we can test the result in our browser.

Let's see how we can do this in NetBeans. We go to File | New Project, select Maven Project and click the Next button.

In the next dialog window we select Maven Webapp Archetype and click the Next button.

Now we can fill in the values for our project and press the Finish button.

NetBeans creates a new project for us. To add Jetty Maven plugin we must open the pom.xml file for our project. In the build section we must add the following code:

<plugins>
 <plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>maven-jetty-plugin</artifactId>
  <version>6.1.14</version>
  <configuration>
   <scanIntervalSeconds>5</scanIntervalSeconds>
  </configuration>
 </plugin>
</plugins>

At line 6 we define how often Jetty will scan the source directories to look for changes. Because we add this definition we can change JSP files and see the result in our web browser without restarting the server.

Okay, we have defined Jetty for our project, but how can we run Jetty in NetBeans? We go to File | Project Properties and select the Actions category. We must look for the action Run project and select it. In the Execute goals field we add jetty:run. This will start Jetty if we run our project. We can close the dialog window.

Now we go to Run | Run Project to start Jetty. In the Output window of NetBeans we see the following text:

Starting jetty 6.1.14 ...
2009-02-11 10:20:20.610::INFO:  jetty-6.1.14
2009-02-11 10:20:20.982::INFO:  No Transaction manager found - if your webapp requires one, please configure one.
2009-02-11 10:20:21.335::INFO:  Started SelectChannelConnector@0.0.0.0:8080
Started Jetty Server
Starting scanner at interval of 5 seconds.

At line 3 we see Started SelectChannelConnector@0.0.0.0:8080 this means Jetty is available at port 8080. We open a web browser and open http://localhost:8080/webappjetty/ and we see the following:

We go back to NetBeans and open the file index.jsp. We add the following to the file:

<h3>It works!</h3>

We switch back to our web browser and reload the page and we get:

Monday, February 9, 2009

Weekly Sightings

http://preloaders.net/
Web page to easily create preloader GIF animations that can be used for AJAX requests from a web page.

Thursday, February 5, 2009

Use Spring or Acegi security to protect RESTful webservices

Simple protection of RESTful webservices is accomplished by using HTTP Basic authentication. We can use Acegi 1.x or Spring 2.x security to define an URL pattern to protect with a username and password. For example we have developed a RESTful webservice with the URI /resources/articles and we want to protect it with a username and password. Let's look at the necessary Spring definition to achieve this with Acegi 1.x security:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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.xsd">

    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
        <property name="filterInvocationDefinitionSource">
            <value>
              <![CDATA[
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /resources/**=httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationWithASCFilter,filterInvocationInterceptor
              ]]>
            </value>
        </property>
    </bean>

    <bean id="httpSessionContextIntegrationFilterWithASCFalse"
        class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
        <property name="allowSessionCreation" value="false"/>
    </bean>

    <bean id="exceptionTranslationWithASCFilter"
        class="org.acegisecurity.ui.ExceptionTranslationFilter">
        <property name="createSessionAllowed" value="false"/>
        <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
        <property name="accessDeniedHandler">
            <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl"/>
        </property>
    </bean>

    <bean id="basicProcessingFilter" class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">
        <property name="authenticationManager">
            <ref bean="authenticationManager"/>
        </property>
        <property name="authenticationEntryPoint">
            <ref bean="authenticationEntryPoint"/>
        </property>
    </bean>

    <bean id="filterInvocationInterceptor"
        class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
        <property name="objectDefinitionSource">
            <value>
            <![CDATA[
                CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
                PATTERN_TYPE_APACHE_ANT
                /resources/**=ROLE_ADMIN
            ]]>
            </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" ref="inMemoryDaoImpl" />
        <property name="forcePrincipalAsString">
            <value>true</value>
        </property>
    </bean>

    <bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
        <property name="userMap">
            <value>
                <![CDATA[
                    admin=crypticpassw,ROLE_ADMIN
                ]]>
            </value>
        </property>
    </bean>

    <bean id="authenticationEntryPoint" class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
        <property name="realmName">
            <value>Restricted resources</value>
        </property>
    </bean>

    <bean id="httpRequestAccessDecisionManager" class="org.acegisecurity.vote.AffirmativeBased">
        <property name="allowIfAllAbstainDecisions" value="false"/>
        <property name="decisionVoters">
            <list>
                <ref bean="roleVoter" />
            </list>
        </property>
    </bean>

    <bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter"/>

</beans>

This is just a basic configuration. To learn more about the different components see the official Acegi 1.x reference documentation. For now the most important thing to remember is that we don't need HTTP sessions to be created when invoking a RESTful webservice. We don't want this to happen, because it will take up a lot of resources on the server and eventually our application can become very slow. The nice thing about a RESTful webservice is that it doesn't need an HTTP session to work correctly. But to accomplish this we must tell Acegi explicitly we don't want HTTP sessions to be created. If we don't, Acegi will create an HTTP session to save authentication information.

When we look at the configuration we notice at line 11 we reference httpSessionContextIntegrationFilterWithASCFalse and exceptionTranslationWithASCFilter. The definition can be found at lines 17 and 22. Here we assign the property allowSessionCreation the value false. Now Acegi will no longer create an HTTP session to save authentication information and that is exactly we wanted to achieve!

Spring 2.0 security is the new Acegi security, but we can use namespaces to configure the security which results in a much easier to read configuration file:

<?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:util="http://www.springframework.org/schema/util"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
                           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.4.xsd">

    <security:http create-session="never" auto-config="false" realm="Restricted resources">
        <security:intercept-url pattern="/resources/**" access="ROLE_ADMIN"/>
        <security:http-basic />
        <security:logout />
    </security:http>
    
    <security:authentication-provider>
        <security:user-service>
            <security:user name="admin" password="crypticpassw" authorities="ROLE_ADMIN"/>
        </security:user-service>
    </security:authentication-provider>

</beans>

Wow that is much easier to read (and maintain) than the previous configuration. To read more about the configuration options see the official Spring 2.0 security reference documentation. At line 9 we assign the attribute create-session the value never to make sure no HTTP session is created when using the RESTful webservice.

Wednesday, February 4, 2009

Add session identifier to request logging in Tomcat

In a previous article we learned how to enable request logging in Tomcat. The format of the log is the same as for standard web servers. If we look at conf/server.xml and the Valve element for the request logging we see the attribute pattern. This is set to common, which is the default format.

We can change the format by changing the pattern attribute. For example if we want to add the session identifier we must add %S to the pattern. For example we can use the following pattern: %h %u %S %t '%r' %s %b %D. The complete element now looks like this:

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
  prefix="localhost_access_log." suffix=".log"
  pattern="%h %u %S %t '%r' %s %b %D" resolveHosts="false"/>

The Tomcat documentation contains more information about request logging and the different patterns.

Enable access logging in Tomcat

Tomcat can log our requests to the server in a log file. This way we can see which pages are invoked, from which IP address and more. To enable request logging We need to open conf/server.xml of our Tomcat instance. We then look for a Valve element where the className attribute has the value org.apache.catalina.valves.AccessLogValve. Probably this element is enclosed in a XML comment. We need to remove the comment so Tomcat can recognize the element. We save the server.xml file and start Tomcat. In the logs directory we get the logfile localhost_common_access_log.2009-02-04.txt. And this file contains all requests made to Tomcat.

Sunday, February 1, 2009

Get the edit link for a Google Calendar with the Google Data Java Client API

The Google Data Java Client library contains samples on how to add or change events for the private calendar of an user. But what if we want to add or change events to a new calendar we created ourselves? I found the information in this article. The author shows an example with the REST API. Here we will see an example with Java code:

final CalendarService calendarService = new CalendarService("mrhaki.com-blogsamples-1.0");
calendarService.setUserCredentials("user@gmail.com", "password");
final URL feedUrl = new URL("http://www.google.com/calendar/feeds/default/owncalendars/full");
final CalendarFeed calendarFeed = service.getFeed(feedUrl, CalendarFeed.class);
for (CalendarEntry entry : calendarFeed.getEntries()) {
  System.out.println("edit link: [" + entry.getLink(Link.Rel.ALTERNATE, Link.Type.ATOM).getHref() + "]");
}

We get the link to invoke the getLink() method with the correct parameters. We can use this link to create an event for the specific calendar:

final URL postURL = new URL(entry.getLink(Link.Rel.ALTERNATE, Link.Type.ATOM).getHref());
final CalendarEventEntry entry = new CalendarEventEntry();
entry.setTitle("Entry for my new calendar");
entry.setContent("Sample content.");
final When event = new When();
event.setStartTime(DateTime.now());
entry.addTime(event);
service.insert(postURL, entry);

Add Google Data Java Client library to NetBeans

The Google Data API is available as Java client library. With this library we can invoke Google Data services via simple Java calls. To add the Google Data Java Client libary to NetBeans we must first download the latest library from the Google Data API site. We must unpack the ZIP file to a directory on our local computer.

In NetBeans we go to Tools | Libraries to create a new Class library. We must click on the New Library... button and Netbeans open a dialog window. In this window we type in the name of our library: GoogleDataJavaAPI and leave the Library Type to Class Libraries.

We click the OK button and NetBeans closes the dialog window. Now we can set the Classpath for the library. This must contain all the JAR files belonging to the Google Data Java Client. So we click on the Add JAR/Folder... and browse to the directory where we unzipped the Google Data Java Client zip file. We open the lib folder and select all files:

To complete the library definition we can also add the Sources and Javadoc so we can get the most information in the Java editor:

Add an all-day event to Google Calendar with Google Data Java API

The Google Data API contains the DateTime class for specifying a date and time value. But what if we don't care about the time, because we want to create an all-day event? That is easy, we must use the setDateOnly method. Here is a little code snippet which shows this:

import com.google.gdata.data.DateTime;
import java.util.Date;

final DateTime date = new DateTime(new Date());
date.setDateOnly(true);