Showing posts with label howto. Show all posts
Showing posts with label howto. Show all posts

Tuesday, 20 November 2007

How to color Datagrid cells/rows in flex 2

I have been looking for a easy and neat way to color a single cell or a complete row in flex 2.

Google brought me two interesting links:

1. How opaqueBackground can be used to color the background of a label itemRenderer
The comment posted by Dallas at 11/10/06 8:01, shows a way of highlighting a cell. Very simple implementation - the only problem is that the background color won't react on mouseover after the opaqueBackground is set.

2. How do you change the background cell color in a DataGrid?
Shows how to implement a colored background that react upon mouseover and selection. The implementation extends a label and overrides the 'updateDisplayList' method to draw some graphics as the background.
The last solution seems to be the one I preferred - because of the ability to see mouse effects applied to the cell. But still I liked the cleen implementation of the first one.

I couldn't resist of bringing combined solution, where I extends a Label, but listens for a Event.RENDER events instead of overriding the updateDisplayList method.

Sample Application


Sourcecode
Demonstrates how to use the renderer as a drop-in and inline itemRenderer.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
layout="vertical" verticalAlign="middle" xmlns:tmp="component.dashboard.*"
creationComplete="init()">

<mx:Script>
private function init() : void {
myGrid.setFocus();
}
</mx:Script>
<mx:XML id="itemsXML">
<items>
<item name="Item 1" state="1" />
<item name="Item 2" state="0" />
<item name="Item 3" state="0" />
<item name="Item 4" state="1" />
<item name="Item 5" state="0" />
</items>
</mx:XML>

<mx:Style>
.centered {
text-align: center;
}
</mx:Style>

<mx:DataGrid id="myGrid" dataProvider="{itemsXML.item}" editable="true">
<mx:columns>
<mx:DataGridColumn dataField="@name" headerText="Name"
headerStyleName="centered"
itemRenderer="component.dashboard.TestItemRenderer"/>

<mx:DataGridColumn dataField="@state" headerText="Price"
textAlign="right" headerStyleName="centered">
<mx:itemRenderer>
<mx:Component>
<tmp:TestItemRenderer/>
</mx:Component>
</mx:itemRenderer>
</mx:DataGridColumn>
</mx:columns>
</mx:DataGrid>

</mx:Application>


CustomItemRenderer.as
Following is a CustomItemRenderer that can be extended to apply logic to decide if a cell is to be styled.

package dk.jacobve {

import mx.controls.Label;
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.*;
import mx.events.FlexEvent;
import flash.events.Event;

public class CustomItemRenderer extends Label {

public function CustomItemRenderer {
//listen for render events
addEventListener(Event.RENDER, renderListener);
}

public function styleIt() : Boolean {
return false;
}

public function styleTrue() : void {
}

public function styleFalse() : void {
}

protected function renderListener(event:Event) : void {
if (listData != null) {
var grid:DataGrid = DataGrid(DataGridListData(listData).owner);
if (!grid.isItemHighlighted(data) && grid.selectedItem != data) {
if (styleIt()) {
styleTrue();
} else {
styleFalse();
}
} else {
styleFalse();
}
}
}
}
}


CustomItemRenderer extension
Shows an implementation using E4X on a xml data element to deside if the cell is to be colored red.

package dk.jacobve {

import mx.controls.Label;
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.*;
import mx.events.FlexEvent;
import flash.events.Event;

public class TestItemRenderer extends CustomItemRenderer {
public override function styleIt() : Boolean {
return data.@state == "0";
}

public override function styleTrue() : void {
this.opaqueBackground = 0x33CC33;
}

public override function styleFalse() : void {
this.opaqueBackground = null;
}
}
}

Thursday, 1 November 2007

Quickstart flex development with this maven archetype

Have you considered starting some flex development, but haven´t found out where to start? Or are you already flex'ing but could use some easy way to quickstart new flex projects in java?

I have created a maven archetype called maven-archetype-flex and distributed it to ibiblio for all to use.
It will quickly get you up and running.

Here is how you do it:

1. Download flex sdk
Download the flex sdk from adobe, if you haven't got it already.

1b. Minor change to flex-config.xml
You have to uncomment the following in your flex-config.xml located in:

${flex.home}/frameworks/flex-config.xml
<local-fonts-snapshot>localFonts.ser<local-fonts-snapshot>
Otherwise the compiler will complain as Matt mentions in his comment.

