Showing posts with label migrated. Show all posts
Showing posts with label migrated. Show all posts

October 29, 2014

Creating a sortable table from an array of complex objects, with custom column ordering, using pure AngularJS

Read this on medium.com instead: https://medium.com/@idleworx/16af1d9edeae?source=tw-ab7a0a61509e-1414631999267

In a recent project I came across a more complex scenario when needing to create a table (from an array of complex objects as the model)

More specifically, I have a list of items to render.
Each item is an object which contains multiple fields.
Each field is an object that has name, value and order properties.
So for example one item looks like this:

{
    "fields": {
      "link": {
        "description": "Link",
        "name": "link",
        "order": 1,        
        "value": "http://www.google.com"
      },
      "name": {
        "description": "Name",
        "name": "name",
        "order": 2,        
        "value": "Google Homepage"
      },
      "notes": {
        "description": "Notes",
        "name": "notes",
        "order": 4,        
        "value": "Notes about google"
      },
      "price": {
        "description": "Price",
        "name": "price",
        "order": 3,        
        "value": "100"
      }
    }
}


The Problem (Requirements)

What I need to do is to render a table from an array of  items, so multiple items as the one above, in such a way that the field names become the columns  (using the order specified in the field.order value), and each column is sortable.

You can assume here that the ordering of all fields in each item is the same, and all items have the same fields. So each item is different only differ in the fields' value property) 

To make this simpler to understand, using the relational table concept, think of the items as records, and the fields for each item as the columns (ordered columns at that).

The final output would look like this given 3 items (with each column header clickable)

AngularJS Complex Table Example


So how would you render something like this?


The Solution

1. Write a helper method for sorting an item's fields



First I need a method that returns a sorted array of fields (that I will call from the partial)

getFieldsSorted(item);


function getFieldsSorted(item){
  var fields = _.sortBy(item.fields,'order'); //using the awesome underscorejs library
  return fields;
};

When run, given the item's JSON defined before, this method will return a sorted array of fields, based on the field.order property, that looks like this. So for a single item, this method would return:

[
  {
    "description": "Link",
    "name": "link",
    "order": 1,    
    "value": "http://www.google.com"
  },
  {
    "description": "Name",
    "name": "name",
    "order": 2,    
    "value": "Google Homepage"
  },
  {
    "description": "Price",
    "name": "price",
    "order": 3,    
    "value": "100"
  },
  {
    "description": "Notes",
    "name": "notes",
    "order": 4,    
    "value": "Notes about google"
  }
]
Note here that unlike the unsorted item defined in the beginning, in which the fields were sorted: Link, Name, Notes,Price, after the getFieldsSorted(item) is called, the fields are now sorted as: Link, Name, Price, Notes because that is how the field ordering is defined.
This requirement about ordering fields, is so because in my particular case the user will need to be able to customize the field ordering of the item's fields.


Now we'll use Angular's ng-repeat directive to generate a sortable table from an array of 3 items

2. Render the table columns using the order of the fields


Since an item's fields are not in ordered by default according to the field.order property, we'll make use of the getFieldsSorted(item) helper method defined before.

First we'll use ng-repeat to generate the table header with all the fields in order.

Since all the fields are the same across all items (except for their value property), we'll just use the first item's fields to render the table column header.

<table class="table table-striped" ng-if="items.length > 0">
  <thead>
    <tr>
        <th ng-repeat="field in getFieldsSorted(items[0])">
            {{field.description}}            
        </th>
    </tr>
  </thead>
</table>

3. Render the table columns using the order of the fields

We'll use the same getFieldsSorted(item) method to make sure the field values match up with the column names.

<table class="table table-striped" ng-if="items.length > 0">
  <thead>
    <tr>
        <th ng-repeat="field in getFieldsSorted(items[0])">
            {{field.description}}            
        </th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="i in items">
        <td ng-repeat="field in getFieldsSorted(i)">            
            {{field.value}}
        </td>        
    </tr>
  </tbody> 
</table>


4. Enable table sorting when clicking on the columns

We'll use the same getFieldsSorted(item) method to make sure the field values match up with the column names. To enable sorting we'll use the ng-click directive to set both the column name to sort on and the sort direction.

Sorting by {{toggles.sort.itemsSort.column}}, reverse = {{toggles.sort.itemsSort.reverse}}.
<br>
<table class="table table-striped" ng-if="items.length > 0">
  <thead>
    <tr>
        <th ng-repeat="field in getFieldsSorted(items[0])"  ng-click="toggles.sort.itemsSort.column='fields.'+field.name+'.value';toggles.sort.itemsSort.reverse=!toggles.sort.itemsSort.reverse;">
            {{field.description}}            
        </th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="i in items">
        <td ng-repeat="field in getFieldsSorted(i)">            
            {{field.value}}
        </td>        
    </tr>
  </tbody> 
</table>
Here when a table column is clicked, we are assigning the name of the column to sort on to the toggles.sort.itemsSort.column variable.

This is the most important part of this, if you've followed so far.

Remember, we are trying to sort the selected field's values for each item in our $scope.items array.

However the item is not a simple array of strings, it's a complex object, and so we need to let angular know to sort using a child property of the complex object,
in our case, by item.fields[name].value

So you may be tempted to use this as the column name

ng-click="toggles.sort.itemsSort.column=field.name"

however because we are dealing with an array of complex objects this won't work, instead we'll use

toggles.sort.itemsSort.column='fields.'+field.name+'.value'
so angular knows to use the object's property properly.
But sorting won't work yet, because inside the tbody table rows we haven't enabled it yet.

4. Enable sorting of the data

