Spirals with HTML5 Canvas – Rectangle, Image, and Text

Summary

The purpose of this post is to show some basics of HTML5 and I also wanted to see how fast some basic HTML5 would render under different browsers. I suggest viewing this on Chrome, Firefox, Safari, and phone browsers to see how it runs to draw your own conclusions. Also there appears to be some redraw issues with the text spiral, if you resize your browser it will usually fix this.

For the first example we will Spiral a box:

Basic Box Spiral

So first we setup our canvas element in the html body:

<canvas id="cpCanvas" width="1000" height="1000"></canvas>

We give the canvas an id so we can use it in JavaScript by calling the getElementById function then we get the 2d context from the canvas object. Further we setup a fillStyle that uses an rgb (red green blue) setup, then draw the rectangle using fillRect with x,y,width, and height parameters:

	
  var canvas = document.getElementById("cpCanvas");
  var ctx = canvas.getContext('2d');

  ctx.fillStyle = "rgb(255,0,0)"; // Setup a fill style
  ctx.fillRect(x,y,width,height);		
  ctx.rotate(5); // Finally we rotate (creating a transformation that is cumulative for multiple calls - if we used save and restore methods on the canvas we wouldn't see the spiral
  setTimeout("draw()",10); // Call this function again in 10 milliseconds

Image Spiral

Loading an image is slightly more complex, we can use images that already exist in the DOM or we can create a new Image() object instance and assign it a source. We will need to give it an onload function that can kick off our drawing once the image has been loaded as well:

  var image = new Image();

  function bodyLoad() {
    image.onload = function() {
      draw(); // kick off the redrawing once the image is ready
    };
    image.src = "logo.png"; // start the loading of the logo.png file
}

Finally we need to use the context drawImage function with the image object and a x and y position:

  var canvas = document.getElementById("cpCanvas");
  var ctx = canvas.getContext('2d');
  ctx.drawImage(image,x,y);

Text Spiral

My last example uses the fillText function and sets the font on the context to 20pt Arial and give it an x and y parameter for positioning:

  ctx.font = "20pt Arial";
  ctx.fillText("This is HTML5 on CrystalPlatform.com",x,y);

My first impression of HTML5 is the Canvas adds a lot of functionality for 2D and 3D drawing to basic HTML. In its current form I would still go with the Flash Platform for better performance, a great workflow, and not having to worry about browser incompatibility. While Flash is still my optimal choice for fast web based graphics, I would use HTML5 for platforms that don’t support Flash such as iOS.

Posted in Uncategorized | 1 Comment

Stack it up – Android AIR Flex Robot Legs BlazeDS Java Tomcat Spring/Spring Security Hibernate ORM MySQL – Massive Mobile Apps

Summary

The purpose of this blog is to show a front to back integration using a mobile Flex AIR application to talk to a backend Tomcat Java server which uses an ORM for talking with the database. All of this information can be found in bits and pieces across multiple websites, but finding it all together was very hard for me so I have tried to provide this information in a centralized spot. This post might be useful to someone that wants to create a cross platform application that can scale for many users while being secure. This is what I would consider a skeleton project, while much of the config is setup and the code is available, it is definitely not done. The UIs need a lot of refinement, I know this, and while I will clean this up for my own application, that is not the purpose of this post. This hopefully will allow others to get up and running quicker and spend more time coding the functionality that really pertains to their application. There is a lot of information here and assumes a lot of knowledge in a lot of areas, I will try to make more concise posts in the future on some of the topics listed here. I posted a lot of code here, and hopefully it will be searchable by Google and other engines so if someone is having a problem with a particular piece of functionality, my hope is this will be helpful.

Let’s Get Started

This stack is pretty large, and I would like to implement all these technologies without too much of a problem. I have been working the past few weeks to try and familiarize myself with Spring and Hibernate, as majority of my development lately has been using Flex. I have worked with Java and JDBC in the past quite a bit, but not Spring and Hibernate ORM. Please note there might be better ways to some of this, this is a basic implementation and should be scaled appropriately. I have tried to explain most of what I did here, you can download the code here. You will need to find the library dependencies for the java project and download Robot Legs for Flex. Maybe once I get up to speed on Maven I will provide something for this. I apologize in advance for typos, I am trying to convey a large amount of information quickly, and it is already 19 pages, most of which is code.