2. Create flex project
Running the following maven command will create a flex project called my-flex having groupId my.group. Feel free you change these to what ever you like:
mvn archetype:create
-DarchetypeArtifactId=maven-archetype-flex
-DarchetypeVersion=1.0
-DarchetypeGroupId=dk.jacobve.maven.archetypes
-DgroupId=my.group
-DartifactId=my-flex
-DpackageName=
Note: it is important that you remember the -DpackageName= as the Main.mxml flex file in the archetype is to be kept in the root of your source dir and not in some subpackage.

3. Set flex.home property
In the newly created project pom.xml you should change the flex.home property to fit your flex.home path.

4. Build flex project
Now you are ready to build the flex project:
mvn install
Running this command inside your project will build the project and create a swf file in the target directory.

Viola! You have just created a simple flash application ready to use.

Where to go from here
To see the result of the work you can do one of the following things:
  • Open the flash file with your favorite browser.
  • Download the standalone player for your operating system ().
  • Deploy the swf file to a webserver. Maybe you can get inspiration on how to do it from this maven flex template.

Thursday, 25 October 2007

Advanced inputfiltering with flex

All the time I have been developing web applications in Java I have build my UI upon some framework like Struts, Tapestry or JSF. All of these frameworks encourage serverside validation and to some extend clientside validation.
I haven't seen a web framework facilitating a prober way to do input filtering. The few times I have implemented an inputfilter I have cooked up some javascript to do the job - normally not that reusable.
I don´t see filtering as a substitution of server side validation, but more as an extension of the user experience where the user gets immediate feedback on her use of an application.

At my current project we build the UI on the flash runtime in flex - and the flex framework really brings some interesting opportunities.

Basic
For basic filtering a restrict property can be set on the TextInput component only allowing a subset of characters as input.
But as soon as your inputfilter depends on already entered text the filtering gets a bit more sophisticated :-)

Advanced
On the TextInput you can listen for a TextEvent that contains the data the user is entering as input but react upon it before it actually hits the input field. That gives you the opportunity to prevent the input from reaching the Textinput component by calling the preventDefault() method on the event if the data isn't allowed for some business rule that you apply.

public class FilterTextInput extends TextInput {

public function FilterTextInput() {
addEventListener(TextEvent.TEXT_INPUT, validateInput);
}

private function validateInput(event : TextEvent) : void {
var actualInput : String = EventUtil.getActualText(event);
trace(actualInput);
//sample filtering securing that all input characters are unique
if (! StringUtil.containsUniqueChars(actualInput)) {
event.preventDefault();
}
}
}

Unfortunately the event only contains the data the user is about to enter. So if you would like to validate the entire input as it would be after when the input is combined with the already entered text, you have to do some work yourself.


EventUtil
I implemented an EventUtil class capable of extracting the actual input as it would look like when the already entered text is combined with the incoming input (the method used in the sample above). The tricky part is to take notice of where in the existing text the new input is about to be entered. The input could replace some existing text and at the same time be pasted into the middle of an existing text.

My utility method looks like this:
public static function getActualText(event : TextEvent) : String {
var input : TextInput = TextInput(event.currentTarget);
var text : String = input.text;
var b : int = input.selectionBeginIndex;
var e : int = input.selectionEndIndex;

var before : String = "";
var after : String = "";
if (e > 0) {
before = text.substring(0, b);
}
if (b < text.length) {
after = text.substring(e, text.length);
}
return before + event.text + after;
}

A simple example illustrating the use of function getActualInput(). The filter prevents the user from entering the same character twice:

Thursday, 6 September 2007

Easy syntax highlight embedded code on your blog

For some time I have been looking for a easy way to syntax highlight code snippets on my blog as my default stylesheet seems to do a bad job.

I came across tools like:

But the one I found most interesting is google-code-prettify that Hung Huynh recommended me.

Prettify only requires you to include a small stylesheet and a single javascript file containing the code doing the hard work - see the simple readme
Then you just surround you code with - say <pre class="prettyprint"> and voila! your code is syntax highlighted.

I have updated some of my older posts so you can see the prettifier in action:

Thursday, 30 August 2007

How to implement remember me using acegi

I have extended the example application showing how to do form based login using acegi.

You need to apply the following changes to the securityContext.xml:

securityContext.xml (download)

Remember me beans:

<!-- remember me processing filter -->
<bean id="rememberMeProcessingFilter"
class="org.acegisecurity.ui.rememberme.RememberMeProcessingFilter">
<property name="rememberMeServices" ref="rememberMeServices" />
<property name="authenticationManager" ref="authenticationManager" />
</bean>