The final step here is to make sure the data is sorted, and for that we'll use the order by filter to do so. Now the orderBy filter will properly sort the data from the list of complex objects (items) because it will attempt to sort by item.fields.name.value (where 'name' is automatically changed whenever toggles.sort.itemsSort.column changes)

Sorting by {{toggles.sort.itemsSort.column}}, reverse = {{toggles.sort.itemsSort.reverse}}.
<br>
<table class="table table-striped" ng-if="items.length > 0">
  <thead>
    <tr>
        <th ng-repeat="field in getFieldsSorted(items[0])"  ng-click="toggles.sort.itemsSort.column='fields.'+field.name+'.value';toggles.sort.itemsSort.reverse=!toggles.sort.itemsSort.reverse;">
            {{field.description}}            
        </th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="i in items | orderBy:toggles.sort.itemsSort.column:toggles.sort.itemsSort.reverse">
        <td ng-repeat="field in getFieldsSorted(i)">            
            {{field.value}}
        </td>        
    </tr>
  </tbody> 

</table>

That's it. To see the full code example checkout the codepen sourcecode for this. 


August 19, 2014

Creating a flexible Alerting Service with AngularJS (Part 1)

Using AngularJS 1.2.20, Bootstrap 3, underscore.js

While working on recent AngularJS project I had to come up with an easier way to deal with application messages (error messages, alert messages, debug messages,etc).

If you have a tiny AngularJS app $scope.error = ‘Error Description’; will do it for sending simple error messages to your controllers, but if you’re using this approach for a larger app you’ll quickly find it’s not a good idea.

While I am sure there are other ways to do this, perhaps better ones, this article will show you how to implement a flexible Alerting/Messaging Service for use in an AngularJS app.

Usage inside Controllers




Why do I have to pass in scope every time?

The way this Message Service works is it allows you to set one message of each type (info,warning,error,success,debug) ,so 5 in total, on any $scope you pass in. This allows you to set scope specific error messages. This is good because you can have a controller that has a warning message, and another one that has an error message. The messages won't interfere with each other.

Usage inside Partials


To make this really easy, I've used bootstrap 3 template code to generate several html templates for the messaging.
You can simply include the following files (messages.tpl.html) and (debug-messages.tpl.html) in your AngularJS application (assuming you are using the bootstrap 3 framework).




The above partials can then be embedded anywhere in your app where you want to display an messages. Typical place would be somewhere on top of your main app content. I like to keep the messages and the debug messages separate like this for easier including where needed. Just make sure they are inside the scope for which you are displaying these messages (otherwise the $scope.messages property will be undefined, and no messages will show for this scope).

So for example, if you are using the controller from before



you should be using this code to add the messages to your app.



How the Message Service actually works


The message service adds a $scope.message property to any $scope for which you invoked the MessageService.init($scope) method. It then keeps track and updates $scope.message any time you call one of the message methods such as MessageService.error($scope,'This is an error');

And here is the actual Message Service (MessageService.js)



If you need the angular and underscore.js libraries used in this example, just add the following to your app





Part 2 - Coming soon ... more complex example, custom error objects, global messages and scope specific messages

February 27, 2014

AngularJS - Best resources for learning ui-router

ui-router is an angular module that replaces the default routing mechanism. It is more flexible than the default and recommended by the AngularJS community. However it is still in active development

This is a collection of resources about ui-router, from simple to more complex.

ui-router project on git
https://github.com/angular-ui/ui-router

Intro video to ui-router (5 mins)
https://egghead.io/lessons/angularjs-introduction-ui-router

Another intro video to ui-router (first 15 minutes).


A great article about ui-router (more indepth)
http://www.ng-newsletter.com/posts/angular-ui-router.html

In-depth video about ui-router (50 min) + with http://slid.es/timkindberg/ui-router#/




Related Resources


One way to setup authentication in AngularJS
http://blog.brunoscopelliti.com/deal-with-users-authentication-in-an-angularjs-web-app

Builds on the article above, but using ui-router
https://medium.com/opinionated-angularjs/4e927af3a15f

Video - Writing a Massive Angular App at Google NG Conf (good tips about authentication in the first part)
http://www.youtube.com/watch?v=62RvRQuMVyg


If you have additional suggestions, let me know and I will add them here.

March 15, 2013

You should update your TableSorter jQuery plugin

If you're still using the cool jQuery TableSorter plugin by Christian Bach, be advised that the last update to it was back in 2008 (version 2.0.8 as of today).

There is a newer forked version of Table Sorter on github, v2.7.x that seems to be maintained by someone else and up to date. Docs here.

March 11, 2013

Teach a Dog to REST

A good video on how to build REST APIs the right way.

November 15, 2012

The Unbearable Immutability of Java Strings

Here is a quick explanation of what an Immutable String is in Java.
Basically, an immutable string means that the string 'object' can't be changed, but references to it can.





November 10, 2012

Jerker Desk Replacement Screws and Bolts

Yes, there is a cult like following on the internet for IKEA Jerker Desks.

It's hard to find replacement screws for the desk since it's discontinued. Here's a list of the screw sizes I found at Lowe's that should work with any Jerker desk. I used these to add on some additional shelves (since I only had the screws and bolts that came with the main table part of the desk)

You can find these at your local Lowe's or HomeDepot store in the METRIC/European section of the nuts and bolts isle. Ask for it, it's there :-)

Screws - Hex Cap Screws (Class 8.8 - M6-1.00x50)
Nuts - Hex Nuts (Class 8 - M6-1.00) [option 1]
Nuts - Insert Lock Nuts (Nylon Class 8 - M6-1.00) [option 2]
Washers - Flat Washers - 6mm

