In this section we will enhance the console application to create and read timecards using the
TimeTrackingService. We will need to add custom code to the business and data
access layers to make the application work.
TimeTrackerConsole.java at
C:/timetracker/console/src/java/org/andromda/timetracker/console.main() method in TimeTrackerConsole.java.
publicstaticvoidmain(String[] args) {// Get servicesserviceLocator = ServiceLocator.instance(); peopleService = serviceLocator.getPeopleService(); timeTrackingService = serviceLocator.getTimeTrackingService();// Create peoplePersonVO naresh = createPerson("nbhatia","Naresh","Bhatia"); PersonVO louis = createPerson("lcoude","Louis","Coude"); PersonVO john = createPerson("jsmith","John","Smith");// Create tasksTaskVO research = createTask("Research"); TaskVO development = createTask("Development");// Create timecardsTimecardVO timecard1 = createTimecard(naresh, john); TimecardVO timecard2 = createTimecard(naresh, john); TimecardVO timecard3 = createTimecard(louis, john); TimecardVO timecard4 = createTimecard(louis, john);// Fetch and show all objects created abovePersonVO[] people = peopleService.getAllPeople(); showPeople(people); TaskVO[] tasks = timeTrackingService.getAllTasks(); showTasks(tasks); TimecardSummaryVO[] timecards = timeTrackingService.getAllTimecardSummaries(); showTimecardSummaries(timecards);// Fetch and show timecard1 detailsSystem.out.println("Timecard "+ timecard1.getId() +" Details:"); TimecardVO timecard1FromDB = timeTrackingService.getTimecard(timecard1.getId()); showTimecard(timecard1FromDB); }
createTask() and createTimecard()
methods call the TimeTrackingService to perform these
functions. Following that we fetch all the people, tasks and timecards
that exist in the database and display them.ttconsole
target as follows: maven -o ttconsole. Of course, there is no
hope of running this application successfully yet as much of the service
layer has not been implemented. We will now try to make the application
run successfully one step at a time.TimeTrackerConsole's createTask() simply calls TimeTrackingService's
createTask() which is not yet implemented. So let us implement that method first. Open
TimeTrackingServiceImpl.java and fill in the handleCreateTask() method as follows:
protectedjava.lang.Long handleCreateTask(org.andromda.timetracker.vo.TaskVO taskVO)throwsjava.lang.Exception { Task task = Task.Factory.newInstance(); getTaskDao().taskVOToEntity(taskVO, task,true); getTaskDao().create(task);returntask.getId(); }
Review the default implementation of taskVOToEntity() in
TaskDaoBase.java. This implementation should work just fine.
Now add the import statements shown below near the top of TimeTrackingServiceImpl.java
(below the package statement):
packageorg.andromda.timetracker.service;importjava.util.Collection;importorg.andromda.timetracker.domain.*;importorg.andromda.timetracker.vo.*;
We should be able to create tasks now. Compile core by executing the command
maven -o core and run the application using maven -o run.
Output from this run is shown below.
C:/timetracker>maven -o run
...
[java] Person 1 created - nbhatia
[java] Person 2 created - lcoude
[java] Person 3 created - jsmith
[java] Task 1 created - Research
[java] Task 2 created - Development
[java] Exception in thread "main" java.lang.NullPointerException
[java] at org.andromda.timetracker.console.TimeTrackerConsole.createTimecard(TimeTrackerConsole.java:94)
[java] at org.andromda.timetracker.console.TimeTrackerConsole.main(TimeTrackerConsole.java:42)
[java] [ERROR] Java Result: 1
Notice that tasks are being created successfully. You can verify this by querying your database.
However, we get a NullPointerException in TimeTrackerConsole.java. After looking at
code in this area it is clear that timeTrackingService.getAllTasks() is returning
null. This is obviously the case because that method has not been implemented yet.
Implement the method as shown below by calling TaskDao.loadAll():
protectedorg.andromda.timetracker.vo.TaskVO[] handleGetAllTasks()throwsjava.lang.Exception { Collection tasks = getTaskDao().loadAll(TaskDao.TRANSFORM_TASKVO);return(TaskVO[])tasks.toArray(newTaskVO[tasks.size()]); }
Compile core by executing the command maven -o core.
Before we run the application again we must wipe the database and recreate the schema.
Execute the command maven -o drop-schema create-schema to
start with a clean database. Now run the application by executing maven -o run.
Output from this run is shown below.
C:/timetracker>maven -o run
...
[java] Person 1 created - nbhatia
[java] Person 2 created - lcoude
[java] Person 3 created - jsmith
[java] Task 1 created - Research
[java] Task 2 created - Development
[java] Timecard null created with 3 allocations
[java] Timecard null created with 1 allocations
[java] Timecard null created with 1 allocations
[java] Timecard null created with 1 allocations
...
Much better! It seems that tasks are being retrieved correctly now. The next hurdle to cross is the creation of timecards.
Looking at the code in TimeTrackerConsole.createTimecard() it is
clear that timeTrackingService.createTimecard() is returning null.
The reason is that createTimecard() has not been implemented in
TimeTrackingService. So open TimeTrackingServiceImpl.java
under C:/timetracker/core/src/java/org/andromda/timetracker/service and
implement handleCreateTimecard() as follows:
protected java.lang.Long handleCreateTimecard(org.andromda.timetracker.vo.TimecardVO timecardVO)
throws java.lang.Exception
{
// Create new timecard from timecardVO
Timecard timecard = Timecard.Factory.newInstance();
getTimecardDao().timecardVOToEntity(timecardVO, timecard, true);
// Set submitter and approver associations
timecard.setSubmitter(getPersonDao().findByUsername(timecardVO.getSubmitterName()));
timecard.setApprover(getPersonDao().findByUsername(timecardVO.getApproverName()));
// Set allocations
TimeAllocationVO allocations[] = timecardVO.getAllocations();
for (int i=0; i<allocations.length; i++) {
// Create TimeAllocation from TimeAllocationVO
TimeAllocationVO allocationVO = allocations[i];
TimeAllocation allocation = TimeAllocation.Factory.newInstance();
getTimeAllocationDao().timeAllocationVOToEntity(allocationVO, allocation, true);
// Connect to timecard
timecard.addTimeAllocation(allocation);
// Connect to task
allocation.setTask(getTaskDao().load(allocationVO.getTaskId()));
}
// Create the timecard
getTimecardDao().create(timecard);
return timecard.getId();
}
Looking at TimeAllocationDaoBase.java, it is clear that
AndroMDA does not handle conversion of embedded values when converting
VOs to entities and vice-versa. We will need to write some custom code
in TimeAllocationDaoImpl.java to do that conversion. This
file is generated in the directory C:/timetracker/core/src/java/org/andromda/timetracker/domain.
Make the following modifications to the file:
packageorg.andromda.timetracker.domain;importorg.andromda.timetracker.vo.TimeAllocationVO;importorg.andromda.timetracker.vo.TimePeriodVO;
toTimeAllocationVO() methods as follows:
public void toTimeAllocationVO(
org.andromda.timetracker.domain.TimeAllocation sourceEntity,
org.andromda.timetracker.vo.TimeAllocationVO targetVO)
{
super.toTimeAllocationVO(sourceEntity, targetVO);
TimePeriod timePeriod = sourceEntity.getTimePeriod();
targetVO.setTimePeriodVO(
new TimePeriodVO(timePeriod.getStartTime(), timePeriod.getEndTime()));
targetVO.setTaskId(sourceEntity.getTask().getId());
}
public org.andromda.timetracker.vo.TimeAllocationVO toTimeAllocationVO(final org.andromda.timetracker.domain.TimeAllocation entity)
{
TimeAllocationVO targetVO = new TimeAllocationVO();
toTimeAllocationVO(entity, targetVO);
return targetVO;
}
timeAllocationVOToEntity() method as follows:
public void timeAllocationVOToEntity(
org.andromda.timetracker.vo.TimeAllocationVO sourceVO,
org.andromda.timetracker.domain.TimeAllocation targetEntity,
boolean copyIfNull)
{
super.timeAllocationVOToEntity(sourceVO, targetEntity, copyIfNull);
TimePeriodVO timePeriodVO = sourceVO.getTimePeriodVO();
targetEntity.setTimePeriod(
TimePeriod.newInstance(timePeriodVO.getStartTime(), timePeriodVO.getEndTime()));
}
We need similar changes to the TimecardDaoImpl class:
packageorg.andromda.timetracker.domain;importjava.util.ArrayList;importjava.util.Collection;importorg.andromda.timetracker.ServiceLocator;importorg.andromda.timetracker.vo.TimeAllocationVO;importorg.andromda.timetracker.vo.TimecardSummaryVO;importorg.andromda.timetracker.vo.TimecardVO;
toTimecardSummaryVO() methods as follows:
public void toTimecardSummaryVO(
org.andromda.timetracker.domain.Timecard sourceEntity,
org.andromda.timetracker.vo.TimecardSummaryVO targetVO)
{
super.toTimecardSummaryVO(sourceEntity, targetVO);
targetVO.setSubmitterName(sourceEntity.getSubmitter().getUsername());
targetVO.setApproverName(sourceEntity.getApprover().getUsername());
}
public org.andromda.timetracker.vo.TimecardSummaryVO toTimecardSummaryVO(final org.andromda.timetracker.domain.Timecard entity)
{
TimecardSummaryVO targetVO = new TimecardSummaryVO();
toTimecardSummaryVO(entity, targetVO);
return targetVO;
}
toTimecardVO() methods as follows:
public void toTimecardVO(
org.andromda.timetracker.domain.Timecard sourceEntity,
org.andromda.timetracker.vo.TimecardVO targetVO)
{
toTimecardSummaryVO(sourceEntity, targetVO);
// Create allocations
Collection allocations = new ArrayList(sourceEntity.getAllocations());
((TimeAllocationDao)ServiceLocator.instance().getService("timeAllocationDao"))
.toTimeAllocationVOCollection(allocations);
targetVO.setAllocations((TimeAllocationVO[])allocations
.toArray(new TimeAllocationVO[allocations.size()]));
}
public org.andromda.timetracker.vo.TimecardVO toTimecardVO(final org.andromda.timetracker.domain.Timecard entity)
{
TimecardVO targetVO = new TimecardVO();
toTimecardVO(entity, targetVO);
return targetVO;
}
Finally we want to implement two methods in TimeTrackingServiceImpl.java
so that timecards can be retrieved for display. Here are the two methods:
protected org.andromda.timetracker.vo.TimecardVO handleGetTimecard(java.lang.Long id)
throws java.lang.Exception
{
return (TimecardVO)getTimecardDao().load(TimecardDao.TRANSFORM_TIMECARDVO, id);
}
protected org.andromda.timetracker.vo.TimecardSummaryVO[] handleGetAllTimecardSummaries()
throws java.lang.Exception
{
Collection timecards = getTimecardDao().loadAll(TimecardDao.TRANSFORM_TIMECARDSUMMARYVO);
return (TimecardSummaryVO[])timecards.toArray(new TimecardSummaryVO[timecards.size()]);
}
Compile the application by executing the command maven -o clean install.
Before we run the application again we must wipe the database and recreate the schema.
Execute the command maven -o drop-schema create-schema to
start with a clean database. Now run the application by executing maven -o run.
The application runs successfully all the way! Output from this run is shown below.
[java] Person 1 created - nbhatia
[java] Person 2 created - lcoude
[java] Person 3 created - jsmith
[java] Task 1 created - Research
[java] Task 2 created - Development
[java] Timecard 1 created with 3 allocations
[java] Timecard 2 created with 1 allocations
[java] Timecard 3 created with 2 allocations
[java] Timecard 4 created with 2 allocations
[java] People:
[java] 1: nbhatia - Naresh Bhatia
[java] 2: lcoude - Louis Coude
[java] 3: jsmith - John Smith
[java]
[java] Tasks:
[java] 1: Research
[java] 2: Development
[java]
[java] Timecards:
[java] 1: status=DRAFT, begin date=2006-02-01 04:23:33.0, comments=On track!, submitter=nbhatia, approver=jsmith
[java] 2: status=DRAFT, begin date=2006-02-01 04:23:33.0, comments=On track!, submitter=nbhatia, approver=jsmith
[java] 3: status=DRAFT, begin date=2006-02-01 04:23:34.0, comments=On track!, submitter=lcoude, approver=jsmith
[java] 4: status=DRAFT, begin date=2006-02-01 04:23:34.0, comments=On track!, submitter=lcoude, approver=jsmith
[java]
[java] Timecard 1 Details:
[java] 1: status=DRAFT, begin date=2006-02-01 04:23:33.0, comments=On track!, submitter=nbhatia, approver=jsmith
[java] 1: start time=2006-02-03 04:23:33.0, end time=2006-02-04 04:23:33.0, task id=2
[java] 2: start time=2006-02-02 04:23:33.0, end time=2006-02-03 04:23:33.0, task id=1
[java] 3: start time=2006-02-01 04:23:33.0, end time=2006-02-02 04:23:33.0, task id=1
In this guide we have made sure we have everything installed to start writing MDA projects using AndroMDA, but that's just the start .. there are several different cartridges you can use, or maybe, if you can't find one you like, you can write one yourself and contribute to the AndroMDA project.
Another thing you can try is to build a GUI front-end for the TimeTracker application. You can refer to the How-to Guides to learn about the Bpm4Struts cartridge which can be used to build Struts front-ends.
In any case you will need to learn about UML, MDA and modeling techniques and best practices. Perhaps
a good idea would be to take a look at the samples included in the binary distribution, each one of
them includes a model. Such a distribution is found here:
AndroMDA
project page
. Please note that the samples in the distribution still need to be built if you
want to see the generated sources or ant to deploy it
(just go into a sample and invoke maven, nothing more to it).