<bean id="rememberMeServices"
class="org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices">
<property name="userDetailsService"> <ref local="memoryAuthenticationDao"/>
</property>
<property name="key" value="someTokenName"/>
</bean>

<bean id="rememberMeAuthenticationProvider"
class="org.acegisecurity.providers.rememberme.RememberMeAuthenticationProvider">
<property name="key" value="someTokenName"/>
</bean>
Apply the following changes to existing beans:
Add the rememberMeServices to the logoutfilter for the logout filter to invalidate the remember me cookie.
<bean id="logoutFilter"
class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg index="0" value="/index.jsp"/>
<constructor-arg index="1">
<list>
<ref local="securityContextLogoutHandler"/>
<ref local="rememberMeServices"/>
</list>
</constructor-arg>
</bean>

Add the rememberMeProcessingFilter to the filterchain for the remember me checks to be performed when a user hits a acegi protected URI:
<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,rememberMeProcessingFilter,authenticationProcessingFilter,logoutFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>

Also remember to set the rememberMeServices at the authenticationProcessingFilter to overwrite the default NullRememberMeServices with your rememberMeServices. That will provide acegi with a service to handle remember me token validation (took me a bit of debugging to find this error)
<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureUrl" value="/index.jsp?login_error=1"/>
<property name="defaultTargetUrl" value="/secure/securecontent.jsp"/>
<property name="filterProcessesUrl" value="/j_acegi_security_check"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
</bean>


Finally extend your login form with a checkbox to let your end user be remembered. The default parameter name is _acegi_security_remember_me:
<tr>
<td>Remember me:</td>
<td><input type="checkbox" name="_acegi_security_remember_me"/></td>
</tr>
Sample (download)
I also provided a simple webapp demonstrating the implementation, just:
  1. download
  2. unzip
  3. type $mvn jetty:run
  4. go to: http://localhost:8080/basicAcegiExample
  5. type user, password as credentials

Monday, 27 August 2007

How to implement formbased authentication with acegi - no container dependencies

I couple of days ago I implemented a sample application illustration the minimal configuration needed for doing basic authentication using acegi. I have decided to take the next step and show a sample of a form based authentication solution - still without any container dependencies. Having no dependencies to a specific container seems to gain a bit of momentum in the Java community these days and Per wrote a interesting blog about keeping your deployment thin and lightweight.

Based on my last basic authentication example you only need to change the following:

See securityContext.xml (download)

ProcessingFilter
Switch the basicProcessingFilter with this one:

<!-- Processes formbased authentication.
The html form should contain to input fields: j_username and j_password.
The post of the form should point at the value of the "filterProcessesUrl"
in this case /j_acegi_security_check -->

<bean id="authenticationProcessingFilter"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureUrl" value="/index.jsp?login_error=1"/>
<property name="defaultTargetUrl" value="/secure/securecontent.jsp"/>
<property name="filterProcessesUrl" value="/j_acegi_security_check"/>
</bean>

Also remember to change the use in your filterChainProxy.
...
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
...
AuthenticationEntryPoint
Switch authenticationEntryPoint with this:
<!-- changed to work with formbased login -->
<bean id="authenticationEntryPoint"
class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
<property name="loginFormUrl" value="/index.jsp"/>
</bean>
Further I changed the UserDetailsService as my own implementation could be swapped with an org.acegisecurity.userdetails.memory.InMemoryDaoImpl and still be a lightweight in memory userdetails implementation for the sake of the example:
<!-- implemented memory dao -->
<bean id="memoryAuthenticationDao"
class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>user=password,USER</value>
</property>
</bean>
Logout
Contrary to basic authentication you are able to let the user logout without closing the browser.

Add the following logoutFilter to the filterChainProxy
...
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,logoutFilter,exceptionTranslationFilter,filterInvocationInterceptor
...
and create a logout handler like the SecurityContextLogoutFilter:
<bean id="logoutFilter" class="org.acegisecurity.ui.logout.LogoutFilter">
<constructor-arg index="0" value="/index.jsp"/>
<constructor-arg index="1">
<list>
<ref local="securityContextLogoutHandler"/>
</list>
</constructor-arg>
</bean>

<bean id="securityContextLogoutHandler"
class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler" />
This snippet will handle a logout when the user requests the /j_acegi_logout that is the default url. Can be changed as a parameter to the logout filter.