TIP: Use the washers between the metal part and the nut for tighter grip]


I got the Jerker desk a while back, as I needed a better desk for programming. I wouldn't say it's the most amazing desk ever but it's comfortamble and makes excellent use of space particularly if you have multiple things you need around eg. scanner, printer, subwoofer, midi keyboard etc.

IKEA has a similar desk on sale called the FREDRIK. Some people seem to think the Jerker desk doesn't even compare with the FREDERIK, but I don't know as I've never tried it so can't compare.

So far the Jerker desk is great for what I need. Use your own judgement.

Hope you found this useful in case you are looking to add some additional shelves to your Jerker desk.






October 31, 2012

All Spring Schema Configurations and JARs for Spring 2.0, 2.5, 3.0

This post contains basic info about Spring Schema Configuration XML syntax for different versions of Spring 2.0.x, 2.5.x and 3.0.x.

Not sure why it's so hard to find this data all put together so here it is. Direct download links for the Spring JARs and the spring xml file header configuration for each version.

Spring 2.0 - October 2006






Direct Download Link: Spring Framework 2.0.8 (latest Spring 2.0.x release)

Spring 2.5 - November 2007



      


Direct Download Link: spring-framework-2.5.6.SEC03.zip (latest Spring 2.5.x maintenance release)

Note:The only difference between the syntax for Spring 2.0 and 2.5 seems to be the addition of the context schema in 2.5.
Also as of Spring 2.5, Spring provides support for configuring the MVC framework components using annotations.

Spring 3.0 - December 2009



 
 
 


Direct Download Link: spring-framework-3.1.3.RELEASE.zip (current production release)

Note:The spring.jar that contained almost the entire framework is no longer provided in Spring 3.0 so you must include each jar as needed separately.

New Features in Spring 3.0


Spring 3.0 also introduced a few new features such as additional annotations for MVC, server-side support for building RESTful applications, the Spring Expression Language and integration of some core features from the JavaConfig project.

Useful Links

Spring 2.0.x Reference
Spring 2.0.x Schema Configuration

Spring 2.5.x Reference
Spring 2.5.x Schema Configuration

Spring 3.0.x Reference
Spring 3.0.x Schema Configuration

New in Spring 3.0

Spring Main Download Page

April 12, 2012

Android Development Is Not Easy

As a seasoned software engineer I spent a good number of hours over the past week trying to figure out how to do the following on an Android device.

Problem: Create an android application that checks a local SQLite database at a given interval (say every day @ 12:00 am), does something with that data, then displays a notification to the user.

Seemed like a trivial thing to do.

Initially I thought I would need only a Service that my Activity starts. I was wrong.

After reading more thoroughly through the Android API documentation, numerous stackoverflow articles, and some trial and error I figured it out.

In order to do this on android you have to understand the following concepts:

  • BroadcastReceivers
  • Services (more specifically IntentServices)
  • Intents (more specifically PendingIntents)
  • Reading/Writing to an SQLite database
  • The AlarmManager 
  • How notifications work
  • + a few other things

The short answer is the following.

Solution: You have to implement a custom broadcast receiver, that uses the AlarmManager to schedule a PendingIntent that starts a custom Service which does the work, which creates a Notification at (or around) a set time for the user to click on.

There's some quirks too you have to consider:

  • How do you make sure your app continues to run after the user reboots the android device?
  • How do you schedule the first Notification after your app is started by the user for the first time?
  • When do you schedule the alarm to run? What happens if the device is off?
  • etc.

So if you just got an awesome idea for an Android app, great. I hope you'll be able to use your skills to build it and make it a success. But be warned, you need not only coding skills, but passion and patience, and don't fool yourself into thinking that it will take you a few hours.

Building an app (a non trivial app that is) is one thing. Building an android application that is well designed and coded, runs well, and provides a true service to your users is hard.

If you don't have the luxury of time, the patience required, or the necessary skills to build an Android Application yourself, don't sweat it, it's not easy stuff.

So do yourself a favor and hire a developer to build it for you.


February 5, 2012

The Do Not Track movement is useless

... or why privacy is your own responsibility

The Do Not Track movement (donottrack.us) is, according to their website

"a technology and policy proposal that enables users to opt out of tracking by websites they do not visit"

and from a recent article in USA Today, How Facebook tracks you across the web we find out the following

"Facebook's efforts to track the browsing habits of visitors to its site have made the company a player in the "Do Not Track" debate, which focuses on whether consumers should be able to prevent websites from tracking the consumers' online activity."

Companies like Facebook, Google, etc have a vested interest in finding out as much information about EVERYTHING you do. That's how they make money. So any movement that proposes these companies self-regulate and take more care of our privacy needs is simply useless.

Even if regulation was passed forcing these companies to allow users to opt out of tracking, that doesn't mean it wouldn't still occur.

The donottrack.us website also mentions that

"Several large third parties have already committed to honor Do Not Track ... "

So what? Does that mean anything really?

What do you know about what they do with this information even if they "committed" to work against their own self and business interests by not tracking you?

I'll tell you. Absolutely nothing!

Do you have a signed contract with them that says they can never track you? Is there an actual law that prevents them from tracking you? No? Then stop daydreaming.

When it comes to personal privacy and security, you can't outsource it (especially to those who have an interest in your lack of privacy). There's no easy way.

So if you care about your privacy, educate yourself and protect yourself.


February 1, 2012

Goodbye Delicious, Hello Pinboard


Goodbye Delicious

