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:
protectedjava.lang.Long handleCreateTimecard(org.andromda.timetracker.vo.TimecardVO timecardVO)throwsjava.lang.Exception {// Create new timecard from timecardVOTimecard timecard = Timecard.Factory.newInstance(); getTimecardDao().timecardVOToEntity(timecardVO, timecard,true);// Set submitter and approver associationstimecard.setSubmitter(getPersonDao().findByUsername(timecardVO.getSubmitterName())); timecard.setApprover(getPersonDao().findByUsername(timecardVO.getApproverName()));// Set allocationsTimeAllocationVO allocations[] = timecardVO.getAllocations();for(inti=0; i<allocations.length; i++) {// Create TimeAllocation from TimeAllocationVOTimeAllocationVO allocationVO = allocations[i]; TimeAllocation allocation = TimeAllocation.Factory.newInstance(); getTimeAllocationDao().timeAllocationVOToEntity(allocationVO, allocation,true);// Connect to timecardtimecard.addTimeAllocation(allocation);// Connect to taskallocation.setTask(getTaskDao().load(allocationVO.getTaskId())); }// Create the timecardgetTimecardDao().create(timecard);returntimecard.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:
publicvoidtoTimeAllocationVO( org.andromda.timetracker.domain.TimeAllocation sourceEntity, org.andromda.timetracker.vo.TimeAllocationVO targetVO) {super.toTimeAllocationVO(sourceEntity, targetVO); TimePeriod timePeriod = sourceEntity.getTimePeriod(); targetVO.setTimePeriodVO(newTimePeriodVO(timePeriod.getStartTime(), timePeriod.getEndTime())); targetVO.setTaskId(sourceEntity.getTask().getId()); }publicorg.andromda.timetracker.vo.TimeAllocationVO toTimeAllocationVO(finalorg.andromda.timetracker.domain.TimeAllocation entity) { TimeAllocationVO targetVO =newTimeAllocationVO(); toTimeAllocationVO(entity, targetVO);returntargetVO; }
timeAllocationVOToEntity()
method as follows:
publicvoidtimeAllocationVOToEntity( org.andromda.timetracker.vo.TimeAllocationVO sourceVO, org.andromda.timetracker.domain.TimeAllocation targetEntity,booleancopyIfNull) {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:
publicvoidtoTimecardSummaryVO( 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()); }publicorg.andromda.timetracker.vo.TimecardSummaryVO toTimecardSummaryVO(finalorg.andromda.timetracker.domain.Timecard entity) { TimecardSummaryVO targetVO =newTimecardSummaryVO(); toTimecardSummaryVO(entity, targetVO);returntargetVO; }
toTimecardVO()
methods as follows:
publicvoidtoTimecardVO( org.andromda.timetracker.domain.Timecard sourceEntity, org.andromda.timetracker.vo.TimecardVO targetVO) { toTimecardSummaryVO(sourceEntity, targetVO);// Create allocationsCollection allocations =newArrayList(sourceEntity.getAllocations()); ((TimeAllocationDao)ServiceLocator.instance().getService("timeAllocationDao")) .toTimeAllocationVOCollection(allocations); targetVO.setAllocations((TimeAllocationVO[])allocations .toArray(newTimeAllocationVO[allocations.size()])); }publicorg.andromda.timetracker.vo.TimecardVO toTimecardVO(finalorg.andromda.timetracker.domain.Timecard entity) { TimecardVO targetVO =newTimecardVO(); toTimecardVO(entity, targetVO);returntargetVO; }
Finally we want to implement two methods in TimeTrackingServiceImpl.java
so that timecards can be retrieved for display. Here are the two methods:
protectedorg.andromda.timetracker.vo.TimecardVO handleGetTimecard(java.lang.Long id)throwsjava.lang.Exception {return(TimecardVO)getTimecardDao().load(TimecardDao.TRANSFORM_TIMECARDVO, id); }protectedorg.andromda.timetracker.vo.TimecardSummaryVO[] handleGetAllTimecardSummaries()throwsjava.lang.Exception { Collection timecards = getTimecardDao().loadAll(TimecardDao.TRANSFORM_TIMECARDSUMMARYVO);return(TimecardSummaryVO[])timecards.toArray(newTimecardSummaryVO[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).