An image of it running on Droid 2:

I have released this under the Apache 2.0 License:

By downloading this software, using any of the code snippets, or using the demo application you agree to the following:

Copyright 2010 Crystal Platform LLC

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Demo
View the Demo, use username test password test, or create your own username and password
Download
Download the code here, you will need to get the libs (I have put a list in the java lib and Flex libs directory of what you need)

Architecture Diagrams

This assumes a basic knowledge of Flex, if you need that I would suggest the Flex in a Week video training, it is easy to get quickly up to speed, at that point I would suggest reading heavily on how the Flash display model works and The Flex component lifecycle (and lookup the articles on the elastic racetrack). I am using the Robot Legs frameworks here, there are many frameworks others have writen for Flex – Cairngorm, Parsely, PureMVC, Mate, Swiz, Spring ActionScript. I have mainly seen PureMVC used, though I know Cairngorm and Parsley are used heavily in certain circles. Why did I use Robot Legs – I wanted dependency injection in Flex, but I wanted a light framework that I don’t need a lot of other functionality. Also a framework needs to be easily understood for all working on the project, otherwise the framework can be a bane rather than a boon.

*** NOTE: This does not use the new Flex Hero SDK which is supposed to be better for mobile development, I was writing the article right before Adobe MAX then Flash Builder “Burrito” and the Flex 4.5 Hero SDK announcement came out, so deploying to Android is quite a bit easier, this still works though, but in my example I am packaging a web application and not an AIR app, so you don’t get a lot of the AIR SDK.

http://www.adobe.com/devnet/flex/videotraining.html

A little vocabulary to get you going:

Flex – a SDK built on top of the Flash Platform that compiles to Flash Player or AIR.

Robot Legs – a MVCS (Model View Controller Service) architecture that allows dependency injection within Flex. I have used PureMVC most of my Flex career, a big fan of PureMVC, but really enjoy Robot Legs for a light (for doing reflection) dependency injection framework.

Spring – a very powerful java framework – which I am sure I am way underutilizing – notable features Dependency Injection – lets you wire objects together with less boilerplate code, AOP – Aspect Oriented Programming (this allows you to apply functionality across your application classes without adding code to each class), Spring Security – a very powerful way to secure your backend, Transactions, takes care of the commit and rollback of the database for you (this is over simplifying and will most likely bring comments).

Hibernate – an ORM (Object Relational Mapping) – this thing is incredible, it manages the interaction between the applications objects and the database (MySQL in this case).

BlazeDS – message system that lets ActionScript objects turn into Java objects and Java objects into ActionScript objects. More features as well – polling, streaming, push messaging.

RDS – Blaze DS Discovery Service (think this stands for Remoting Discovery Service, somebody please correct me if I am wrong), this allows Flash Builder (formerly Flex Builder) to connect into the Blaze DS java services (denoted buy the @Service connation in Spring) and allows you to test connections and generate forms that attach to the back end.

1. Setting up the front end piece

Using dependency injection from Robot Legs in Flex. Make the property public and use the [Inject] tag.


	public class LoginCommand extends Command
	{
		[Inject]
		public var userService:UserService;
		
		[Inject]
		public var event:SendLoginEvent;		
		
		override public function execute():void
		{
			var popupVO:PopupVO = new PopupVO();
			popupVO.title = "Logging in, Please wait";
			this.dispatch(new PopupEvent(PopupEvent.SHOW,popupVO));
			userService.login(event.loginVO);
		}
	}


 

This Inject metadata tag tells the system to inject the userService and event into the command as needed by the framework. When the method execute is called, the dependencies have already been injected so the objects can be used as needed.

Robot Legs use an Model View Controller Service (MVCS) model. Mediators adapt the view layer to the rest of the system. So typically, a user clicks a button on the view, that event is passed to a mediator. The mediator then sends out another system event to carry out an action. In the instance above when the login button is clicked on the view, it sends out a system event which is handled by this command, the command then takes and makes the necessary service call. When the service is ready it will send out another system event with the data it received and the system can act on it as needed, for example:


	public class LoginCompleteCommand extends Command
	{
		public static const COMPLETE:String = "loginComplete";
		
		[Inject]
		public var loginSuccessfulEvent:LoginSuccessfulEvent;	
		
		[Inject]
		public var userProxy:UserModel;
		
		override public function execute():void
		{						
			userProxy.userVO = this.loginSuccessfulEvent.userVO;	
			this.dispatch(new Event(ShowNavigatorViewCommand.SHOW));
		}
	}