There are two types of people in the world, those who rarely save bookmarks, and those who have thousands. If you're like me, you probably have thousands or at least a few hundred. For me it's more exactly 4466 bookmarks at last count. (If you're not like me, a bookmark hoarder, then you probably want to skip this article.)

Over the past 10-15 years I've collected tons of bookmarks because I like to keep track of cool, useful and interesting things I find online so if I ever want to go back to them I can.

I've spent countless hours over the years keeping things clean, ordered and organized so I can actually make use of this information. As you can imagine if you don't keep this many bookmarks organized and neat there's absolutely no point in saving them in the first place, since you won't be able to find anything if you so choose at a later time.

Bookmarks, when used correctly are nothing more than a self maintained cache of the things you've found most interesting or useful. Thus they are a treasure trove of data for various services such as  delicious or various others which have capitalized on this.

Delicious was founded in 2003, and was essentially the company that introduced social bookmarking and tagging to the masses. That said and done I didn't really get on board with them until a few years ago when I outgrew my bookmarking needs. Trying to manage several thousand bookmarks across multiple browsers and multiple computers does that to you.

But delicious has not delivered and has recently started to fall short, in part due to Yahoo firing the delicious team, and its subsequent purchase by Youtube founders.

Here's just a few problems I found:

  • Slow syncing of bookmarks in browser
  • Having to sometimes log in every day 
  • Firefox addons would stop working after upgrading to certain version of Firefox
  • The pain and waste of time trying to find a way to mark all my bookmarks private when bookmarking through a browser plugin. Why, delicious? Why?
  • Inconsistent tag naming - You could use spaces in an older versions of the Firefox plugin, but only commas in newer versions. Because it wasn't made clear, myself and I'm sure plenty of others, had had to go through tons of delicious bookmarks and convert tags like "programming jsp reference useful" into the 4 separate tags they should have been in the first place. Not cool)

And there were other unhappy campers.

Hello Pinboard


As delicious was going down, I learned of other social bookmarking sites, pinboard.in being one that caught my attention.

Throughout the years, I had migrated over from IE Favorites to Firefox Bookmarks to delicious bookmarks. I had hand curated my bookmarks and cleaned them up with link checkers to remove expired ones. It was time to move on to something better.

So last night, I finally made the switch and created an account on pinboard.in. It's not free mind you (there is a one time fee of about $9), but from everything I read it's worth it  Not to mention the guy behind it seems like a great chap and has his stuff together.

And from the first looks, I love it.

  • Importing almost 4500 bookmarks from both firefox and delicious was painless. Took a few minutes.
  • Interface is great, simple, minimal and quick, exactly what I wanted
  • Great default privacy settings give you the ability to 'add bookmarks as private by default'
  • 'enable public profile' is OFF by default
  • and more
I did notice there was no easy way to rename a tag in pinboard (there is a way though), but I'm planning to play around with the Pinboard API soon and see what I can cook up.

I'm sure pinboard is not perfect, but hey, it is the best I've found so far for my bookmarking needs.


January 17, 2012

A simple birthday reminder app

Are you looking for an easy breazy birthday reminder app to keep track of all your friends' birthdays that you seem to forget every year? Well, look no further.

The time has come for you to get your self organized and never forget another birthday again. Check out http://beta.birthdayduck.com a simple, clean and useful birthday reminder service from IdleWorx

Here's a screenshot




It has the essential features you need in a birthday reminder application:
  • Reminders by email
  • Reminders by SMS/text message
  • A simple way to add names ands birthdays
  • Import contacts from Facebook

No bells and whistles. birthdayduck.com aims to help you organize your life, by making it very easy to remember people's birthdays. 

It works like a birthday reminder calendar, except you won't need to worry about it all the time. The application will send you reminders by email and sms before someone's birthday.

We're currently in beta, and getting ready to launch soon. 

If you sign up now at  http://beta.birthdayduck.com  and you are one of the first 50 sign-ups you'll receive a free lifetime account on birthdayduck.com once we launch.




December 28, 2011

How algorithms shape our world (video)


Kevin Slavin argues that we're living in a world designed for -- and increasingly controlled by -- algorithms. In this riveting talk from TEDGlobal, he shows how these complex computer programs determine: espionage tactics, stock prices, movie scripts, and architecture.

December 20, 2011

Your time is not worth that much

I noticed a lot of people in the startup/programming/HN community seem to measure their time in the equivalent of how much money they could be making during that time.

For example, you ask a friend to do something for you that takes 2 hours, and they tell you that in those 2 hours they could be making 300$ because that's their hourly rate if they were doing freelance work. So essentially if they aren't paid for these 2 hours they are basically loosing 300$.

I say this way of estimating how much your time is worth is flawed.

The only time this estimate is true is when you have a guy waiting at your door 24/7 for you to open it and give you work, and let you charge him 150$/hr for that work (per the example above).

Given any other time, your time estimate is probably way off. Because if you don't have work available NOW at the rate you're estimating yourself to be worth, your time is just not worth as much as you think it is. In fact, if you don't have any work lined up for that rate, your time is worth almost nothing. It's free time.

Could you be making money during your free time? Yes, however if you are not ready at that very moment to take on the work at your going rate, your lost opportunity cost is not 150$/hr, but 0$.

The other problem with correctly estimating what your time is worth is how easy it is easy to overestimate. I mean hey, in this next hour that I don't do anything I could be making a million dollars by winning the lottery. So my hourly rate is a million dollars. Just like the example above, that rate IS possible, but highly unprobable not to mention ridiculously unsustainable.

To dig in further, the wiki informs us that: 

"The notion of opportunity cost plays a crucial part in ensuring that scarce resources are used efficiently" 

