]> SALOME platform Git repositories - tools/siman.git/blob - Workspace/Siman-Common/src/org/splat/service/StepServiceImpl.java
Salome HOME
Fix: document removing is fixed. Unit tests for StudyDAO and StepService.removeDocume...
[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                 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
245                                 .setStep(aStep.getStep()));
246                 getDocumentService().generateDocumentId(newdoc, dprop);
247
248                 // Creation of the save directory
249                 java.io.File wdir = getDocumentService().getSaveDirectory(newdoc);
250                 if ((!wdir.exists()) && (!wdir.mkdirs())) {
251                         throw new IOException(
252                                         "Cannot create the repository vault directory");
253                 }
254
255                 // Identification and save
256                 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwnerStudy());
257                 getDocumentDAO().create(newdoc);
258
259                 return new Publication(newdoc, aStep.getOwner());
260         }
261
262         /**
263          * {@inheritDoc}
264          * 
265          * @see org.splat.service.StepService#assignDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
266          */
267         public Publication assignDocument(final Step aStep,
268                         final Document.Properties dprop) throws MissedPropertyException,
269                         InvalidPropertyException, NotApplicableException {
270                 String refid = dprop.getReference();
271                 Publication res = null;
272                 if (refid != null) {
273                         Document slot = getDocumentService().selectDocument(refid,
274                                         new Revision().toString());
275                         if ((slot != null) && (slot.isUndefined())) {
276                                 getDocumentService().initialize(slot,
277                                                 dprop.setOwner(aStep.getOwnerStudy()));
278                                 res = new Publication(slot, aStep.getOwner());
279                         }
280                 }
281                 return res;
282         }
283
284         /**
285          * Create a new version of a document in the given study step.
286          * 
287          * @param aStep
288          *            the study step
289          * @param base
290          *            the base document published version
291          * @return the new version publication
292          * @throws MissedPropertyException
293          *             if a mandatory property is missed
294          * @throws InvalidPropertyException
295          *             if some property doesn't exist
296          * @throws MultiplyDefinedException
297          *             if some property is defined several times
298          * @throws IOException
299          *             if a file system error occurs
300          * @throws MismatchException
301          *             if the document is not applicable to the given study step
302          */
303         public Publication versionDocument(final Step aStep, final Publication base)
304                         throws MissedPropertyException, InvalidPropertyException,
305                         MultiplyDefinedException, IOException, MismatchException {
306                 return versionDocument(aStep, base, new Document.Properties());
307         }
308
309         /**
310          * Create a new version of a document in the given study step.
311          * 
312          * @param aStep
313          *            the study step
314          * @param base
315          *            the base document published version
316          * @param reason
317          *            the comment for the new version
318          * @return the new version publication
319          * @throws MissedPropertyException
320          *             if a mandatory property is missed
321          * @throws InvalidPropertyException
322          *             if some property doesn't exist
323          * @throws MultiplyDefinedException
324          *             if some property is defined several times
325          * @throws IOException
326          *             if a file system error occurs
327          * @throws MismatchException
328          *             if the document is not applicable to the given study step
329          */
330         public Publication versionDocument(final Step aStep,
331                         final Publication base, final String reason)
332                         throws MissedPropertyException, InvalidPropertyException,
333                         MultiplyDefinedException, IOException, MismatchException {
334                 return versionDocument(aStep, base, new Document.Properties()
335                                 .setDescription(reason));
336         }
337
338         /**
339          * Create a new version of a document in the given study step.
340          * 
341          * @param aStep
342          *            the study step
343          * @param base
344          *            the base document published version
345          * @param dprop
346          *            properties of the new version
347          * @return the new version publication
348          * @throws MissedPropertyException
349          *             if a mandatory property is missed
350          * @throws InvalidPropertyException
351          *             if some property doesn't exist
352          * @throws MultiplyDefinedException
353          *             if some property is defined several times
354          * @throws IOException
355          *             if a file system error occurs
356          * @throws MismatchException
357          *             if the document is not applicable to the given study step
358          */
359         @Transactional
360         public Publication versionDocument(final Step aStep,
361                         final Publication base, final Document.Properties dprop)
362                         throws MissedPropertyException, InvalidPropertyException,
363                         MultiplyDefinedException, IOException, MismatchException {
364                 Document previous = base.value();
365
366                 // RKV: Keep the new file format if it is related to the same document type on this step.
367                 String newFormat = dprop.getFormat();
368
369                 dprop.setDocument(previous, getProjectSettings().getStep(
370                                 base.getStep().getNumber())); // Initializes the Step property
371                 if (dprop.getStep().getNumber() != aStep.getNumber()) {
372                         throw new MismatchException();
373                 }
374
375                 if (newFormat != null
376                                 && previous.getType().equals(
377                                                 getProjectSettings().getDefaultDocumentType(
378                                                                 aStep.getStep(), newFormat))) {
379                         dprop.setFormat(newFormat);
380                 }
381
382                 if (dprop.getAuthor() == null) {
383                         dprop.setAuthor(previous.getAuthor());
384                 }
385                 String summary = dprop.getDescription();
386
387                 // Creation of the document
388                 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
389                                 .setStep(aStep.getStep()));
390                 getDocumentService().generateDocumentId(newdoc, dprop);
391                 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwner(),
392                                 previous);
393                 getDocumentDAO().create(newdoc);
394
395                 // Versioning
396                 VersionsRelation aRel;
397                 aRel = new VersionsRelation(newdoc, previous, summary);
398                 // getVersionsRelationDAO().create(aRel);
399                 newdoc.addRelation(aRel);
400
401                 // Update of usedby relations, if exist
402                 /*
403                  * RKV: Consider the new version as not used by old dependent documents. So these documents must be marked as outdated then. List<Relation>
404                  * relist = previous.getRelations(UsedByRelation.class); Study scope = aStep.getOwnerStudy(); for (Iterator<Relation> i =
405                  * relist.iterator(); i.hasNext();) { UsedByRelation relation = (UsedByRelation) i.next(); Document relatedoc = relation.getTo(); if
406                  * (scope.shares(relatedoc)) { relatedoc.addRelation(new UsesRelation(relatedoc, newdoc)); } else { relation.moveTo(newdoc); } }
407                  */
408                 return new Publication(newdoc, aStep.getOwner());
409         }
410
411         /**
412          * Get document types which are applicable for the given study step (activity).
413          * 
414          * @param aStep
415          *            the study step
416          * @return the list of document types
417          */
418         public List<DocumentType> getValidDocumentTypes(final Step aStep) {
419                 return getDocumentTypeService().selectTypesOf(aStep.getStep());
420         }
421
422         /**
423          * Add a document publication to the given step.
424          * 
425          * @param aStep
426          *            the target study step
427          * @param newdoc
428          *            the document publication to add
429          * @return true if publication succeeded
430          */
431         public boolean add(final Step aStep, final Publication newdoc) {
432                 boolean res = aStep.getOwner().add(newdoc); // Updates the study in memory
433                 if (res) {
434                         aStep.getDocuments().add(0, newdoc); // Updates this step
435                         getDocumentService().hold(newdoc.value()); // Increments the configuration tag count of document
436                         // If not yet saved, the Publication MUST NOT be saved here, although this creates a temporary inconsistent state into the
437                         // database (it will be saved later by cascading the update of owner scenario).
438                 }
439                 return res;
440         }
441
442         /**
443          * Remove a document publication from the given step.
444          * 
445          * @param aStep
446          *            the study step
447          * @param oldoc
448          *            the document publication to remove
449          * @return true if removing of the publication succeeded
450          */
451         public boolean remove(final Step aStep, final Publication oldoc) {
452                 aStep.getDocuments().remove(oldoc); // Updates this step
453                 // Synchronize with database
454                 ProjectElement owner = getProjectElementDAO().merge(aStep.getOwner());
455                 if (owner != null) {
456                         aStep.getOwner().remove(oldoc); // in transient copy
457                         owner.remove(oldoc); // in persistent copy
458                 }
459                 getDocumentService().release(oldoc.value()); // Decrements the configuration tag count of document
460                 // The publication becoming orphan, it should automatically be removed from the database when updating of owner scenario.
461                 return true;
462         }
463
464         /**
465          * Remove a document from the given step and from the database if it is no more used.
466          * 
467          * @param aStep
468          *            the study step
469          * @param docId
470          *            the document id
471          * @return true if removing of the document succeeded
472          */
473         @Transactional
474         public boolean removeDocument(final Step aStep, final long docId) {
475                 Publication torem = aStep.getDocument(docId);
476                 boolean res = (torem != null);
477                 if (res) {
478                         torem = getPublicationDAO().merge(torem);
479                         remove(aStep, torem);
480                         Document value = torem.value();
481                         if (!value.isPublished() && !value.isVersioned()) { // The referenced document is no more used
482                                 List<Document> using = new ArrayList<Document>();
483                                 List<Relation> converts = new ArrayList<Relation>();
484                                 for (Relation link : value.getAllRelations()) {
485                                         if (link.getClass().equals(ConvertsRelation.class)) { // File conversion
486                                                 converts.add(link);
487                                         } else if (link.getClass().equals(UsesRelation.class)) { // Document dependency
488                                                 using.add((Document) link.getTo());
489                                         }
490                                 }
491 //                              value.getAllRelations().removeAll(converts);
492                                 // Remove relations from depending documents
493                                 if (LOG.isDebugEnabled()) {
494                                         LOG.debug("Remove " + using.size() + " UsedByRelation(s).");
495                                 }
496                                 for (Document doc : using) {
497                                         if (LOG.isDebugEnabled()) {
498                                                 LOG.debug("Remove UsedByRelation from "
499                                                                 + doc.getTitle() + " to " + value.getTitle());
500                                         }
501                                         doc.removeRelation(UsedByRelation.class, value);
502                                 }
503                                 // Synchronize deleted objects with the database to avoid hibernate exception
504                                 // related with null value of not-nullable property because back reference from Document to Publication is not mapped:
505                                 // org.hibernate.PropertyValueException: not-null property references a null or transient value:
506                                 // org.splat.dal.bo.som.Publication.mydoc
507                                 getDocumentDAO().flush(); // To show to the database that files from ConvertsRelation(s) are deleted already
508                                 getDocumentDAO().delete(value); // The corresponding physical file is not removed from the vault
509                                 // Delete document's files
510                                 for (Relation link : converts) {
511                                         File file = (File) link.getTo();
512                                         getFileDAO().delete(file); // The corresponding physical file is not removed from the vault
513                                 }
514                         }
515                 }
516                 return res;
517         }
518
519         /**
520          * Get the documentService.
521          * 
522          * @return the documentService
523          */
524         public DocumentService getDocumentService() {
525                 return _documentService;
526         }
527
528         /**
529          * Set the documentService.
530          * 
531          * @param documentService
532          *            the documentService to set
533          */
534         public void setDocumentService(final DocumentService documentService) {
535                 _documentService = documentService;
536         }
537
538         /**
539          * Get the simulationContextService.
540          * 
541          * @return the simulationContextService
542          */
543         public SimulationContextService getSimulationContextService() {
544                 return _simulationContextService;
545         }
546
547         /**
548          * Set the simulationContextService.
549          * 
550          * @param simulationContextService
551          *            the simulationContextService to set
552          */
553         public void setSimulationContextService(
554                         final SimulationContextService simulationContextService) {
555                 _simulationContextService = simulationContextService;
556         }
557
558         /**
559          * Get the documentDAO.
560          * 
561          * @return the documentDAO
562          */
563         public DocumentDAO getDocumentDAO() {
564                 return _documentDAO;
565         }
566
567         /**
568          * Set the documentDAO.
569          * 
570          * @param documentDAO
571          *            the documentDAO to set
572          */
573         public void setDocumentDAO(final DocumentDAO documentDAO) {
574                 _documentDAO = documentDAO;
575         }
576
577         /**
578          * Get the simulationContextDAO.
579          * 
580          * @return the simulationContextDAO
581          */
582         public SimulationContextDAO getSimulationContextDAO() {
583                 return _simulationContextDAO;
584         }
585
586         /**
587          * Set the simulationContextDAO.
588          * 
589          * @param simulationContextDAO
590          *            the simulationContextDAO to set
591          */
592         public void setSimulationContextDAO(
593                         final SimulationContextDAO simulationContextDAO) {
594                 _simulationContextDAO = simulationContextDAO;
595         }
596
597         /**
598          * Get the projectElementDAO.
599          * 
600          * @return the projectElementDAO
601          */
602         public ProjectElementDAO getProjectElementDAO() {
603                 return _projectElementDAO;
604         }
605
606         /**
607          * Set the projectElementDAO.
608          * 
609          * @param projectElementDAO
610          *            the projectElementDAO to set
611          */
612         public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
613                 _projectElementDAO = projectElementDAO;
614         }
615
616         /**
617          * Get the indexService.
618          * 
619          * @return the indexService
620          */
621         public IndexService getIndexService() {
622                 return _indexService;
623         }
624
625         /**
626          * Set the indexService.
627          * 
628          * @param indexService
629          *            the indexService to set
630          */
631         public void setIndexService(final IndexService indexService) {
632                 _indexService = indexService;
633         }
634
635         /**
636          * Get the fileDAO.
637          * 
638          * @return the fileDAO
639          */
640         public FileDAO getFileDAO() {
641                 return _fileDAO;
642         }
643
644         /**
645          * Set the fileDAO.
646          * 
647          * @param fileDAO
648          *            the fileDAO to set
649          */
650         public void setFileDAO(final FileDAO fileDAO) {
651                 _fileDAO = fileDAO;
652         }
653
654         /**
655          * Get the documentTypeService.
656          * 
657          * @return the documentTypeService
658          */
659         public DocumentTypeService getDocumentTypeService() {
660                 return _documentTypeService;
661         }
662
663         /**
664          * Set the documentTypeService.
665          * 
666          * @param documentTypeService
667          *            the documentTypeService to set
668          */
669         public void setDocumentTypeService(
670                         final DocumentTypeService documentTypeService) {
671                 _documentTypeService = documentTypeService;
672         }
673
674         /**
675          * Get the versionsRelationDAO.
676          * 
677          * @return the versionsRelationDAO
678          */
679         public VersionsRelationDAO getVersionsRelationDAO() {
680                 return _versionsRelationDAO;
681         }
682
683         /**
684          * Set the versionsRelationDAO.
685          * 
686          * @param versionsRelationDAO
687          *            the versionsRelationDAO to set
688          */
689         public void setVersionsRelationDAO(
690                         final VersionsRelationDAO versionsRelationDAO) {
691                 _versionsRelationDAO = versionsRelationDAO;
692         }
693
694         /**
695          * Get project settings.
696          * 
697          * @return Project settings service
698          */
699         private ProjectSettingsService getProjectSettings() {
700                 return _projectSettings;
701         }
702
703         /**
704          * Set project settings service.
705          * 
706          * @param projectSettingsService
707          *            project settings service
708          */
709         public void setProjectSettings(
710                         final ProjectSettingsService projectSettingsService) {
711                 _projectSettings = projectSettingsService;
712         }
713
714         /**
715          * Get the publicationDAO.
716          * 
717          * @return the publicationDAO
718          */
719         public PublicationDAO getPublicationDAO() {
720                 return _publicationDAO;
721         }
722
723         /**
724          * Set the publicationDAO.
725          * 
726          * @param publicationDAO
727          *            the publicationDAO to set
728          */
729         public void setPublicationDAO(final PublicationDAO publicationDAO) {
730                 this._publicationDAO = publicationDAO;
731         }
732
733         /**
734          * Get the relationDAO.
735          * 
736          * @return the relationDAO
737          */
738         public RelationDAO getRelationDAO() {
739                 return _relationDAO;
740         }
741
742         /**
743          * Set the relationDAO.
744          * 
745          * @param relationDAO
746          *            the relationDAO to set
747          */
748         public void setRelationDAO(final RelationDAO relationDAO) {
749                 _relationDAO = relationDAO;
750         }
751 }