This command updates the model with the value from the service layer, and then sends out another system event to show a view. In Robot Legs, the System maps these values in the Context – for our earlier example, to setup these mappings:


injector.mapSingleton(UserService); // Maps the user service singleton for injection

mediatorMap.mapView(LoginView, LoginMediator); // Maps the login view to the login mediator, allows us to inject the view

commandMap.mapEvent(ShowLoginViewCommand.SHOW, ShowLoginViewCommand); // Allows us to show the login view                                     

// Map the login

commandMap.mapEvent(SendLoginEvent.LOGIN, LoginCommand);                                                                     

commandMap.mapEvent(LoginSuccessfulEvent.SUCCESS, LoginCompleteCommand);

commandMap.mapEvent(LoginFailEvent.FAIL, ShowLoginFailCommand);

In our main application we map the Context like this:


      <fx:Declarations>

            <context:ExpensesContext contextView="{<strong>this</strong>}" />

      </fx:Declarations>

Something I find neat about this framework as well is, once a mapped view is added to the stage, it creates the mediator, so the power of the MXML is not lost through this framework. I can create complex hierarchies within an MXML (granted deep nesting of components is a bad idea, specially with mobile, but hopefully I am making my point here that it keeps the view layout logic readable and understandable from a Flex perspective.)

A couple of notes to pushing to a Droid 2 on Android:

Packaging, apk is the android install file, crystalPlatform.p12 is my certificate I generated through Flash Builder for an air project (I am forced to create a password, so running the following command will ask me for that password).

Building package:

adt -package -target apk -storetype pkcs12 -keystore crystalPlatform.p12 ExpensesApp.apk ExpensesApp-app.xml ExpensesApp.swf

Installing the package:

adt -installApp -platform android -package ExpensesApp.apk

Removing the package:

adt -uninstallApp -platform android -appid ExpensesApp

2. Setting up the backend

Tomcat SSL setup: Go to the JDK bin (or add it to the path and type the following)

keytool -genkey -alias tomcat -keyalg RSA

It will ask you for a password (make sure you get this right, otherwise you will have to go into your users\(username) directory and delete the .keystore file)

Give it the rest of the information, this is a locally generated certificate make sure you go live you get one from a real trusted authority.

Edit the server.xml included with tomcat to uncomment the SSL connect, and make sure you add the


<Connector className="org.apache.catalina.connector.http.HttpConnector"
           port="8443" minProcessors="5" maxProcessors="75"
           enableLookups="true"
           acceptCount="10" debug="0" scheme="https" secure="true"
           clientAuth="false" protocol="TLS" keystorePass="[Put your password here]"
</Connector>

I have tried to make commends throughout the web xml and the spring context file. The configuration here is the hardest part.

The basic pieces/dependencies to this are:

The Spring Framework and The Spring / BlazeDS integration

Spring Security – this allows us to use the @Secured annotations, for method level security and optionally setup tomcat page security before allowing access to our RIA.

Hibernate and Hibernate Annotations

MySQL and the MySQL connector lib

I am trying to keep this article concise, so if you have questions and I can offer my help feel free to contact me.

Overview of what is going on in this project: We use Spring as a way to wire up the application on the server side, we have a service layer, that communicates using BlazeDS to the client side. The service layer will access the appropriate DAOs or other system objects as needed to create Transfer Objects for the client side.

Docs I have found useful: Spring Documentation, Chapter 1 and 2, the one on transaction management, Spring BlazeDS integration documentation Chapter 1 and 2 (this goes over the important config), Hibernate documentation Chapters 1 and 2, and Hibernate Annotations documentation

