V. Trucs et astuces : finition du client console▲
Dans cette section, nous allons enrichir l'application console pour créer et lire des fiches de temps en utilisant le service TimeTrackingService. Nous allons devoir ajouter du code personnalisé aux couches métier et d'accès aux données afin de faire fonctionner l'application.
- Téléchargez l'application console à cette adresse (http://galaxy.andromda.org/docs/getting-started/java/resources/sample-code/timetracker/TimeTrackerConsole.java) et remplacez la copie existante de TimeTrackerConsole.java dans C:/timetracker/console/src/java/org/andromda/timetracker/console par le fichier que vous venez de télécharger.
- Passez en revue la méthode main dans le nouveau TimeTrackerConsole.java.
public
static
void
main
(
String[] args) {
// Get services
serviceLocator =
ServiceLocator.instance
(
);
peopleService =
serviceLocator.getPeopleService
(
);
timeTrackingService =
serviceLocator.getTimeTrackingService
(
);
// Create people
PersonVO naresh =
createPerson
(
"nbhatia"
, "Naresh"
, "Bhatia"
);
PersonVO louis =
createPerson
(
"lcoude"
, "Louis"
, "Coude"
);
PersonVO john =
createPerson
(
"jsmith"
, "John"
, "Smith"
);
// Create tasks
TaskVO research =
createTask
(
"Research"
);
TaskVO development =
createTask
(
"Development"
);
// Create timecards
TimecardVO 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 above
PersonVO[] people =
peopleService.getAllPeople
(
);
showPeople
(
people);
TaskVO[] tasks =
timeTrackingService.getAllTasks
(
);
showTasks
(
tasks);
TimecardSummaryVO[] timecards =
timeTrackingService.getAllTimecardSummaries
(
);
showTimecardSummaries
(
timecards);
// Fetch and show timecard1 details
System.out.println
(
"Timecard "
+
timecard1.getId
(
) +
" Details:"
);
TimecardVO timecard1FromDB =
timeTrackingService.getTimecard
(
timecard1.getId
(
));
showTimecard
(
timecard1FromDB);
}
Comme vous pouvez le voir, nous pouvons maintenant créer des tâches et des fiches en plus des personnes. Les méthodes createTask() et createTimecard() appellent le service TimeTrackingService pour réaliser ces opérations. Ensuite nous récupérons toutes les personnes, toutes les tâches et toutes les fiches de temps qui existent dans la base de données, et nous les affichons.
Assurez-vous que l'application console compile en exécutant la cible ttconsole comme suit: maven -o ttconsole. Bien sûr, il n'y a aucun espoir de pouvoir exécuter cette application avec succès pour l'instant puisque la plus grande partie de la couche métier n'a pas encore été implémentée (en particulier les méthodes de TimeTrackingService que nous avons modélisées à l'étape précédente). Nous allons maintenant essayer de rendre l'application exécutable, mais une étape à la fois.
V-A. Création des tâches▲
La méthode createTask() de TimeTrackerConsole appelle simplement la méthode createTask() de TimeTrackingService, que nous n'avons pas encore implémentée. Alors implémentons cette méthode pour commencer. Ouvrez le fichier TimeTrackingServiceImpl.java et remplissez la méthode handleCreateTask() comme suit:
protected
java.lang.Long handleCreateTask
(
org.andromda.timetracker.vo.TaskVO taskVO)
throws
java.lang.Exception
{
Task task =
Task.Factory.newInstance
(
);
getTaskDao
(
).taskVOToEntity
(
taskVO, task, true
);
getTaskDao
(
).create
(
task);
return
task.getId
(
);
}
Vérifiez l'implémentation par défaut de taskVOToEntity dans TaskDaoBase.java. Cette implémentation devrait fonctionner parfaitement.
Ajoutez maintenant les instructions import ci-dessous dans TimeTrackingServiceImpl.java (juste en dessous de l'instruction package):
package
org.andromda.timetracker.service;
import
java.util.Collection;
import
org.andromda.timetracker.domain.*;
import
org.andromda.timetracker.vo.*;
Nous devrions pouvoir créer des tâches maintenant. Compilez le module code en exécutant la commande « maven -o core », puis exécutez l'application grâce à la commande « maven -o run ». La sortie correspondante est recopiée ci-dessous.
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
Notez que les tâches sont bien créées avec succès. Vous pouvez le vérifier en jetant un œil à votre base de données. Toutefois, nous obtenons une NullPointerException dans TimeTrackerConsole.java. Après avoir regardé dans le code à la ligne spécifiée, il est clair que timeTrackingService.getAllTasks() retourne null. Et cela est tout à fait normal puisque cette méthode n'a pas encore été implémentée. Implémentez cette méthode comme indiqué ci-dessous en appelant TaskDao.loadAll():
protected
org.andromda.timetracker.vo.TaskVO[] handleGetAllTasks
(
)
throws
java.lang.Exception
{
Collection tasks =
getTaskDao
(
).loadAll
(
TaskDao.TRANSFORM_TASKVO);
return
(
TaskVO[])tasks.toArray
(
new
TaskVO[tasks.size
(
)]);
}
Compilez le module core en exécutant la commande « maven -o core ». Avant que nous ne puissions exécuter l'application à nouveau, nous devons réinitialiser la base de données en supprimant le schéma et en le recréant. Exécutez la commande « maven -o drop-schema create-schema » pour démarrer avec une nouvelle base de données. Ensuite, exécutez l'application grâce à la commande « maven -o run ». La sortie correspondante est reproduite ci-dessous.
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
...
Beaucoup mieux! Il semble que les tâches soient bien créées à présent. Le prochain obstacle à franchir est la création de fiches de temps.
V-B. Création de fiches de temps▲
En analysant le code dans TimeTrackerConsole.createTimecard(), il est clair que timeTrackingService.createTimecard() retourne null. Cela vient bien sûr du fait que createTimecard() n'a pas été implémentée dans TimeTrackingService. Il va donc vous falloir ouvrir TimeTrackingServiceImpl.java sous C:/timetracker/core/src/java/org/andromda/timetracker/service et implémenter handleCreateTimecard() comme suit:
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
(
);
}
En analysant TimeAllocationDaoBase.java, il est clair qu'AndroMDA ne gère pas la conversion de valeurs imbriquées lorsqu'il génère les méthodes de conversion d'objets de valeurs en entités, et vice-versa. Nous allons donc devoir ajouter du code dans TimeAllocationDaoImpl.java pour effectuer cette conversion. Ce fichier est généré dans le répertoire C:/timetracker/core/src/java/org/andromda/timetracker/domain. Apportez les modifications suivantes au fichier :
- ajoutez les instructions import suivantes après l'instruction package.
package
org.andromda.timetracker.domain;
import
org.andromda.timetracker.vo.TimeAllocationVO;
import
org.andromda.timetracker.vo.TimePeriodVO;
- implémentez les deux méthodes toTimeAllocationVO() comme suit:
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;
}
- implémentez la méthode timeAllocationVOToEntity() comme suit (attention à implémenter la bonne méthode, c'est-à-dire celle qui prend un paramètre copyIfNull):
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
(
)));
}
Nous devons apporter des changements similaires à la classe TimecardDaoImpl :
- ajoutez les instructions import suivantes après l'instruction package.
package
org.andromda.timetracker.domain;
import
java.util.ArrayList;
import
java.util.Collection;
import
org.andromda.timetracker.ServiceLocator;
import
org.andromda.timetracker.vo.TimeAllocationVO;
import
org.andromda.timetracker.vo.TimecardSummaryVO;
import
org.andromda.timetracker.vo.TimecardVO;
- implémentez les deux méthodes toTimecardSummaryVO() comme suit:
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;
}
Nous allons enfin implémenter deux méthodes dans TimeTrackingServiceImpl.java de façon à ce que les timecards puissent être retrouvées pour être affichées. Voici ces deux méthodes:
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
(
)]);
}
Compilez l'application en exécutant la commande « maven -o clean install ». Avant de pouvoir exécuter l'application à nouveau, nous devons encore effacer la base de données et recréer le schéma. Exécutez la commande « maven -o drop-schema create-schema » pour démarrer avec une base de données vide. Ensuite, exécutez l'application grâce à la commande « maven -o run ». L'application s'exécute avec succès jusqu'au bout! La sortie est reproduite ci-dessous.
[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
V-C. La suite des évènements▲
Dans ce tutoriel, nous nous sommes assurés d'avoir tout l'environnement installé pour pouvoir démarrer l'écriture de projets MDA en utilisant AndroMDA, mais ce n'est que le début. Il y a plusieurs cartridges différentes que vous pouvez utiliser, ou peut-être, si vous n'en trouvez aucune qui correspond à vos besoins, pourrez-vous en écrire une vous-même et la proposer à l'intégration dans le projet AndroMDA.
Une autre chose que vous pourrez essayer sera de construire une interface graphique utilisateur pour l'application TimeTracker. Vous pouvez vous référer aux guides pratiques (http://galaxy.andromda.org/docs/howto-guides.html) pour en savoir plus sur la cartridge Bpm4Struts qui peut être utilisée pour développer des interfaces web.
Quoi qu'il en soit, vous devrez en apprendre plus sur UML, MDA, les techniques et les meilleures pratiques de modélisation. Une bonne idée pourrait être également de jeter un œil aux exemples compris dans la distribution binaire, et notamment au modèle inclus dans chacun d'entre eux. Cette distribution peut être téléchargée depuis la page du projet AndroMDA: http://sourceforge.net/project/showfiles.php?group_id=73047. Notez toutefois que les exemples de la distribution doivent être construits si vous désirez voir les sources générées ou avant de les déployer. Pour ce faire, rendez-vous dans le dossier de l'exemple et invoquez maven, c'est tout.