And that's a good thing. If you're wasting your time on the couch picking your nose, you could be doing much better things with your time (Eg. creating something useful for others and getting paid for it too)

Some people however have the tendency to put a dolar value on EVERYTHING in their lives. And sadly it's a rather limited world view when everything has a dollar value and an opportunity cost.

News Flash: Not everything in life has a dollar value


The wiki has a fairly straight forward example of this

"Opportunity costs are not always measured in monetary units or being able to produce one good over another. For instance, an individual could choose not to mow his or her lawn, in an attempt to create a prairie land for additional wild life. Neighbors of this individual may see this as unsightly, and want the lawn to be mowed. In this case, the opportunity cost of additional wild life is unhappy neighbors."

We are not robots and life is not a well written ruby script (as some would like to believe).

You can always look at everything in terms of the lost opportunity cost (and the dollar value associated with it), however, often the lost opportunity cost in dollars is far less valuable as an indicator of how much your time is really worth, and in some cases it can't even be used to accurately describe the lost opportunity cost, such as the opportunity cost of non-tangible things.

For example, spending 2 hours playing with your kids or volunteering and genuinely helping out another human being, is INFINITELY more important, beneficial and fulfilling than your lost opportunity cost of 300$ that you could be making doing freelance work.


So to sum it up, while it's good to have a perspective about how much your time is worth, don't over do it.

There are obvious cases when estimating your time makes perfect sense, but breaking down your entire waking time into lost opportunity costs is a bit too much in my opinion.

Just like with most things in life, aim for moderation.

September 23, 2011

MyBatis DAO Example Code Tutorial

This tutorial will show how how to integrate MyBatis with the Data Access Object pattern (DAO) and MySQL for use in Java Web Apps.

In case you're not familiar, MyBatis is the new version of the iBatis Data Mapper Java Framework, which allows you to use a relational database with object-oriented applications.

If you're not familiar with the DAO pattern or the benefits of using it read more about it here Generic implementation of the DAO pattern.

Full code of this mybatis dao example tutorial is available on github here.

Step 1 - Define the interface

Create an IParentDAO interface to define the main method calls for all objects. This interface can be used as the parent for various DAO implementations. Here are the default CRUD methods that all objects will have

get(id)
getByName(name)
getAll()
create(obj)
update(object)
delete(id)

Create the IParentDAO.java class


public interface IParentDAO<T, PK>{
 public T get(PK id) throws PersistenceException;//get obj of type T by the primary key 'id' 
 public T getByName(String name) throws PersistenceException;//get obj of type T by the 'name' field, if one exists for that table
 public ArrayList<T> getAll() throws PersistenceException;//get all objects of type T
 public int create(T objInstance) throws PersistenceException;//insert an object of type T into the database
 int update(T transientObject) throws PersistenceException; //update an object of type T    
 int delete(PK id)  throws PersistenceException;//delete an object of type T
}

Step 2 - Create the base class

Create the MyBatisDAO abstract base class. This will be the default MyBatis implementation of the DAO. You can of course write a different one for JDBC, Spring etc. Feel free to remove the logging code if you don't need it. I used Logback for that.


import java.util.ArrayList;

import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** 
 *  Class contains all the basic CRUD related methods which are inherited by all objects
 *  Children daos should generally not overwrite these method but add extra ones as needed.  
 */
public abstract class MyBatisDAO<T, PK> implements IParentDAO<T, PK>{
 
 private static Logger log = LoggerFactory.getLogger(MyBatisDAO.class);
 private static final String NAMESPACE = "mappers"; 
 
 private SqlSessionFactory sf; //reference to mybatis session factory 
 private Class<T> type;
  
 /** 
  * Define prefixes for easier naming convetions between XML mapper files and the DAO class 
  **/ 
 public static final String PREFIX_SELECT_QUERY = "get";     //prefix of select queries in mapper files (eg. getAddressType) 
 public static final String PREFIX_INSERT_QUERY = "create"; //prefix of create queries in mapper files (eg. createAddressType)
 public static final String PREFIX_UPDATE_QUERY = "update";  //prefix of update queries in mapper files (eg. updateAddressType)
 public static final String PREFIX_DELETE_QUERY = "delete";  //prefix of delete queries in mapper files (eg. deleteAddressType)
 
 /** Default Constructor */
    public MyBatisDAO(Class<T> type,SqlSessionFactory sf) {
        this.type = type;
        this.sf = sf;
        if(sf==null)
   log.error("Error: Could not instantiate MyBatisDAO. Loading myBatis sessionFactory failed.");  
    }
    
    /** Use this method to get a session factory for using in any methods impelmented in child dao classes */
    protected SqlSessionFactory getSessionFactory() {
  return sf;
 }

    /** 
     *  Default get by id method. 
     *  </br></br> 
     *  Almost all objects in the db will 
     *  need this (except mapping tables for multiple joins, which you 
     *  probably shouldn't even have as objects in your model, since proper 
     *  MyBatis mappings can take care of that).
     *  </br></br>
     *  Example: 
     *  </br>
     *  If your DAO object is called CarInfo.java, 
     *  the corresponding mapper query id should be: &lt;select id="getCarInfo" ...  
     */
    public T get(PK id) throws PersistenceException {
        
     SqlSession session = sf.openSession(); 
     T obj = null;
  try
  {  
   String query = NAMESPACE+"."+PREFIX_SELECT_QUERY+this.type.getSimpleName();  //If the object's calls name is AddressType.java, this matches the mapper query id: "namespace.getAddressType"
   obj = (T)session.selectOne(query,id);      
  }
  finally
  {
   session.close();
  }
  return obj;
    }
    
