Salome HOME
Document id generation is fixed. Document index is updated in the database now.
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / StepServiceImpl.java
1 /*****************************************************************************
2  * Company         OPEN CASCADE
3  * Application     SIMAN
4  * File            $Id$ 
5  * Creation date   06.10.2012
6  * @author         $Author$
7  * @version        $Revision$
8  *****************************************************************************/
9
10 package org.splat.service;
11
12 import java.io.IOException;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16
17 import org.splat.dal.bo.kernel.Relation;
18 import org.splat.dal.bo.som.ConvertsRelation;
19 import org.splat.dal.bo.som.Document;
20 import org.splat.dal.bo.som.DocumentType;
21 import org.splat.dal.bo.som.File;
22 import org.splat.dal.bo.som.KnowledgeElement;
23 import org.splat.dal.bo.som.ProjectElement;
24 import org.splat.dal.bo.som.Publication;
25 import org.splat.dal.bo.som.Scenario;
26 import org.splat.dal.bo.som.SimulationContext;
27 import org.splat.dal.bo.som.UsedByRelation;
28 import org.splat.dal.bo.som.UsesRelation;
29 import org.splat.dal.bo.som.VersionsRelation;
30 import org.splat.dal.dao.kernel.RelationDAO;
31 import org.splat.dal.dao.som.DocumentDAO;
32 import org.splat.dal.dao.som.FileDAO;
33 import org.splat.dal.dao.som.ProjectElementDAO;
34 import org.splat.dal.dao.som.PublicationDAO;
35 import org.splat.dal.dao.som.SimulationContextDAO;
36 import org.splat.dal.dao.som.VersionsRelationDAO;
37 import org.splat.kernel.InvalidPropertyException;
38 import org.splat.kernel.MismatchException;
39 import org.splat.kernel.MissedPropertyException;
40 import org.splat.kernel.MultiplyDefinedException;
41 import org.splat.kernel.NotApplicableException;
42 import org.splat.log.AppLogger;
43 import org.splat.service.technical.IndexService;
44 import org.splat.service.technical.ProjectSettingsService;
45 import org.splat.som.Revision;
46 import org.splat.som.Step;
47 import org.springframework.transaction.annotation.Transactional;
48
49 /**
50  * Step service implementation.
51  * 
52  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
53  */
54 public class StepServiceImpl implements StepService {
55
56         /**
57          * logger for the service.
58          */
59         public final static AppLogger LOG = AppLogger
60                         .getLogger(StepServiceImpl.class);
61         /**
62          * Injected index service.
63          */
64         private IndexService _indexService;
65         /**
66          * Injected document service.
67          */
68         private DocumentService _documentService;
69         /**
70          * Injected document type service.
71          */
72         private DocumentTypeService _documentTypeService;
73         /**
74          * Injected document DAO.
75          */
76         private DocumentDAO _documentDAO;
77         /**
78          * Injected relation DAO.
79          */
80         private RelationDAO _relationDAO;
81         /**
82          * Injected file DAO.
83          */
84         private FileDAO _fileDAO;
85         /**
86          * Injected simulation context service.
87          */
88         private SimulationContextService _simulationContextService;
89         /**
90          * Injected simulation context DAO.
91          */
92         private SimulationContextDAO _simulationContextDAO;
93         /**
94          * Injected project element DAO.
95          */
96         private ProjectElementDAO _projectElementDAO;
97         /**
98          * Injected versions relation DAO.
99          */
100         private VersionsRelationDAO _versionsRelationDAO;
101         /**
102          * Injected project service.
103          */
104         private ProjectSettingsService _projectSettings;
105         /**
106          * Injected publication DAO.
107          */
108         private PublicationDAO _publicationDAO;
109
110         /**
111          * {@inheritDoc}
112          * 
113          * @see org.splat.service.StepService#addSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext.Properties)
114          */
115         public SimulationContext addSimulationContext(final Step aStep,
116                         final SimulationContext.Properties dprop)
117                         throws MissedPropertyException, InvalidPropertyException,
118                         MultiplyDefinedException {
119                 SimulationContext context = new SimulationContext(dprop.setStep(aStep
120                                 .getStep()));
121                 return addSimulationContext(aStep, context);
122         }
123
124         /**
125          * {@inheritDoc}
126          * 
127          * @see org.splat.service.StepService#addSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext)
128          */
129         @Transactional
130         public SimulationContext addSimulationContext(final Step aStep,
131                         final SimulationContext context) {
132                 SimulationContext res = null;
133                 getSimulationContextService().hold(context); // Increments the reference count of simulation context
134                 if (aStep.getOwner().isSaved()) {
135                         try {
136                                 if (!context.isSaved()) {
137                                         getSimulationContextDAO().create(context);
138                                 }
139                                 aStep.getOwner().add(context);
140                                 aStep.getContex().add(context); // The context is also referenced from this (transient) Step
141                                 getProjectElementDAO().update(aStep.getOwner());
142                                 updateKnowledgeElementsIndex(aStep);
143                                 res = context;
144                         } catch (Exception error) {
145                                 LOG.debug(error.getMessage(), error);
146                         }
147                 } else { // Happens when copying a scenario
148                         aStep.getOwner().add(context);
149                         aStep.getContex().add(context); // The context is also referenced from this (transient) Step
150                         // In case of owner scenario, the Knowledge Element index will be updated later, when saving the scenario
151                         res = context;
152                 }
153                 return res;
154         }
155
156         /**
157          * Update lucene index of knowledge elements of a scenario or a study which the given step is related to.
158          * 
159          * @param aStep
160          *            the step (activity)
161          */
162         private void updateKnowledgeElementsIndex(final Step aStep) {
163                 Scenario[] scenarii;
164                 if (aStep.getOwner() instanceof Scenario) {
165                         scenarii = new Scenario[1];
166                         scenarii[0] = (Scenario) aStep.getOwner();
167                 } else {
168                         scenarii = aStep.getOwnerStudy().getScenarii();
169                 }
170                 try {
171                         for (int i = 0; i < scenarii.length; i++) {
172                                 Scenario scene = scenarii[i];
173                                 List<KnowledgeElement> knelm = scene.getAllKnowledgeElements();
174                                 for (Iterator<KnowledgeElement> j = knelm.iterator(); j
175                                                 .hasNext();) {
176                                         KnowledgeElement kelm = j.next();
177                                         getIndexService().update(kelm);
178                                 }
179                                 updateScenarioIndex(scene);
180                         }
181                 } catch (Exception error) {
182                         LOG.error("Unable to re-index Knowledge Elements, reason:", error);
183                 }
184         }
185
186         /**
187          * Update lucene index for knowledge elements of the scenario.
188          * 
189          * @param scene
190          *            the scenario
191          * @throws IOException
192          *             if can't update lucene index
193          */
194         private void updateScenarioIndex(final Scenario scene) throws IOException {
195                 if (scene.getUcase() == null) {
196                         for (Iterator<KnowledgeElement> i = scene.getKnowledgeElements()
197                                         .iterator(); i.hasNext();) {
198                                 KnowledgeElement kelm = i.next();
199                                 if (!kelm.getType().equals("usecase")) {
200                                         continue;
201                                 }
202                                 scene.setUcase(kelm);
203                                 break;
204                         }
205                 }
206                 getIndexService().update(scene.getUcase());
207         }
208
209         /**
210          * {@inheritDoc}
211          * 
212          * @see org.splat.service.StepService#removeSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext)
213          */
214         @Transactional
215         public boolean removeSimulationContext(final Step aStep,
216                         final SimulationContext context) {
217                 SimulationContext torem = aStep
218                                 .getSimulationContext(context.getIndex());
219
220                 boolean isOk = (torem != null) && (aStep.getOwner().remove(torem));
221                 if (isOk) {
222
223                         aStep.getContex().remove(torem);
224                         getProjectElementDAO().update(aStep.getOwner());
225                         if (torem.isShared()) {
226                                 getSimulationContextService().release(torem);
227                                 getSimulationContextDAO().update(torem);
228                         } else {
229                                 getSimulationContextDAO().delete(torem);
230                         }
231                 }
232                 return isOk;
233         }
234
235         /**
236          * {@inheritDoc}
237          * 
238          * @see org.splat.service.StepService#createDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
239          */
240         @Transactional
241         public Publication createDocument(final Step aStep,
242                         final Document.Properties dprop) throws MissedPropertyException,
243                         InvalidPropertyException, MultiplyDefinedException, IOException {
244                 if (LOG.isDebugEnabled()) {
245                         LOG.debug("Local index before: "
246                                         + aStep.getOwnerStudy().getLastLocalIndex());
247                 }
248                 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
249                                 .setStep(aStep.getStep()));
250                 getDocumentService().generateDocumentId(newdoc, dprop);
251
252                 // Creation of the save directory
253                 java.io.File wdir = getDocumentService().getSaveDirectory(newdoc);
254                 if ((!wdir.exists()) && (!wdir.mkdirs())) {
255                         throw new IOException(
256                                         "Cannot create the repository vault directory");
257                 }
258
259                 // Identification and save
260                 aStep.getOwnerStudy().setLastLocalIndex(
261                                 dprop.getOwner().getOwnerStudy().getLastLocalIndex());
262                 if (LOG.isDebugEnabled()) {
263                         LOG.debug("Local index after: "
264                                         + dprop.getOwner().getOwnerStudy().getLastLocalIndex());
265                 }
266                 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwnerStudy());
267                 getDocumentDAO().create(newdoc);
268
269                 return new Publication(newdoc, aStep.getOwner());
270         }
271
272         /**
273          * {@inheritDoc}
274          * 
275          * @see org.splat.service.StepService#assignDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
276          */
277         public Publication assignDocument(final Step aStep,
278                         final Document.Properties dprop) throws MissedPropertyException,
279                         InvalidPropertyException, NotApplicableException {
280                 String refid = dprop.getReference();
281                 Publication res = null;
282                 if (refid != null) {
283                         Document slot = getDocumentService().selectDocument(refid,
284                                         new Revision().toString());
285                         if ((slot != null) && (slot.isUndefined())) {
286                                 getDocumentService().initialize(slot,
287                                                 dprop.setOwner(aStep.getOwnerStudy()));
288                                 res = new Publication(slot, aStep.getOwner());
289                         }
290                 }
291                 return res;
292         }
293
294         /**
295          * Create a new version of a document in the given study step.
296          * 
297          * @param aStep
298          *            the study step
299          * @param base
300          *            the base document published version
301          * @return the new version publication
302          * @throws MissedPropertyException
303          *             if a mandatory property is missed
304          * @throws InvalidPropertyException
305          *             if some property doesn't exist
306          * @throws MultiplyDefinedException
307          *             if some property is defined several times
308          * @throws IOException
309          *             if a file system error occurs
310          * @throws MismatchException
311          *             if the document is not applicable to the given study step
312          */
313         public Publication versionDocument(final Step aStep, final Publication base)
314                         throws MissedPropertyException, InvalidPropertyException,
315                         MultiplyDefinedException, IOException, MismatchException {
316                 return versionDocument(aStep, base, new Document.Properties());
317         }
318
319         /**
320          * Create a new version of a document in the given study step.
321          * 
322          * @param aStep
323          *            the study step
324          * @param base
325          *            the base document published version
326          * @param reason
327          *            the comment for the new version
328          * @return the new version publication
329          * @throws MissedPropertyException
330          *             if a mandatory property is missed
331          * @throws InvalidPropertyException
332          *             if some property doesn't exist
333          * @throws MultiplyDefinedException
334          *             if some property is defined several times
335          * @throws IOException
336          *             if a file system error occurs
337          * @throws MismatchException
338          *             if the document is not applicable to the given study step
339          */
340         public Publication versionDocument(final Step aStep,
341                         final Publication base, final String reason)
342                         throws MissedPropertyException, InvalidPropertyException,
343                         MultiplyDefinedException, IOException, MismatchException {
344                 return versionDocument(aStep, base, new Document.Properties()
345                                 .setDescription(reason));
346         }
347
348         /**
349          * Create a new version of a document in the given study step.
350          * 
351          * @param aStep
352          *            the study step
353          * @param base
354          *            the base document published version
355          * @param dprop
356          *            properties of the new version
357          * @return the new version publication
358          * @throws MissedPropertyException
359          *             if a mandatory property is missed
360          * @throws InvalidPropertyException
361          *             if some property doesn't exist
362          * @throws MultiplyDefinedException
363          *             if some property is defined several times
364          * @throws IOException
365          *             if a file system error occurs
366          * @throws MismatchException
367          *             if the document is not applicable to the given study step
368          */
369         @Transactional
370         public Publication versionDocument(final Step aStep,
371                         final Publication base, final Document.Properties dprop)
372                         throws MissedPropertyException, InvalidPropertyException,
373                         MultiplyDefinedException, IOException, MismatchException {
374                 Document previous = base.value();
375
376                 // RKV: Keep the new file format if it is related to the same document type on this step.
377                 String newFormat = dprop.getFormat();
378
379                 dprop.setDocument(previous, getProjectSettings().getStep(
380                                 base.getStep().getNumber())); // Initializes the Step property
381                 if (dprop.getStep().getNumber() != aStep.getNumber()) {
382                         throw new MismatchException();
383                 }
384
385                 if (newFormat != null
386                                 && previous.getType().equals(
387                                                 getProjectSettings().getDefaultDocumentType(
388                                                                 aStep.getStep(), newFormat))) {
389                         dprop.setFormat(newFormat);
390                 }
391
392                 if (dprop.getAuthor() == null) {
393                         dprop.setAuthor(previous.getAuthor());
394                 }
395                 String summary = dprop.getDescription();
396
397                 // Creation of the document
398                 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
399                                 .setStep(aStep.getStep()));
400                 getDocumentService().generateDocumentId(newdoc, dprop);
401                 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwner(),
402                                 previous);
403                 getDocumentDAO().create(newdoc);
404
405                 // Versioning
406                 VersionsRelation aRel;
407                 aRel = new VersionsRelation(newdoc, previous, summary);
408                 // getVersionsRelationDAO().create(aRel);
409                 newdoc.addRelation(aRel);
410
411                 // Update of usedby relations, if exist
412                 /*
413                  * RKV: Consider the new version as not used by old dependent documents. So these documents must be marked as outdated then. List<Relation>
414                  * relist = previous.getRelations(UsedByRelation.class); Study scope = aStep.getOwnerStudy(); for (Iterator<Relation> i =
415                  * relist.iterator(); i.hasNext();) { UsedByRelation relation = (UsedByRelation) i.next(); Document relatedoc = relation.getTo(); if
416                  * (scope.shares(relatedoc)) { relatedoc.addRelation(new UsesRelation(relatedoc, newdoc)); } else { relation.moveTo(newdoc); } }
417                  */
418                 return new Publication(newdoc, aStep.getOwner());
419         }
420
421         /**
422          * Get document types which are applicable for the given study step (activity).
423          * 
424          * @param aStep
425          *            the study step
426          * @return the list of document types
427          */
428         public List<DocumentType> getValidDocumentTypes(final Step aStep) {
429                 return getDocumentTypeService().selectTypesOf(aStep.getStep());
430         }
431
432         /**
433          * Add a document publication to the given step.
434          * 
435          * @param aStep
436          *            the target study step
437          * @param newdoc
438          *            the document publication to add
439          * @return true if publication succeeded
440          */
441         public boolean add(final Step aStep, final Publication newdoc) {
442                 boolean res = aStep.getOwner().add(newdoc); // Updates the study in memory
443                 if (res) {
444                         aStep.getDocuments().add(0, newdoc); // Updates this step
445                         getDocumentService().hold(newdoc.value()); // Increments the configuration tag count of document
446                         // If not yet saved, the Publication MUST NOT be saved here, although this creates a temporary inconsistent state into the
447                         // database (it will be saved later by cascading the update of owner scenario).
448                 }
449                 return res;
450         }
451
452         /**
453          * Remove a document publication from the given step.
454          * 
455          * @param aStep
456          *            the study step
457          * @param oldoc
458          *            the document publication to remove
459          * @return true if removing of the publication succeeded
460          */
461         public boolean remove(final Step aStep, final Publication oldoc) {
462                 aStep.getDocuments().remove(oldoc); // Updates this step
463                 // Synchronize with database
464                 ProjectElement owner = getProjectElementDAO().merge(aStep.getOwner());
465                 if (owner != null) {
466                         aStep.getOwner().remove(oldoc); // in transient copy
467                         owner.remove(oldoc); // in persistent copy
468                 }
469                 getDocumentService().release(oldoc.value()); // Decrements the configuration tag count of document
470                 // The publication becoming orphan, it should automatically be removed from the database when updating of owner scenario.
471                 return true;
472         }
473
474         /**
475          * Remove a document from the given step and from the database if it is no more used.
476          * 
477          * @param aStep
478          *            the study step
479          * @param docId
480          *            the document id
481          * @return true if removing of the document succeeded
482          */
483         @Transactional
484         public boolean removeDocument(final Step aStep, final long docId) {
485                 Publication torem = aStep.getDocument(docId);
486                 boolean res = (torem != null);
487                 if (res) {
488                         torem = getPublicationDAO().merge(torem);
489                         remove(aStep, torem);
490                         Document value = torem.value();
491                         if (!value.isPublished() && !value.isVersioned()) { // The referenced document is no more used
492                                 List<Document> using = new ArrayList<Document>();
493                                 List<Relation> converts = new ArrayList<Relation>();
494                                 for (Relation link : value.getAllRelations()) {
495                                         if (link.getClass().equals(ConvertsRelation.class)) { // File conversion
496                                                 converts.add(link);
497                                         } else if (link.getClass().equals(UsesRelation.class)) { // Document dependency
498                                                 using.add((Document) link.getTo());
499                                         }
500                                 }
501                                 // value.getAllRelations().removeAll(converts);
502                                 // Remove relations from depending documents
503                                 if (LOG.isDebugEnabled()) {
504                                         LOG.debug("Remove " + using.size() + " UsedByRelation(s).");
505                                 }
506                                 for (Document doc : using) {
507                                         if (LOG.isDebugEnabled()) {
508                                                 LOG.debug("Remove UsedByRelation from "
509                                                                 + doc.getTitle() + " to " + value.getTitle());
510                                         }
511                                         doc.removeRelation(UsedByRelation.class, value);
512                                 }
513                                 // Synchronize deleted objects with the database to avoid hibernate exception
514                                 // related with null value of not-nullable property because back reference from Document to Publication is not mapped:
515                                 // org.hibernate.PropertyValueException: not-null property references a null or transient value:
516                                 // org.splat.dal.bo.som.Publication.mydoc
517                                 getDocumentDAO().flush(); // To show to the database that files from ConvertsRelation(s) are deleted already
518                                 getDocumentDAO().delete(value); // The corresponding physical file is not removed from the vault
519                                 // Delete document's files
520                                 for (Relation link : converts) {
521                                         File file = (File) link.getTo();
522                                         getFileDAO().delete(file); // The corresponding physical file is not removed from the vault
523                                 }
524                         }
525                 }
526                 return res;
527         }
528
529         /**
530          * Get the documentService.
531          * 
532          * @return the documentService
533          */
534         public DocumentService getDocumentService() {
535                 return _documentService;
536         }
537
538         /**
539          * Set the documentService.
540          * 
541          * @param documentService
542          *            the documentService to set
543          */
544         public void setDocumentService(final DocumentService documentService) {
545                 _documentService = documentService;
546         }
547
548         /**
549          * Get the simulationContextService.
550          * 
551          * @return the simulationContextService
552          */
553         public SimulationContextService getSimulationContextService() {
554                 return _simulationContextService;
555         }
556
557         /**
558          * Set the simulationContextService.
559          * 
560          * @param simulationContextService
561          *            the simulationContextService to set
562          */
563         public void setSimulationContextService(
564                         final SimulationContextService simulationContextService) {
565                 _simulationContextService = simulationContextService;
566         }
567
568         /**
569          * Get the documentDAO.
570          * 
571          * @return the documentDAO
572          */
573         public DocumentDAO getDocumentDAO() {
574                 return _documentDAO;
575         }
576
577         /**
578          * Set the documentDAO.
579          * 
580          * @param documentDAO
581          *            the documentDAO to set
582          */
583         public void setDocumentDAO(final DocumentDAO documentDAO) {
584                 _documentDAO = documentDAO;
585         }
586
587         /**
588          * Get the simulationContextDAO.
589          * 
590          * @return the simulationContextDAO
591          */
592         public SimulationContextDAO getSimulationContextDAO() {
593                 return _simulationContextDAO;
594         }
595
596         /**
597          * Set the simulationContextDAO.
598          * 
599          * @param simulationContextDAO
600          *            the simulationContextDAO to set
601          */
602         public void setSimulationContextDAO(
603                         final SimulationContextDAO simulationContextDAO) {
604                 _simulationContextDAO = simulationContextDAO;
605         }
606
607         /**
608          * Get the projectElementDAO.
609          * 
610          * @return the projectElementDAO
611          */
612         public ProjectElementDAO getProjectElementDAO() {
613                 return _projectElementDAO;
614         }
615
616         /**
617          * Set the projectElementDAO.
618          * 
619          * @param projectElementDAO
620          *            the projectElementDAO to set
621          */
622         public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
623                 _projectElementDAO = projectElementDAO;
624         }
625
626         /**
627          * Get the indexService.
628          * 
629          * @return the indexService
630          */
631         public IndexService getIndexService() {
632                 return _indexService;
633         }
634
635         /**
636          * Set the indexService.
637          * 
638          * @param indexService
639          *            the indexService to set
640          */
641         public void setIndexService(final IndexService indexService) {
642                 _indexService = indexService;
643         }
644
645         /**
646          * Get the fileDAO.
647          * 
648          * @return the fileDAO
649          */
650         public FileDAO getFileDAO() {
651                 return _fileDAO;
652         }
653
654         /**
655          * Set the fileDAO.
656          * 
657          * @param fileDAO
658          *            the fileDAO to set
659          */
660         public void setFileDAO(final FileDAO fileDAO) {
661                 _fileDAO = fileDAO;
662         }
663
664         /**
665          * Get the documentTypeService.
666          * 
667          * @return the documentTypeService
668          */
669         public DocumentTypeService getDocumentTypeService() {
670                 return _documentTypeService;
671         }
672
673         /**
674          * Set the documentTypeService.
675          * 
676          * @param documentTypeService
677          *            the documentTypeService to set
678          */
679         public void setDocumentTypeService(
680                         final DocumentTypeService documentTypeService) {
681                 _documentTypeService = documentTypeService;
682         }
683
684         /**
685          * Get the versionsRelationDAO.
686          * 
687          * @return the versionsRelationDAO
688          */
689         public VersionsRelationDAO getVersionsRelationDAO() {
690                 return _versionsRelationDAO;
691         }
692
693         /**
694          * Set the versionsRelationDAO.
695          * 
696          * @param versionsRelationDAO
697          *            the versionsRelationDAO to set
698          */
699         public void setVersionsRelationDAO(
700                         final VersionsRelationDAO versionsRelationDAO) {
701                 _versionsRelationDAO = versionsRelationDAO;
702         }
703
704         /**
705          * Get project settings.
706          * 
707          * @return Project settings service
708          */
709         private ProjectSettingsService getProjectSettings() {
710                 return _projectSettings;
711         }
712
713         /**
714          * Set project settings service.
715          * 
716          * @param projectSettingsService
717          *            project settings service
718          */
719         public void setProjectSettings(
720                         final ProjectSettingsService projectSettingsService) {
721                 _projectSettings = projectSettingsService;
722         }
723
724         /**
725          * Get the publicationDAO.
726          * 
727          * @return the publicationDAO
728          */
729         public PublicationDAO getPublicationDAO() {
730                 return _publicationDAO;
731         }
732
733         /**
734          * Set the publicationDAO.
735          * 
736          * @param publicationDAO
737          *            the publicationDAO to set
738          */
739         public void setPublicationDAO(final PublicationDAO publicationDAO) {
740                 this._publicationDAO = publicationDAO;
741         }
742
743         /**
744          * Get the relationDAO.
745          * 
746          * @return the relationDAO
747          */
748         public RelationDAO getRelationDAO() {
749                 return _relationDAO;
750         }
751
752         /**
753          * Set the relationDAO.
754          * 
755          * @param relationDAO
756          *            the relationDAO to set
757          */
758         public void setRelationDAO(final RelationDAO relationDAO) {
759                 _relationDAO = relationDAO;
760         }
761 }