Actually I found this api documentation for the BasicProcessingFilterEntryPoint indicating that it is possible to logout using basic authentication without killing the browser:
/**
* Used by the <code>SecurityEnforcementFilter</code> to commence authentication via the {@link
* BasicProcessingFilter}.<P>Once a user agent is authenticated using BASIC authentication, logout requires that
* the browser be closed or an unauthorized (401) header be sent. The simplest way of achieving the latter is to call
* the {@link #commence(ServletRequest, ServletResponse, AuthenticationException)} method below. This will indicate to
* the browser its credentials are no longer authorized, causing it to prompt the user to login again.</p>
*
* @author Ben Alex
* @version $Id: BasicProcessingFilterEntryPoint.java 1877 2007-05-25 05:33:06Z benalex $
*/
I tried the suggested commence solution in my basic autentication example, but did not have success. If you are able to implement the commence solution let me know.

Sample (download)
I also provided a simple webapp demonstrating the implementation, just:
  1. download
  2. unzip
  3. type $mvn jetty:run
  4. go to: http://localhost:8080/formbasedAcegiExample
  5. type user, password as credentials
Next step
Using formbased login you can easy implement "remember me" functionality. In a couple of days I will have a sample for that as well. I will update this post with a link when the time comes. I have implemented a remember me example and it is available here.

Further documentation

Tuesday, 14 August 2007

How to implement basic authentication with acegi - no container dependency

I have always implemented basic authentication by depending on a specific container implementation - always with the drawback of not being able to easy switch between containers in development, test and production.
Now I stood in front of another implementation and decided to look into Acegi's possibilities. If Acegi could provide a basic authentication mechanism bundled in my application I could get rid of the container dependency.
I did use Acegi on one other project to do form based login, but at that time the API changed between each little minor release making it a pain to upgrade.
Now they promise to keep the API stable so I thought it was about time give it a new fair chance to improve the first impression I got.

And I must say it did!

Following is a simple securityContext.xml needed to perform basic authentication using spring and acegi.
I provided a very simple UserDetailsService for the sake of the example. You should probably be using the
org.acegisecurity.userdetails.jdbc.JdbcDaoImpl implementation instead - or any other implementation that suites your setup.

securityContext.xml (download)

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

<!-- ======================== FILTER CHAIN ======================= -->

<bean id="filterChainProxy"
class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=httpSessionContextIntegrationFilter,basicProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>

<!-- responsible for setting up a security context holder for other
authentication mechanisms to work with -->
<bean id="httpSessionContextIntegrationFilter"
class="org.acegisecurity.context.HttpSessionContextIntegrationFilter">
<!-- no session should ever be created. We are processing basic
authentication credentials on each request -->
<property name="allowSessionCreation" value="false"/>
</bean>

<!-- Processes basic authentication headers and works together with the
provided authentication manager and
entry point to perform basic authentication -->
<bean id="basicProcessingFilter"
class="org.acegisecurity.ui.basicauth.BasicProcessingFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationEntryPoint"
ref="authenticationEntryPoint"/>
</bean>

<!-- filter responsible for access decisions. What urlrequests may be
processed by which roles -->
<bean id="filterInvocationInterceptor"
class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager">
<ref local="httpRequestAccessDecisionManager"/>
</property>
<property name="objectDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=USER
</value>
</property>
</bean>

<!-- filter responsible for translating exceptions and delegating to the
provided authenticationEntryPoint -->
<bean id="exceptionTranslationFilter"
class="org.acegisecurity.ui.ExceptionTranslationFilter">
<property name="authenticationEntryPoint"
ref="authenticationEntryPoint"/>
</bean>

<!-- ======================== AUTHENTICATION ======================= -->

<bean id="authenticationEntryPoint"
class="org.acegisecurity.ui.basicauth.BasicProcessingFilterEntryPoint">
<property name="realmName" value="Protected atlight"/>
</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="simpleUserDetailsService"/>
</bean>

<!-- a simple simple UserDetailsService -->
<bean id="simpleUserDetailsService"
class="com.blogspot.ancientprogramming.security.SimpleUserDetailsService" />

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

<bean id="roleVoter" class="org.acegisecurity.vote.RoleVoter">
<property name="rolePrefix" value=""/>
</bean>
</beans>


web.xml
Together with this spring, acegi configuration in your web.xml you are up and running.
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
<display-name>Archetype Created Web Application</display-name>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/securityContext.xml</param-value>
</context-param>

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

<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

Sample (download)
I also provided a simple webapp demonstrating the implementation, just:
  1. download
  2. unzip
  3. type $mvn jetty:run
  4. go to: http://localhost:8080/basicAcegiExample
  5. type user, password as credentials