    /** 
     *  Method returns all rows for this object.
     *  </br></br>  
     *  Example:
     *  </br>  
     *  If your DAO object is called CarInfo.java, 
     *  the corresponding mapper query id should be: &lt;select id="getAllCarInfo" ...  
     *  </br></br>  
     *  SQL Executed: select * from [tablename]
     *  </br></br>  
     *  Notes:
     *  </br>   
     *  Consider overdiding this method in order to handle large numbers of objects 
     *  with multiple references.  
     *  LAZY LOADING should be enabled in this case, otherwise you might run out of memory (eg. get all UserAccounts if the table has 1,000,000 rows)
     *  look into the aggresiveLazyLoading property 
     *  */
    public ArrayList<T> getAll() throws PersistenceException {
        
     SqlSession session = sf.openSession(); 
     ArrayList<T> list = null;
  try
  {     
   String query = NAMESPACE+"."+PREFIX_SELECT_QUERY+"All"+this.type.getSimpleName();
   list = (ArrayList<T>)session.selectList(query); 
  }
  finally
  {
   session.close();
  }   
  return list;
    }
    
    /** 
     *  Method returns first object which matches the given name (exact match).
     *  </br></br>  
     *  It's up to you to decide what constitutes an object's name. Typically you would have a 
     *  NAME column in the table, but not all objects have this. Generally this method should be overriden (if you need it at all)
     *  in the child dao class.
     *  </br></br>
     *  Example:
     *  </br>  
     *  If your DAO object is called CarInfo.java, 
     *  the corresponding mapper query id should be: &lt;select id="getCarInfoByName" ...  
     *  </br></br>  
     *  SQL Executed (example): select * from [tablename] where NAME = ? 
     *  
     */
    public T getByName(String name) throws PersistenceException {
        
     SqlSession session = sf.openSession();
     T obj = null;
  try
  { 
   String query = NAMESPACE+"."+PREFIX_SELECT_QUERY+this.type.getSimpleName()+"ByName";
   obj = (T)session.selectOne(query,name);   
  }
  finally
  {
   session.close();
  }
  return obj;
    }
    
    
    /** 
     *  Method inserts the object into the table.
     *  </br></br>
     *  You will usually override this method, especially if you're inserting associated objects.
     *  </br> 
     *  Example:
     *  </br>  
     *  If your DAO object is called CarInfo.java, 
     *  the corresponding mapper query id should be: &lt;insert id="createCarInfo" ...  
     *  </br></br>  
     *  SQL Executed (example): insert into [tablename] (fieldname1,fieldname2,...) values(value1,value2...) ... 
     *  
     */
    public int create(T o) throws PersistenceException{        
     SqlSession session = sf.openSession();
     Integer status = null;
     try
  {   
      String query = NAMESPACE+"."+PREFIX_INSERT_QUERY+o.getClass().getSimpleName();
   status = (Integer)session.insert(query,o);
   session.commit();   
  }
  finally
  {
   session.close();
  }  
  return status;
    }
    
    
    /** 
     *  Method updates the object by id.
     *  </br></br>
     *  You will usually override this method. But it can be used for simple objects.
     *  </br> 
     *  Example:
     *  </br>  
     *  If your DAO object is called CarInfo.java, 
     *  the corresponding mapper query id should be: &lt;update id="updateCarInfo" ...  
     *  </br></br>  
     *  SQL Executed (example): update [tablename] set fieldname1 = value1 where id = #{id} 
     *  
     */
    public int update(T o)throws PersistenceException {
        
     SqlSession session = sf.openSession();
  Integer status = null;
     try
  {   
   String query = NAMESPACE+"."+PREFIX_UPDATE_QUERY+o.getClass().getSimpleName();
      status = session.update(query,o);
   session.commit();
   
  }
  finally
  {
   session.close();
  } 
  return status;
     
    }

    
    /** 
     *  Method deletes the object by id.
     *  </br></br>
     *  Example:
     *  </br>  
     *  If your DAO object is called CarInfo.java, 
     *  the corresponding mapper query id should be: &lt;delete id="deleteCarInfo" ...  
     *  </br></br>  
     *  SQL Executed (example): update [tablename] set fieldname1 = value1 where id = #{id} 
     *  
     */
    public int delete(PK id)  throws PersistenceException{
  SqlSession session = sf.openSession();
  Integer status = null;
  try
  {   
   String query = NAMESPACE+"."+PREFIX_DELETE_QUERY+this.type.getSimpleName();
   status = session.delete(query,id);
   session.commit();
  } 
  finally
  {
   session.close();
  } 
  return status;
  
    }
}

Naming Convetions

You'll notice there are four prefix constants defined in the class above.

The reason for this is to keep consistency between the sql query ids you will define in the mybatis mapper.xml files (see Step 4) and the method names defined in the MyBatisDAO class we're implementing.

This won't work exactly like ActiveRecord or similar frameworks where there is a pluralization engine but it will still simplify things a lot.

For example, if you have an object called Status for which you will create a DAO, you will have to define the following mybatis querries

Java Method MyBatis Query Id Convention
dao.get(1) <select id="getStatus" ... getClassName
dao.getAll() <select id="getAllStatus" ... getAllClassName
dao.getByName(String name) <select id="getStatusByName" ... getClassNameByName
dao.create(obj) <insert id="createStatus" ... createClassName
dao.update(obj) <update id="updateStatus" ... updateClassName
dao.delete(id) <delete id="deleteStatus" ... deleteClassName

Don't worry, this will make a lot more sense once you get to Step 4