Basics of web xml setup:

      <!-- Spring Security Setup -->

      <filter>

        <filter-name>springSecurityFilterChain</filter-name>

        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

      </filter>

      <filter-mapping>

        <filter-name>springSecurityFilterChain</filter-name>

        <url-pattern>/*</url-pattern>

      </filter-mapping>

      <!-- Spring Security Setup End -->

      <!-- BlazeDS Spring Integration Setup -->

    <!-- Pulls the Spring configuration -->

      <context-param>

          <param-name>contextConfigLocation</param-name>

          <param-value>

              /WEB-INF/spring/*-context.xml

          </param-value>

      </context-param>

      <listener>

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

      </listener>

      <servlet>

          <servlet-name>flex</servlet-name>

          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

          <load-on-startup>1</load-on-startup>

      </servlet>

      <servlet-mapping>

          <servlet-name>flex</servlet-name>

          <url-pattern>/messagebroker/*</url-pattern>

      </servlet-mapping>

      <!-- Spring MVC Mapping, allows you to use the traditional Spring MVC along with the BlazeDS -->

      <servlet>

          <servlet-name>spring-mvc</servlet-name>

          <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

          <load-on-startup>1</load-on-startup>

      </servlet>

      <servlet-mapping>

          <servlet-name>spring-mvc</servlet-name>

          <url-pattern>/spring/*</url-pattern>

      </servlet-mapping>           

      <!-- BlazeDS Spring Integration Setup End -->  

      <!-- BlazeDS Remote Discovery Service -->

      <servlet>

        <servlet-name>RDSDispatchServlet</servlet-name>

            <display-name>RDSDispatchServlet</display-name>

        <servlet-class>flex.rds.server.servlet.FrontEndServlet</servlet-class>

        <init-param>

                  <param-name>messageBrokerId</param-name>

                  <param-value>_messageBroker</param-value>

            </init-param>      

            <init-param>

                  <param-name>useAppserverSecurity</param-name>

                  <param-value>false</param-value>

            </init-param>       

        <load-on-startup>10</load-on-startup>

    </servlet>   

    <servlet-mapping id=<em>"RDS_DISPATCH_MAPPING"</em>>

        <servlet-name>RDSDispatchServlet</servlet-name>

        <url-pattern>/CFIDE/main/ide.cfm</url-pattern>

    </servlet-mapping>

    <!-- BlazeDS Remote Discovery Service End -->

 

Above spring security protects our application allowing us to add @Secured annotations to our service calls, the BlazeDS and Spring integration sets up the Blaze servlet and the traditional Spring MVC servlet. The BladeDS Remote Discovery service allows you to use Flex to connect to the data service, I would suggest turning this off once your application is ready, as you might not want others to have easy access to your interface, you can also password protect this which is a more robust for large applications that might be in constant heavy development, though I might still suggest only leaving this on in development and not production.

The spring config:


<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:flex="http://www.springframework.org/schema/flex" 
	   xmlns:tx="http://www.springframework.org/schema/tx"	   
	   xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/flex
           http://www.springframework.org/schema/flex/spring-flex-1.0.xsd
		   http://www.springframework.org/schema/tx
           http://www.springframework.org/schema/tx/spring-tx.xsd    
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.0.xsd       
           ">
           
    <!-- BlazeDS Message Broker and Default Channels Setup -->       
	<flex:message-broker>
		<flex:remoting-service default-channels="my-amf"/>
	</flex:message-broker>
	<!-- BlazeDS Message Broker and Default Channels Setup End -->           
	
	<!-- Spring Security Annotations -->
	<security:global-method-security secured-annotations="enabled" />
	
	<!-- Spring Security URL patterns -->
    <security:http auto-config='true'>    
    <!-- This would force the user to be logged in and sends the user to a basic spring login - to make this work comment on the IS_AUTHENTICATED_ANONYMOUSLY one below, and enable (uncomment the ROLE_USER) -->
      <!-- <security:intercept-url pattern="/**" access="ROLE_USER" />-->      
      <!-- This allows us to access the page without authenticating, good for us since we want to provide the login in our app -->
      <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
      
    </security:http>
    <!-- Spring Security URL patterns End -->
	
	<!-- Custom Spring Security Authentication Provider -->
	<bean id="crystalAuthenticationProvider" class="com.cp.security.CrystalAuthenticationProvider"/>
	
	<security:authentication-manager>
	  <security:authentication-provider ref="crystalAuthenticationProvider"/>
	</security:authentication-manager>	
	<!-- Custom Spring Security Authentication Provider End -->
	
	<!-- Use Spring Annotations -->
	<context:annotation-config/>
	
	<!-- Spring Component Scan for Annotations on these Packages -->
	<context:component-scan base-package="com.cp.services"/>
	<context:component-scan base-package="com.cp.dao"/>
	<!-- Spring Component Scan for Annotations on these Packages End -->
	      		
	<!-- MySQL DB Connection Setup -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	    <property name="driverClassName" value="com.mysql.jdbc.Driver" />
	    <property name="url" value="jdbc:mysql://localhost/crystalplatform" />
     	<property name="username" value="root"/>
        <property name="password" value="root"/>	    
	</bean>
	<!-- MySQL DB Connection Setup End -->
	
	<!-- Hibernate Spring Setup -->
	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
	    <property name="dataSource" ref="dataSource" />
	    <property name="packagesToScan" value="com.cp.dao.entities"/>
	    <property name="hibernateProperties">
	        <props>
	            <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
	        </props>
	    </property>
	</bean>
	<!-- Hibernate Spring Setup End -->
	
	<!-- Spring Declarative Transaction Management Setup -->
	<tx:annotation-driven/>

	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
	  <property name="sessionFactory" ref="sessionFactory" />
	</bean>
	<!-- Spring Declarative Transaction Management Setup End -->	
				    
</beans>


The Spring config does the following: integrates the Flex message broker and sets up the default channels, allows security annotations (@Secured) in a Spring managed component, allows anonymous access to our RIA swf, we are securing the application on the service layer not before we get here, setting up Hibernate and mapping its classes, connecting Hibernate to the MySQL database using the MySQL connector, setting up a custom authentication provider (this can also be attached to the Spring Security basic login if one wants more than method level security at some point.

Basic hibernate entity setup:


@Entity
@Table(name="users")
public class User {

                @Id

                @GeneratedValue(strategy=GenerationType.AUTO)

                @Column(name="id")

                private Integer id;

                @Column(name="username")

                private String username;

                @Column(name="password")

                private String password;

                @Column(name="email")

                private String email;

                @OneToMany(mappedBy="user")

                private List <Expense> expenses;

                @OneToMany(mappedBy="user")

                private List <Compensation> compensations;

                public List<Compensation> getCompensations() {

                                return compensations;

                }

                public void setCompensations(List<Compensation> compensations) {

                                this.compensations = compensations;

                }

                public List<Expense> getExpenses() {

                                return expenses;

                }

                public void setExpenses(List<Expense> expenses) {

                                this.expenses = expenses;

                }             

                public Integer getId() {

                                return id;

                }

                public void setId(Integer id) {

                                this.id = id;

                }

                public String getUsername() {

                                return username;

                }

                public void setUsername(String username) {

                                this.username = username;

                }

                public String getPassword() {

                                return password;

                }

                public void setPassword(String password) {

                                this.password = password;

                }

                public String getEmail() {

                                return email;

                }

                public void setEmail(String email) {

                                this.email = email;

                }

}

One of the corresponding many to one mappings:


@Entity

@Table(name="expenses")

public class Expense {

      @Id

      @GeneratedValue(strategy=GenerationType.AUTO)

      @Column(name="id")

      private int id;

      @Column(name="type")

      private String type;

      @Column(name="total_expense")

      private double totalExpense;

      @Column(name="payment")

      private double payment;

      @Column(name="annual_percentage_rate")

      private double annualPercentageRate;     

      @Column(name="payments_per_year")

      private int paymentsPerYear; 

      @ManyToOne

      @JoinColumn(name="user_id")

      private User user;

      public User getUser() {

            return user;

      }

      public void setUser(User user) {

            this.user = user;

      }

      public Integer getId() {

            return id;

      }

      public void setId(Integer id) {

            this.id = id;

      }          

      public String getType() {

            return type;

      }

      public void setType(String type) {

            this.type = type;

      }

      public double getTotalExpense() {

            return totalExpense;

      }

      public void setTotalExpense(double totalExpense) {

            this.totalExpense = totalExpense;

      }

      public double getPayment() {

            return payment;

      }

      public void setPayment(double payment) {

            this.payment = payment;

      }

      public double getAnnualPercentageRate() {

            return annualPercentageRate;

      }

      public void setAnnualPercentageRate(double annualPercentageRate) {

            this.annualPercentageRate = annualPercentageRate;

      }

      public int getPaymentsPerYear() {

            return paymentsPerYear;

      }

      public void setPaymentsPerYear(int paymentsPerYear) {

            this.paymentsPerYear = paymentsPerYear;

      }

      public ExpenseTO getAsExpenseTO() {

            ExpenseTO expenseTO = new ExpenseTO();

            expenseTO.setId(this.id);

            expenseTO.setAnnualPercentageRate(this.annualPercentageRate);

            expenseTO.setPayment(this.payment);

            expenseTO.setPaymentsPerYear(this.paymentsPerYear);

            expenseTO.setTotalExpense(this.totalExpense);

            expenseTO.setType(this.type);

            return expenseTO;

      }

}

Example Service Code:


@Service("users")
@RemotingDestination
public class UsersService {
	@Autowired
	public UsersDAO userDAO;
	
	@Autowired
	public CrystalAuthenticationProvider authenticationProvider;
	
	@RemotingInclude
	@Secured("IS_AUTHENTICATED_ANONYMOUSLY")	
	public CompleteTO registerUser(RegisterUserTO registerUserTO) {
		// TODO: Add error checking to check that the register user is valid
		userDAO.addUser(registerUserTO);
		return new CompleteTO(true);
	}	
	
	@RemotingInclude
	@Secured("IS_AUTHENTICATED_ANONYMOUSLY")
	public UserTO login(LoginTO loginTO) {		
		Authentication authentication = new UsernamePasswordAuthenticationToken(loginTO.getUsername(), loginTO.getPassword());
		authentication = authenticationProvider.authenticate(authentication);
		SecurityContextHolder.getContext().setAuthentication(authentication);
		UserTO userTO = userDAO.getUserByUsername(loginTO.getUsername());
		return userTO;
	}
	
	@RemotingInclude
	@Secured("ROLE_USER")
	public CompleteTO saveUser(UserTO userTO) {
		userDAO.saveUser(userTO);
		CompleteTO completeTO = new CompleteTO(true);
		return completeTO;
	}
}


The custom authentication provider:


@Component
public class CrystalAuthenticationProvider implements AuthenticationProvider {
	
	@Autowired
	public UsersDAO userDAO;
	
	@Override
	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException, BadCredentialsException {
		
		List <GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();		
		authorities.add(new GrantedAuthorityImpl("ROLE_USER")); // TODO: Pull roles from the DB
		
		LoginTO loginTO = new LoginTO();
		loginTO.setUsername(authentication.getPrincipal().toString());
		loginTO.setPassword(authentication.getCredentials().toString());
		
		if (userDAO.checkIfLoginValid(authentication.getPrincipal().toString(),authentication.getCredentials().toString()))
		{
			return new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),authorities);
		}
		throw new BadCredentialsException("Bad username or password");
	}

	@Override
	public boolean supports(Class<? extends Object> clazz) {
        if (clazz.isAssignableFrom(UsernamePasswordAuthenticationToken.class))  
	    {  
        	return true;
	    }
        return false;
	}
	
}


This allows the session factory with the MySQL setup to be injected in as a HibernateTemplate. Then we use the template as follows:


@Transactional
public abstract class AbstractDAO 
{
	protected HibernateTemplate template;
	
	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory)
	{
		template = new HibernateTemplate(sessionFactory);
	}
}

@Transactional
@Component
public class UsersDAO extends AbstractDAO {
	public UserTO getUserByUsername(String username) {
		List<User> users = template.find("from User as user where user.username like '"+username+"'");
		User user = users.get(0);
		UserTO userTO = new UserTO();
		userTO.setId(user.getId());
		
		List<Expense> expensesList = user.getExpenses();
		List<ExpenseTO> expensesTOList = new ArrayList<ExpenseTO>();
		
		for (Iterator<Expense> it = expensesList.iterator(); it.hasNext();)
		{
			Expense expense = it.next();
			expensesTOList.add(expense.getAsExpenseTO());
		}	
		
		userTO.setExpenses(expensesTOList);		
		return userTO;		
	}
	
	public User getUserById(int id) {
		List<User> users = template.find("from User as user where user.id like '"+id+"'");
		return users.get(0);
	}
	
	public List<User> getAllUsers() {
		return template.findByExample(new User());
	}
	
	public void addUser(RegisterUserTO registerUserTO) {
		User user = new User();
		
		user.setUsername(registerUserTO.getUsername());
		user.setPassword(registerUserTO.getPassword());
		user.setEmail(registerUserTO.getEmail());
		
		template.save(user);
	}	
	
	public Boolean checkIfLoginValid(String username, String password) {
		
		List<User> users;

		users = template.find("from User as user where user.username like '"+username+"'");

		if (users.isEmpty())
		{
			return false;
		}
		
		User user = users.get(0);
		
		List <Expense> expenses = user.getExpenses();
		
		if (user.getPassword().compareTo(password) == 0)
		{
			return true;
		}
		
		return false;
	}
	
	public Boolean saveUser(UserTO userTO) {
		List<User> users = template.find("from User as user where user.id like '"+userTO.getId()+"'");

		if (users.isEmpty())
		{
			return false;
		}
		
		User user = users.get(0);
		
		// Convert TO expenses to Expense entities		
		
		List<ExpenseTO> expenses = userTO.getExpenses();
		List<Expense> saveExpenses = new ArrayList<Expense>();
		for (Iterator<ExpenseTO> it = expenses.iterator(); it.hasNext();)
		{
			ExpenseTO expenseTO = it.next();
			saveExpenses.add(expenseTO.getAsExpenseEntity());
		}
		user.setExpenses(saveExpenses);
		
		// Convert TO compensations to Compensation entities		
		
		List<CompensationTO> compensations = userTO.getCompensations();		
		List<Compensation> saveCompensations = new ArrayList<Compensation>();
				
		for (Iterator<CompensationTO> it = compensations.iterator(); it.hasNext();)
		{
			CompensationTO compensationTO = it.next();
			saveCompensations.add(compensationTO.getAsCompensationEntity());
		}
		user.setCompensations(saveCompensations);		
		
		template.save(user);		
		return true;
	}

}


The @Service(“users”) annotation exposes the “users” service to be connected to on the Blaze end through remote object:


	public class UserService extends Actor
	{
		private var remoteObject:RemoteObject;
		
		public function UserService()
		{
			super();
			remoteObject = new RemoteObject("users");			
			remoteObject.endpoint = "http://localhost:8400/crystalPlatformServer/messagebroker/amf";
			// remoteObject.endpoint = "https://localhost:9400/crystalPlatformServer/messagebroker/amfsecure"; // Use this for a secure HTTPS connection
			remoteObject.login.addEventListener(ResultEvent.RESULT,handleLoginResult);	
			remoteObject.login.addEventListener(FaultEvent.FAULT, handleLoginFault);
			remoteObject.registerUser.addEventListener(ResultEvent.RESULT,handleRegisterUserResult);
			remoteObject.registerUser.addEventListener(FaultEvent.FAULT,handleRegisterUserFault);
			remoteObject.saveUser.addEventListener(ResultEvent.RESULT,handleSaveUserResult);
			remoteObject.saveUser.addEventListener(FaultEvent.FAULT,handleSaveUserFault);
		}
		
		private function handleLoginFault(event:FaultEvent):void
		{
			LoggingUtil.log("Fault calling service "+event.toString());
			this.failLogin();
		}
		
		public function login(loginVO:LoginVO):void
		{			
			LoggingUtil.log("Making login service call.");
			remoteObject.login(loginVO);
		}
		
		public function saveUser(vo:UserVO):void
		{			
			LoggingUtil.log("Making save user service call.");
			remoteObject.saveUser(vo);
		}		
		
		private function handleLoginResult(event:ResultEvent):void
		{
			LoggingUtil.log("Login call result returned.");
			if (event.result is UserVO)
			{
				// Login successful
				this.dispatch(new LoginSuccessfulEvent(LoginSuccessfulEvent.SUCCESS,event.result as UserVO));
			} else {
				// Login not succcesful
				this.failLogin();
			}				
		}
		
		private function failLogin():void
		{
			LoggingUtil.log("Login failed.");
			this.dispatch(new LoginFailEvent(LoginFailEvent.FAIL));
		}
		
		public function registerUser(registerUserVO:RegisterUserVO):void 
		{
			LoggingUtil.log("Making registerUser service call.");
			remoteObject.registerUser(registerUserVO);
		}				
		
		private function handleRegisterUserResult(event:ResultEvent):void
		{
			LoggingUtil.log("Register User call result returned.");
			if (event.result is CompleteVO)
			{
				var vo:CompleteVO = event.result as CompleteVO;
				if (true === vo.successful)
				{
					// User registration successful
					this.dispatch(new RegisterUserSuccessfulEvent(RegisterUserSuccessfulEvent.SUCCESS));
				} else {
					this.failRegistration();
				} 
			} else {
				this.failRegistration();
			}
		}		
		
		private function handleRegisterUserFault(event:FaultEvent):void
		{
			LoggingUtil.log("Fault calling service "+event.toString());
			this.failRegistration();
		}		
		
		private function failRegistration():void
		{
			LoggingUtil.log("Registration failed.");
			this.dispatch(new RegisterUserFailEvent(RegisterUserFailEvent.FAIL));
		}		
		
		private function handleSaveUserResult(event:ResultEvent):void
		{
			LoggingUtil.log("Save User call result returned.");
			if (event.result is CompleteVO)
			{
				var vo:CompleteVO = event.result as CompleteVO;
				if (true === vo.successful)
				{
					// User registration successful
					this.dispatch(new Event(SaveUserSuccesfulCommand.SUCCESFUL));
				} else {
					this.failSave();
				} 
			} else {
				this.failSave();
			}
		}		
		
		private function handleSaveUserFault(event:FaultEvent):void
		{
			LoggingUtil.log("Fault calling service "+event.toString());
			this.failSave();
		}			
		
		private function failSave():void
		{
			LoggingUtil.log("Registration failed.");
			this.dispatch(new SaveFailEvent(SaveFailEvent.FAIL));
		}		
				
	}


The endpoint in the Flex code tells us where to find the Blaze DS server. For debugging and testing, this is localhost – you will need to change this to allow BlazeDS to work on Android, as you won’t be running a local instance of Tomcat with MySQL on Android – as least not that I know of yet.

The service uses the usersDAO which is @Transactional, which tells spring to wrap calls in a transaction and allow for rollback, this allows global policies to be implemented for transactions and is a good case for AOP – Aspect Oriented Programming because this functionality applies across the data layer. The userDAO uses Hibernate Query Language and the Spring HibernateTemplate for CRUD (Create, Read, Update, and Delete) tasks with the entities on the database. @Table tells what table in the database the entity is linked to, @Column links up the columns, and I have also shown a one to many relationship and how it is mapped by the many classes table (Expenses.user_id or Compensations.user_id in our case) to the one classes table id (User.id).

Value Objects on the Flex side are mapped to Transfer Objects on the Java side:

*** Note: the class must have been referenced somewhere in the project for it to map properly when coming backfrom BlazeDS, otherwise it will come back as an ObjectProxy and not the class you mapped.

Flex side:


package com.crystalplatform.expenses.context.model.vo
{
	[RemoteClass(alias="com.cp.services.transfer.LoginTO")]	
	public class LoginVO
	{
		public var username:String;
		public var password:String;
	}
}


Java side:


package com.cp.services.transfer;

public class LoginTO {
	private String username;
	private String password;
	
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}	
}

Creating the database from MySQL command line (in the project his is in sql\tablesSQL.txt which you can run by typing mysql –user=root –password=[your password] < tablesSQL.txt)

mysql --user=root --password=[your password] tablesSQL.txt

drop database crystalplatform;
create database crystalplatform;
use crystalplatform;
create table users (id int(50) not null auto_increment primary key, username varchar(50), password varchar(50), email varchar(100));
create table expenses (id int(50) not null auto_increment primary key, user_id int(50) not null, type varchar(50), total_expense double, payment double, annual_percentage_rate double, payments_per_year double);
create table compensations (id int(50) not null auto_increment primary key, user_id int(50) not null, type varchar(50), amount double, payments_per_year int(50));
insert into users (username,password,email) values ('test','test','test@test.com');
insert into expenses (user_id,type,total_expense,payment,annual_percentage_rate,payments_per_year) values (1,'Car Loan',6000,300,6,12);
insert into expenses (user_id,type,total_expense,payment,annual_percentage_rate,payments_per_year) values (1,'Student Loan',10000,200,4,12);
insert into compensations (user_id,type,amount,payments_per_year) values (1, 'Job', 3000, 12);
insert into compensations (user_id,type,amount,payments_per_year) values (1, 'Stocks', 500, 12);

In conclusion this is a large stack, I have tried to simplify some of the integration and interactions of the process. Constructive pointers are greatly appreciated.

Posted in Uncategorized | Leave a comment