Step 3 - Write the actual DAO classes

Now you need to implement your concrete DAO classes.

Let's say you have a simple object called Status which maps to a simple table, and has 2 attributes, an ID and a NAME. Think of it as an object you could use to represent the status of a task. I chose this to illustrate a very basic example here

The table for this object would look like this

ID NAME
1 Done
2 In Progress
3 Not Started

And the java class (or DTO object) would look like this (Status.java)


public class Status 
{
 private int id;
 private String name;
 
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
 
 @Override
 public String toString() {  
  return "[Status] " + "(" + id + ") " + name;
 }
}

Writing the DAO class for the Status object now becomes trivial since you're inheriting all the default CRUD methods from MyBatisDAO.java defined above.

Here's how the StatusDAO.java should look:


import org.apache.ibatis.session.SqlSessionFactory;

import com.idleworx.mybatisdao.MyBatisDAO;
import com.idleworx.mybatisdao.tests.objects.Status;

public class StatusDAO extends MyBatisDAO<Status,Integer>{
 
 //Don't forget to define the default custom constructor when implementing a new 
 //child DAO class, and set the class type accordingly 
 public StatusDAO(Class<Status> type,SqlSessionFactory containerSessionFactory) {
  super(type,containerSessionFactory);
 }
 
}

You'll notice here that all you need to do is call the constructor from the parent MyBatisDAO.java class. Now all the default CRUD methods are available for the StatusDAO.java class.

You are free of course to add any additional methods as needed here that go beyond the CRUD methods that were defined. For example something like

getStatusForBlog(Integer blogId).

See the full code example.
Both the MyBatisDAO.java and IParentDAO.java classes are included.

Of course you will still have to define the MyBatis mapper SQL statements for the default CRUD methods defined in MyBatisDAO.java, as well as additional SQLs for other DAO methods you choose to implement. Which brings us to the next step ...

Step 4 - Defining the mybatis mapper

The last major step in the puzzle, is writing the actual SQL that will implement all the default CRUD methods and any other methods you've implemented for the Status object.

Your code may differ of course, but note the use of the naming conventions for naming the sql statements which I talked about earlier.

That is the key to this whole thing, and it will make your life a lot easier when writing other DAOs which extend the MyBatisDAO class.

Here is an example of how the mapper file for the StatusDAO object would look like.

StatusMapper.xml


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="mappers">
 
 <select id="getStatus" parameterType="int" resultType="Status">
  select 
   status_id as "id",
   status_name as "name"
  from daohelper.status where status_id = #{id}
 </select>
 
 <select id="getAllStatus" parameterType="int" resultType="Status">
  select 
   status_id as "id",
   status_name as "name"
  from daohelper.status order by status_id
 </select>
 
 <select id="getStatusByName" parameterType="int" resultType="Status">
  select 
   status_id as "id",
   status_name as "name"
  from daohelper.status where status_name = #{name}
 </select>
 
 <insert id="createStatus" keyColumn="status_id" useGeneratedKeys="true" parameterType="Status">
  insert into daohelper.status (status_name)
  values (#{name})  
 </insert>
 
 <update id="updateStatus" parameterType="Status">
  update daohelper.status set status_name = #{name} where status_id = #{id}  
 </update>
 
 <delete id="deleteStatus" parameterType="int">
  delete from daohelper.status where status_id = #{id}  
 </delete> 
 
</mapper>

Note here the use of the mapper namespace which is the same as referenced by the MyBatisDAO abstract class.

It's used for convenience in this case, and generally you should be able to use multiple mapper files with the same namespace as long as the you don't have multiple queries with the same id across several xml mapper files (which would be a bad idea anyway)

Errors

Just a side note on some errors you may encounter.

If you call one of the default CRUD methods but don't define the appropriate query in the mapper.xml file, you will get an error like this:

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mappers.getAllFrog
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for mappers.getAllFrog

Wrapping it up

By this point I hope you've managed to build yourself a small but working DAO implementation based on the MyBatisDAO abstract class.

You can download the full code example for more a better overview.

It also contains a jUnit example, the mybatis configuration file (mybatis.config.xml) as well as the simple DDL statments for setting up the MySQL table.

Note:If you need to use this from a Servlet or Spring controller, see my other blog post about defining a servletcontextlistener

Hope you found this useful. Improvements or suggestions are welcome.

June 28, 2011

Creating a simple android app with 2 buttons

How do I build a very simple android app you ask? It's easy, building a basic android application is not that hard. Making something really useful, cool and bug free, now that takes a good developer.

This is a brief tutorial will show you how to code a very basic two button android application (with a start button and a stop button).

You can use this code as an android project template or starting point for simple projects.

Two Button Application Use Case

A simple two button application, can be your starting point for various android projects. It can be useful for example when you have an application that starts and stops a service from the click of a button Watch for tutorial on this soon.

Note:This tutorial assumes you have completed the HelloWorld Tutorial in the Android docs and you are a little familiar with Eclipse and ADT. The tutorial is aimed at developers who are very new to Android.

Creating a two button app

1) Create the project

In Eclipse create a new Android project and define the properties as shown below. Feel free to use your own package names.

2) Create a simple layout

For our main activity we're going to define a very basic layout consisting of one TextView and two Buttons (a start button and a stop button).

Modify your project/res/layout/main.xml file to this:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="This is a simple two button app. \r\n \r\n Tell your user what your app does here \r\n \r\n \r\n \r\n"
    android:padding="10dp"
    android:textColor="#FFFFFF"
    />
<Button
 android:id="@+id/buttonStart"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Start"/>
<Button
 android:id="@+id/buttonStop"
 android:layout_width="fill_parent"
 android:layout_height="wrap_content"
 android:text="Stop"/>
</LinearLayout>

If you run your project in the emulator it should look like this

3) Adding onClickListeners to the buttons

In order for the buttons to actually do something useful, and to provide a template for where you can put future functionality, we'll need to define onClickListeners for each button.

Let's update the TwoButtonApp.java main activiy with the following code:


package com.idleworx.android.twobuttonapp;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class TwoButtonApp extends Activity {
    
 private static String logtag = "TwoButtonApp";//for use as the tag when logging 
  
 /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button buttonStart = (Button)findViewById(R.id.buttonStart);        
     buttonStart.setOnClickListener(startListener); // Register the onClick listener with the implementation above
      
     Button buttonStop = (Button)findViewById(R.id.buttonStop);        
     buttonStop.setOnClickListener(stopListener); // Register the onClick listener with the implementation above
    }
    
    //Create an anonymous implementation of OnClickListener
    private OnClickListener startListener = new OnClickListener() {
        public void onClick(View v) {
          Log.d(logtag,"onClick() called - start button");              
          Toast.makeText(TwoButtonApp.this, "The Start button was clicked.", Toast.LENGTH_LONG).show();
          Log.d(logtag,"onClick() ended - start button");
        }
    };
    
    // Create an anonymous implementation of OnClickListener
    private OnClickListener stopListener = new OnClickListener() {
        public void onClick(View v) {
         Log.d(logtag,"onClick() called - stop button"); 
         Toast.makeText(TwoButtonApp.this, "The Stop button was clicked.", Toast.LENGTH_LONG).show();
          Log.d(logtag,"onClick() ended - stop button");
        } 
    };
    
    
    @Override
 protected void onStart() {//activity is started and visible to the user
  Log.d(logtag,"onStart() called");
  super.onStart();  
 }
 @Override
 protected void onResume() {//activity was resumed and is visible again
  Log.d(logtag,"onResume() called");
  super.onResume();
  
 }
 @Override
 protected void onPause() { //device goes to sleep or another activity appears
  Log.d(logtag,"onPause() called");//another activity is currently running (or user has pressed Home)
  super.onPause();
  
 }
 @Override
 protected void onStop() { //the activity is not visible anymore
  Log.d(logtag,"onStop() called");
  super.onStop();
  
 }
 @Override
 protected void onDestroy() {//android has killed this activity
   Log.d(logtag,"onDestroy() called");
   super.onDestroy();
 }
}

Notes

  • As you can see, each button (or any resource for that matter) can be retrieved by the id was associated with in the layout:
    @+id/buttonStart 
    
    can be retreived with:
    
    Button buttonStart = (Button)findViewById(R.id.buttonStart);  
    
  • We have attached two anonymous OnClickListeners() to each of our two buttons
  • Each listener displays a simple Toast (a brief message to the user).
  • Logging is very important especially during debugging, so make sure you use it where ever you need
  • Not the logtag variable defined in the very top. It's a quick shortcut to save time when logging statements in your app with the Log.X methods. I usually use the same name as the class name and use the Create Filter option in the LogCat view to filter my code out.
  • For easier debugging I've added logging of all the other lifecycle methods in the Activity. When you do debugging of your apps it's very important to understand the lifecycle of an android app, and even more important to see how it's called in relation to your code.

So this is it, Introduction to Android 101. You should now have a very basic android app running.

For reference here is how your AndroidManifest.xml file should look (you should not have had to modify this file so far if you have followed this tutorial):


<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.idleworx.android.twobuttonapp"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="8" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".TwoButtonApp"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>

June 19, 2011

First Android App Goes Live

I've taken an interest in Android App Development a few months ago, and tonight I decided to launch the first android app I created.

It's a very simple taxi finder app targeted for people in Bucharest, Romania.

If you ever find yourself in Bucharest, Romania and you need a taxi, and you happen to have an android phone, make sure to install this app. It may just be what you need. From the Android market you can search for "vreau taxi" or check out the link below:

VreauTaxi

The goal of this was to learn the whole process of android app development from top to bottom and I think it went rather well despite a few painful hours dealing with Windows 7 Android USB device installation issues.

I will write more about Android soon, as some new blog post ideas have been rolling through my head.

February 3, 2011

The IdleWorx Monster MyBatis Tutorial

Building an entire Java web application with MyBatis 3, Tomcat, MySQL and Eclipse (on Windows 7)

This is a multi part tutorial which will show you how to build a Servlet/JSP based web application from scratch, using MySQL, Tomcat and MyBatis (the new version of the iBatis framework) on a windows platform using Eclipse.

You will make the most of this tutorial if

  • You have built at least a few small webapplications in the past.
  • You know how to setup Tomcat 5.x or higher version
  • You are somewhat familiar with the Eclipse IDE
  • You are familiar with SQL.
  • You know how to set-up MySQL on your development box and integrate it with your java web application.

Let's get started

To see how Tomcat, MyBatis and MySQL work together we're going to create a tiny java web application in Eclipse, called ModelingAgency.

If you don't want to follow the whole tutorial, you can skip through to the different sections below and pick out the information you need, otherwise continue to Part 1 - The Setup

Table of Contents

At the end of this tutorial you will hopefully be able to create a basic Java JSP/Servlet based webapp with MyBatis, MySQL and Tomcat in an Eclipse environment.

You can download a full version of finished ModelingAgency webapp here.

This tutorial took me a long time to write, so if you found it useful in any way, if you found errors with it or you think something is missing, please let me know and I will do my best to improve it.