Salome HOME
It was impossible to edit the body of the knowledge when the ordered or unordered...
[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.List;
15
16 import org.hibernate.criterion.Restrictions;
17 import org.splat.dal.bo.kernel.Relation;
18 import org.splat.dal.bo.kernel.User;
19 import org.splat.dal.bo.som.ConvertsRelation;
20 import org.splat.dal.bo.som.Document;
21 import org.splat.dal.bo.som.DocumentType;
22 import org.splat.dal.bo.som.File;
23 import org.splat.dal.bo.som.KnowledgeElement;
24 import org.splat.dal.bo.som.ProjectElement;
25 import org.splat.dal.bo.som.Publication;
26 import org.splat.dal.bo.som.Scenario;
27 import org.splat.dal.bo.som.SimulationContext;
28 import org.splat.dal.bo.som.StepCommentAttribute;
29 import org.splat.dal.bo.som.UsedByRelation;
30 import org.splat.dal.bo.som.UsesRelation;
31 import org.splat.dal.bo.som.VersionsRelation;
32 import org.splat.dal.dao.kernel.RelationDAO;
33 import org.splat.dal.dao.kernel.UserDAO;
34 import org.splat.dal.dao.som.DocumentDAO;
35 import org.splat.dal.dao.som.FileDAO;
36 import org.splat.dal.dao.som.ProjectElementDAO;
37 import org.splat.dal.dao.som.PublicationDAO;
38 import org.splat.dal.dao.som.SimulationContextDAO;
39 import org.splat.dal.dao.som.StepCommentAttributeDAO;
40 import org.splat.dal.dao.som.VersionsRelationDAO;
41 import org.splat.exception.DocumentIsUsedException;
42 import org.splat.exception.InvalidParameterException;
43 import org.splat.kernel.InvalidPropertyException;
44 import org.splat.kernel.MismatchException;
45 import org.splat.kernel.MissedPropertyException;
46 import org.splat.kernel.MultiplyDefinedException;
47 import org.splat.kernel.NotApplicableException;
48 import org.splat.log.AppLogger;
49 import org.splat.service.dto.StepCommentDTO;
50 import org.splat.service.technical.IndexService;
51 import org.splat.service.technical.ProjectSettingsService;
52 import org.splat.som.Revision;
53 import org.splat.som.Step;
54 import org.splat.util.BeanHelper;
55 import org.springframework.transaction.annotation.Transactional;
56
57 /**
58  * Step service implementation.
59  * 
60  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
61  */
62 public class StepServiceImpl implements StepService {
63
64         /**
65          * logger for the service.
66          */
67         public final static AppLogger LOG = AppLogger
68                         .getLogger(StepServiceImpl.class);
69         /**
70          * Injected index service.
71          */
72         private IndexService _indexService;
73         /**
74          * Injected document service.
75          */
76         private DocumentService _documentService;
77         /**
78          * Injected document type service.
79          */
80         private DocumentTypeService _documentTypeService;
81         /**
82          * Injected document DAO.
83          */
84         private DocumentDAO _documentDAO;
85         /**
86          * Injected relation DAO.
87          */
88         private RelationDAO _relationDAO;
89         /**
90          * Injected file DAO.
91          */
92         private FileDAO _fileDAO;
93         /**
94          * Injected simulation context service.
95          */
96         private SimulationContextService _simulationContextService;
97         /**
98          * Injected simulation context DAO.
99          */
100         private SimulationContextDAO _simulationContextDAO;
101         /**
102          * Injected project element DAO.
103          */
104         private ProjectElementDAO _projectElementDAO;
105         /**
106          * Injected versions relation DAO.
107          */
108         private VersionsRelationDAO _versionsRelationDAO;
109         /**
110          * Injected project service.
111          */
112         private ProjectSettingsService _projectSettings;
113         /**
114          * Injected publication DAO.
115          */
116         private PublicationDAO _publicationDAO;
117
118         /**
119          * Injected text attribute DAO.
120          */
121         private StepCommentAttributeDAO _stepCommentAttributeDAO;
122
123         /**
124          * Injected user DAO.
125          */
126         private UserDAO _userDAO;
127
128         /**
129          * {@inheritDoc}
130          * 
131          * @see org.splat.service.StepService#addSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext.Properties)
132          */
133         @Override
134         public SimulationContext addSimulationContext(final Step aStep,
135                         final SimulationContext.Properties dprop)
136                         throws MissedPropertyException, InvalidPropertyException,
137                         MultiplyDefinedException {
138                 SimulationContext context = new SimulationContext(dprop.setStep(aStep
139                                 .getStep()));
140                 return addSimulationContext(aStep, context);
141         }
142
143         /**
144          * {@inheritDoc}
145          * 
146          * @see org.splat.service.StepService#addSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext)
147          */
148         @Override
149         @Transactional
150         public SimulationContext addSimulationContext(final Step aStep,
151                         final SimulationContext context) {
152                 SimulationContext res = null;
153                 getSimulationContextService().hold(context); // Increments the reference count of simulation context
154                 if (aStep.getOwner().isSaved()) {
155                         try {
156                                 if (!context.isSaved()) {
157                                         getSimulationContextDAO().create(context);
158                                 }
159                                 aStep.getOwner().add(context);
160                                 aStep.getContex().add(context); // The context is also referenced from this (transient) Step
161                                 getProjectElementDAO().update(aStep.getOwner());
162                                 updateKnowledgeElementsIndex(aStep);
163                                 res = context;
164                         } catch (Exception error) {
165                                 LOG.debug(error.getMessage(), error);
166                         }
167                 } else { // Happens when copying a scenario
168                         aStep.getOwner().add(context);
169                         aStep.getContex().add(context); // The context is also referenced from this (transient) Step
170                         // In case of owner scenario, the Knowledge Element index will be updated later, when saving the scenario
171                         res = context;
172                 }
173                 return res;
174         }
175
176         /**
177          * Update lucene index of knowledge elements of a scenario or a study which the given step is related to.
178          * 
179          * @param aStep
180          *            the step (activity)
181          */
182         private void updateKnowledgeElementsIndex(final Step aStep) {
183                 Scenario[] scenarii;
184                 if (aStep.getOwner() instanceof Scenario) {
185                         scenarii = new Scenario[1];
186                         scenarii[0] = (Scenario) aStep.getOwner();
187                 } else {
188                         scenarii = aStep.getOwnerStudy().getScenarii();
189                 }
190                 for (int i = 0; i < scenarii.length; i++) {
191                         Scenario scene = scenarii[i];
192                         updateScenarioIndex(scene);
193                 }
194         }
195
196         /**
197          * Update lucene index for knowledge elements of the scenario.
198          * 
199          * @param scene
200          *            the scenario
201          */
202         private void updateScenarioIndex(final Scenario scene) {
203                 if (scene.getUcase() == null) {
204                         for (KnowledgeElement kelm : scene.getKnowledgeElements()) {
205                                 if (kelm.getType().equals("usecase")) {
206                                         scene.setUcase(kelm);
207                                         break;
208                                 }
209                         }
210                 }
211         }
212
213         /**
214          * {@inheritDoc}
215          * 
216          * @see org.splat.service.StepService#removeSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext)
217          */
218         @Override
219         @Transactional
220         public boolean removeSimulationContext(final Step aStep,
221                         final SimulationContext context) {
222                 SimulationContext torem = aStep
223                                 .getSimulationContext(context.getIndex());
224
225                 boolean isOk = (torem != null) && (aStep.getOwner().remove(torem));
226                 if (isOk) {
227
228                         aStep.getContex().remove(torem);
229                         getProjectElementDAO().update(aStep.getOwner());
230                         if (torem.isShared()) {
231                                 getSimulationContextService().release(torem);
232                                 getSimulationContextDAO().update(torem);
233                         } else {
234                                 getSimulationContextDAO().delete(torem);
235                         }
236                 }
237                 return isOk;
238         }
239
240         /**
241          * {@inheritDoc}
242          * 
243          * @see org.splat.service.StepService#createDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
244          */
245         @Override
246         @Transactional
247         public Publication createDocument(final Step aStep,
248                         final Document.Properties dprop) throws MissedPropertyException,
249                         InvalidPropertyException, MultiplyDefinedException, IOException {
250                 if (LOG.isDebugEnabled()) {
251                         LOG.debug("Local index before: "
252                                         + aStep.getOwnerStudy().getLastLocalIndex());
253                 }
254                 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
255                                 .setStep(aStep.getStep()));
256                 getDocumentService().generateDocumentId(newdoc, dprop);
257
258                 // Creation of the save directory
259                 java.io.File wdir = getDocumentService().getSaveDirectory(newdoc);
260                 if ((!wdir.exists()) && (!wdir.mkdirs())) {
261                         throw new IOException(
262                                         "Cannot create the repository vault directory");
263                 }
264
265                 // Identification and save
266                 if (LOG.isDebugEnabled()) {
267                         LOG.debug("Local index after: "
268                                         + aStep.getOwnerStudy().getLastLocalIndex());
269                 }
270                 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwnerStudy());
271                 getDocumentDAO().create(newdoc);
272
273                 return new Publication(newdoc, aStep.getOwner());
274         }
275
276         /**
277          * {@inheritDoc}
278          * 
279          * @see org.splat.service.StepService#assignDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
280          */
281         @Override
282         public Publication assignDocument(final Step aStep,
283                         final Document.Properties dprop) throws MissedPropertyException,
284                         InvalidPropertyException, NotApplicableException {
285                 String refid = dprop.getReference();
286                 Publication res = null;
287                 if (refid != null) {
288                         Document slot = getDocumentService().selectDocument(refid,
289                                         new Revision().toString());
290                         if ((slot != null) && (slot.isUndefined())) {
291                                 getDocumentService().initialize(slot,
292                                                 dprop.setOwner(aStep.getOwnerStudy()));
293                                 res = new Publication(slot, aStep.getOwner());
294                         }
295                 }
296                 return res;
297         }
298
299         /**
300          * Create a new version of a document in the given study step.
301          * 
302          * @param aStep
303          *            the study step
304          * @param base
305          *            the base document published version
306          * @return the new version publication
307          * @throws MissedPropertyException
308          *             if a mandatory property is missed
309          * @throws InvalidPropertyException
310          *             if some property doesn't exist
311          * @throws MultiplyDefinedException
312          *             if some property is defined several times
313          * @throws IOException
314          *             if a file system error occurs
315          * @throws MismatchException
316          *             if the document is not applicable to the given study step
317          */
318         public Publication versionDocument(final Step aStep, final Publication base)
319                         throws MissedPropertyException, InvalidPropertyException,
320                         MultiplyDefinedException, IOException, MismatchException {
321                 return versionDocument(aStep, base, new Document.Properties());
322         }
323
324         /**
325          * Create a new version of a document in the given study step.
326          * 
327          * @param aStep
328          *            the study step
329          * @param base
330          *            the base document published version
331          * @param reason
332          *            the comment for the new version
333          * @return the new version publication
334          * @throws MissedPropertyException
335          *             if a mandatory property is missed
336          * @throws InvalidPropertyException
337          *             if some property doesn't exist
338          * @throws MultiplyDefinedException
339          *             if some property is defined several times
340          * @throws IOException
341          *             if a file system error occurs
342          * @throws MismatchException
343          *             if the document is not applicable to the given study step
344          */
345         public Publication versionDocument(final Step aStep,
346                         final Publication base, final String reason)
347                         throws MissedPropertyException, InvalidPropertyException,
348                         MultiplyDefinedException, IOException, MismatchException {
349                 return versionDocument(aStep, base, new Document.Properties()
350                                 .setDescription(reason));
351         }
352
353         /**
354          * Create a new version of a document in the given study step.
355          * 
356          * @param aStep
357          *            the study step
358          * @param base
359          *            the base document published version
360          * @param dprop
361          *            properties of the new version
362          * @return the new version publication
363          * @throws MissedPropertyException
364          *             if a mandatory property is missed
365          * @throws InvalidPropertyException
366          *             if some property doesn't exist
367          * @throws MultiplyDefinedException
368          *             if some property is defined several times
369          * @throws IOException
370          *             if a file system error occurs
371          * @throws MismatchException
372          *             if the document is not applicable to the given study step
373          */
374         @Transactional
375         public Publication versionDocument(final Step aStep,
376                         final Publication base, final Document.Properties dprop)
377                         throws MissedPropertyException, InvalidPropertyException,
378                         MultiplyDefinedException, IOException, MismatchException {
379                 Document previous = base.value();
380
381                 // RKV: Keep the new file format if it is related to the same document type on this step.
382                 String newFormat = dprop.getFormat();
383
384                 dprop.setDocument(previous, getProjectSettings().getStep(
385                                 base.getStep().getNumber())); // Initializes the Step property
386                 if (dprop.getStep().getNumber() != aStep.getNumber()) {
387                         throw new MismatchException();
388                 }
389
390                 if (newFormat != null
391                 /*
392                  * && previous.getType().equals( getProjectSettings().getDefaultDocumentType( aStep.getStep(), newFormat))
393                  */) {
394                         dprop.setFormat(newFormat);
395                 }
396
397                 if (dprop.getAuthor() == null) {
398                         dprop.setAuthor(previous.getAuthor());
399                 }
400                 String summary = dprop.getDescription();
401
402                 // Creation of the document
403                 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
404                                 .setStep(aStep.getStep()));
405                 getDocumentService().generateDocumentId(newdoc, dprop);
406                 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwner(),
407                                 previous);
408                 getDocumentDAO().create(newdoc);
409
410                 // Versioning
411                 VersionsRelation aRel;
412                 aRel = new VersionsRelation(newdoc, previous, summary);
413                 // getVersionsRelationDAO().create(aRel);
414                 newdoc.addRelation(aRel);
415
416                 // Update of usedby relations, if exist
417                 /*
418                  * RKV: Consider the new version as not used by old dependent documents. So these documents must be marked as outdated then. List<Relation>
419                  * relist = previous.getRelations(UsedByRelation.class); Study scope = aStep.getOwnerStudy(); for (Iterator<Relation> i =
420                  * relist.iterator(); i.hasNext();) { UsedByRelation relation = (UsedByRelation) i.next(); Document relatedoc = relation.getTo(); if
421                  * (scope.shares(relatedoc)) { relatedoc.addRelation(new UsesRelation(relatedoc, newdoc)); } else { relation.moveTo(newdoc); } }
422                  */
423                 return new Publication(newdoc, aStep.getOwner());
424         }
425
426         /**
427          * Get document types which are applicable for the given study step (activity).
428          * 
429          * @param aStep
430          *            the study step
431          * @return the list of document types
432          */
433         @Override
434         public List<DocumentType> getValidDocumentTypes(final Step aStep) {
435                 return getDocumentTypeService().selectTypesOf(aStep.getStep());
436         }
437
438         /**
439          * Add a document publication to the given step.
440          * 
441          * @param aStep
442          *            the target study step
443          * @param newdoc
444          *            the document publication to add
445          * @return true if publication succeeded
446          */
447         @Override
448         public boolean add(final Step aStep, final Publication newdoc) {
449                 boolean res = aStep.getOwner().add(newdoc); // Updates the study in memory
450                 if (res) {
451                         aStep.getDocuments().add(0, newdoc); // Updates this step
452                         getDocumentService().hold(newdoc.value()); // Increments the configuration tag count of document
453                         // If not yet saved, the Publication MUST NOT be saved here, although this creates a temporary inconsistent state into the
454                         // database (it will be saved later by cascading the update of owner scenario).
455                 }
456                 return res;
457         }
458
459         /**
460          * Remove a document publication from the given step.
461          * 
462          * @param aStep
463          *            the study step
464          * @param oldoc
465          *            the document publication to remove
466          * @return true if removing of the publication succeeded
467          */
468         @Override
469         public boolean remove(final Step aStep, final Publication oldoc) {
470                 aStep.getDocuments().remove(oldoc); // Updates this step
471                 aStep.getOwner().remove(oldoc); // remove from the parent project element
472                 getProjectElementDAO().merge(aStep.getOwner().getOwnerStudy());
473                 getDocumentService().release(oldoc.value()); // Decrements the configuration tag count of document
474                 // The publication becoming orphan, it should automatically be removed from the database when updating of owner scenario.
475                 return true;
476         }
477
478         /**
479          * Remove a document from the given step and from the database if it is no more used.
480          * 
481          * @param aStep
482          *            the study step
483          * @param docId
484          *            the document id
485          * @return true if removing of the document succeeded
486          * @throws DocumentIsUsedException
487          *             if the document is used by other documents
488          */
489         @Override
490         @Transactional
491         public boolean removeDocument(final Step aStep, final long docId)
492                         throws DocumentIsUsedException {
493                 Publication torem = aStep.getDocument(docId);
494                 boolean res = (torem != null);
495                 if (res) {
496                         if (!torem.value().getRelations(UsedByRelation.class).isEmpty()) {
497                                 throw new DocumentIsUsedException(torem.value().getTitle());
498                         }
499                         // Remove the document publication from the step
500                         remove(aStep, torem);
501                         // Republish the previous version if any to avoid it becoming an orphan
502                         Document prevVersion = torem.value().getPreviousVersion();
503                         if (prevVersion != null) {
504                                 prevVersion.setHistory(prevVersion.getHistory() - 1);
505                                 add(aStep, new Publication(prevVersion, aStep.getOwner()));
506                                 getProjectElementDAO().merge(aStep.getOwner());
507                         }
508                         // Delete the document if it is no more used
509                         Document value = torem.value();
510                         if (!value.isPublished() && !value.isVersioned()) { // The referenced document is no more used
511                                 List<Document> using = new ArrayList<Document>();
512                                 List<File> files = new ArrayList<File>();
513                                 files.add(value.getFile()); // To delete the source file physically at the end
514                                 for (Relation link : value.getAllRelations()) {
515                                         if (link.getClass().equals(ConvertsRelation.class)) { // File conversion
516                                                 files.add((File) link.getTo());
517                                         } else if (link.getClass().equals(UsesRelation.class)) { // Document dependency
518                                                 using.add((Document) link.getTo());
519                                         }
520                                 }
521                                 // Remove relations from depending documents
522                                 if (LOG.isDebugEnabled()) {
523                                         LOG.debug("Remove " + using.size() + " UsedByRelation(s).");
524                                 }
525                                 for (Document doc : using) {
526                                         if (LOG.isDebugEnabled()) {
527                                                 LOG.debug("Remove UsedByRelation from "
528                                                                 + doc.getTitle() + " to " + value.getTitle());
529                                                 LOG.debug("Nb relations of doc " + doc.getTitle()
530                                                                 + " before: " + doc.getAllRelations().size());
531                                         }
532                                         doc.removeRelation(UsedByRelation.class, value);
533                                         if (LOG.isDebugEnabled()) {
534                                                 LOG.debug("Nb relations of doc " + doc.getTitle()
535                                                                 + " after: " + doc.getAllRelations().size());
536                                         }
537                                         getDocumentDAO().merge(doc);
538                                 }
539                                 // Synchronize deleted objects with the database to avoid hibernate exception
540                                 // org.hibernate.PropertyValueException: not-null property references a null or transient value
541                                 getDocumentDAO().flush();
542                                 // The corresponding physical file is not removed from the vault
543                                 getDocumentDAO().delete(getDocumentDAO().merge(torem.value()));
544                                 // Delete document's files
545                                 // Delete files from file system
546                                 for (File file : files) {
547                                         // getFileDAO().delete(getFileDAO().merge(file)); // The corresponding physical file is not removed from the vault
548                                         LOG.info("Delete the file "
549                                                         + file.asFile().getAbsolutePath());
550                                         if (file.asFile().delete()) {
551                                                 LOG.info("File " + file.asFile().getAbsolutePath()
552                                                                 + " successfully deleted.");
553                                         } else {
554                                                 LOG.info("File " + file.asFile().getAbsolutePath()
555                                                                 + " can not be deleted.");
556                                         }
557                                 }
558                         }
559                 }
560                 return res;
561         }
562
563         /**
564          * {@inheritDoc}
565          * 
566          * @see org.splat.service.StepService#addComment(org.splat.som.Step, org.splat.dal.bo.som.CommentAttribute)
567          */
568         @Override
569         @Transactional
570         public void addStepComment(final StepCommentDTO comment)
571                         throws InvalidParameterException {
572
573                 if (comment.getId() != null) {
574                         throw new InvalidParameterException("id", String.valueOf(comment
575                                         .getId()));
576                 }
577                 User user = getUserDAO().get(comment.getUserId());
578                 if (user == null) {
579                         throw new InvalidParameterException("userId", String
580                                         .valueOf(comment.getUserId()));
581                 }
582                 ProjectElement projectElement = getProjectElementDAO().get(
583                                 comment.getProjectElementId());
584                 if (projectElement == null) {
585                         throw new InvalidParameterException("projectElementId", comment
586                                         .getProjectElementId().toString());
587                 }
588                 if (comment.getStep() == null || comment.getStep() < 0) {
589                         throw new InvalidParameterException("step", String.valueOf(comment
590                                         .getStep()));
591                 }
592                 if (comment.getDate() == null) {
593                         throw new InvalidParameterException("date", String.valueOf(comment
594                                         .getDate()));
595                 }
596                 if (comment.getTitle() == null) {
597                         throw new InvalidParameterException("title", String.valueOf(comment
598                                         .getTitle()));
599                 }
600
601                 StepCommentAttribute newComment = new StepCommentAttribute(
602                                 projectElement, comment.getText(), comment.getDate(), comment
603                                                 .getStep(), user, comment.getTitle());
604
605                 Long resultKey = getStepCommentAttributeDAO().create(newComment);
606                 comment.setId(resultKey);
607         }
608
609         /**
610          * {@inheritDoc}
611          * 
612          * @see org.splat.service.StepService#getStepComments(org.splat.som.Step)
613          */
614         @Override
615         @Transactional(readOnly = true)
616         public List<StepCommentDTO> getStepComments(final Step step)
617                         throws InvalidParameterException {
618                 ProjectElement owner = _projectElementDAO.get(step.getOwner().getRid());
619                 if (owner == null) {
620                         throw new InvalidParameterException("step owner id", Long.valueOf(
621                                         step.getOwner().getRid()).toString());
622                 }
623                 List<StepCommentAttribute> comments = _stepCommentAttributeDAO
624                                 .getFilteredList(Restrictions.and(Restrictions.eq("step",
625                                                 Integer.valueOf(step.getNumber())), Restrictions.eq(
626                                                 "owner", owner)));
627                 List<StepCommentDTO> commentDTOs = new ArrayList<StepCommentDTO>();
628                 for (StepCommentAttribute comment : comments) {
629                         StepCommentDTO stepCommentDTO = BeanHelper.copyBean(comment,
630                                         StepCommentDTO.class);
631                         stepCommentDTO.setText(comment.getValue());
632                         stepCommentDTO.setId(Long.valueOf(comment.getRid()));
633                         commentDTOs.add(stepCommentDTO);
634                 }
635                 return commentDTOs;
636         }
637
638         /**
639          * {@inheritDoc}
640          * 
641          * @see org.splat.service.StepService#removeStepComment(long)
642          */
643         @Override
644         @Transactional
645         public void removeStepComment(final long commentId)
646                         throws InvalidParameterException {
647                 StepCommentAttribute stepComment = _stepCommentAttributeDAO.get(Long
648                                 .valueOf(commentId));
649                 if (stepComment == null) {
650                         throw new InvalidParameterException("commentId", String
651                                         .valueOf(commentId));
652                 }
653                 _stepCommentAttributeDAO.delete(stepComment);
654         }
655
656         /**
657          * {@inheritDoc}
658          * 
659          * @see org.splat.service.StepService#editStepComment(long, java.lang.String, java.lang.String)
660          */
661         @Override
662         @Transactional
663         public void editStepComment(final long commentId, final String newValue,
664                         final String newTitle) throws InvalidParameterException {
665                 StepCommentAttribute comment = _stepCommentAttributeDAO.get(Long
666                                 .valueOf(commentId));
667                 if (comment == null) {
668                         throw new InvalidParameterException("commentId", String
669                                         .valueOf(commentId));
670                 }
671                 if (newTitle != null) {
672                         comment.setTitle(newTitle);
673                 }
674                 if (newValue != null) {
675                         comment.setValue(newValue);
676                 }
677                 _stepCommentAttributeDAO.update(comment);
678         }
679
680         /**
681          * {@inheritDoc}
682          * 
683          * @see org.splat.service.StepService#isCommentMadeByUser(long, long)
684          */
685         @Override
686         @Transactional(readOnly = true)
687         public boolean isCommentMadeByUser(final long commentId, final long userId)
688                         throws InvalidParameterException {
689                 StepCommentAttribute comment = _stepCommentAttributeDAO.get(Long
690                                 .valueOf(commentId));
691                 if (comment == null) {
692                         throw new InvalidParameterException("commentId", String
693                                         .valueOf(commentId));
694                 }
695                 return comment.getUser().getIndex() == userId;
696         }
697
698         /**
699          * Get the documentService.
700          * 
701          * @return the documentService
702          */
703         public DocumentService getDocumentService() {
704                 return _documentService;
705         }
706
707         /**
708          * Set the documentService.
709          * 
710          * @param documentService
711          *            the documentService to set
712          */
713         public void setDocumentService(final DocumentService documentService) {
714                 _documentService = documentService;
715         }
716
717         /**
718          * Get the simulationContextService.
719          * 
720          * @return the simulationContextService
721          */
722         public SimulationContextService getSimulationContextService() {
723                 return _simulationContextService;
724         }
725
726         /**
727          * Set the simulationContextService.
728          * 
729          * @param simulationContextService
730          *            the simulationContextService to set
731          */
732         public void setSimulationContextService(
733                         final SimulationContextService simulationContextService) {
734                 _simulationContextService = simulationContextService;
735         }
736
737         /**
738          * Get the documentDAO.
739          * 
740          * @return the documentDAO
741          */
742         public DocumentDAO getDocumentDAO() {
743                 return _documentDAO;
744         }
745
746         /**
747          * Set the documentDAO.
748          * 
749          * @param documentDAO
750          *            the documentDAO to set
751          */
752         public void setDocumentDAO(final DocumentDAO documentDAO) {
753                 _documentDAO = documentDAO;
754         }
755
756         /**
757          * Get the simulationContextDAO.
758          * 
759          * @return the simulationContextDAO
760          */
761         public SimulationContextDAO getSimulationContextDAO() {
762                 return _simulationContextDAO;
763         }
764
765         /**
766          * Set the simulationContextDAO.
767          * 
768          * @param simulationContextDAO
769          *            the simulationContextDAO to set
770          */
771         public void setSimulationContextDAO(
772                         final SimulationContextDAO simulationContextDAO) {
773                 _simulationContextDAO = simulationContextDAO;
774         }
775
776         /**
777          * Get the projectElementDAO.
778          * 
779          * @return the projectElementDAO
780          */
781         public ProjectElementDAO getProjectElementDAO() {
782                 return _projectElementDAO;
783         }
784
785         /**
786          * Set the projectElementDAO.
787          * 
788          * @param projectElementDAO
789          *            the projectElementDAO to set
790          */
791         public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
792                 _projectElementDAO = projectElementDAO;
793         }
794
795         /**
796          * Get the indexService.
797          * 
798          * @return the indexService
799          */
800         public IndexService getIndexService() {
801                 return _indexService;
802         }
803
804         /**
805          * Set the indexService.
806          * 
807          * @param indexService
808          *            the indexService to set
809          */
810         public void setIndexService(final IndexService indexService) {
811                 _indexService = indexService;
812         }
813
814         /**
815          * Get the fileDAO.
816          * 
817          * @return the fileDAO
818          */
819         public FileDAO getFileDAO() {
820                 return _fileDAO;
821         }
822
823         /**
824          * Set the fileDAO.
825          * 
826          * @param fileDAO
827          *            the fileDAO to set
828          */
829         public void setFileDAO(final FileDAO fileDAO) {
830                 _fileDAO = fileDAO;
831         }
832
833         /**
834          * Get the documentTypeService.
835          * 
836          * @return the documentTypeService
837          */
838         public DocumentTypeService getDocumentTypeService() {
839                 return _documentTypeService;
840         }
841
842         /**
843          * Set the documentTypeService.
844          * 
845          * @param documentTypeService
846          *            the documentTypeService to set
847          */
848         public void setDocumentTypeService(
849                         final DocumentTypeService documentTypeService) {
850                 _documentTypeService = documentTypeService;
851         }
852
853         /**
854          * Get the versionsRelationDAO.
855          * 
856          * @return the versionsRelationDAO
857          */
858         public VersionsRelationDAO getVersionsRelationDAO() {
859                 return _versionsRelationDAO;
860         }
861
862         /**
863          * Set the versionsRelationDAO.
864          * 
865          * @param versionsRelationDAO
866          *            the versionsRelationDAO to set
867          */
868         public void setVersionsRelationDAO(
869                         final VersionsRelationDAO versionsRelationDAO) {
870                 _versionsRelationDAO = versionsRelationDAO;
871         }
872
873         /**
874          * Get project settings.
875          * 
876          * @return Project settings service
877          */
878         private ProjectSettingsService getProjectSettings() {
879                 return _projectSettings;
880         }
881
882         /**
883          * Set project settings service.
884          * 
885          * @param projectSettingsService
886          *            project settings service
887          */
888         public void setProjectSettings(
889                         final ProjectSettingsService projectSettingsService) {
890                 _projectSettings = projectSettingsService;
891         }
892
893         /**
894          * Get the stepCommentAttributeDAO.
895          * 
896          * @return the stepCommentAttributeDAO
897          */
898         public StepCommentAttributeDAO getStepCommentAttributeDAO() {
899                 return _stepCommentAttributeDAO;
900         }
901
902         /**
903          * Set the stepCommentAttributeDAO.
904          * 
905          * @param commentAttributeDAO
906          *            the stepCommentAttributeDAO to set
907          */
908         public void setStepCommentAttributeDAO(
909                         final StepCommentAttributeDAO commentAttributeDAO) {
910                 _stepCommentAttributeDAO = commentAttributeDAO;
911         }
912
913         /**
914          * Get the userDAO.
915          * 
916          * @return the userDAO
917          */
918         public UserDAO getUserDAO() {
919                 return _userDAO;
920         }
921
922         /**
923          * Set the userDAO.
924          * 
925          * @param userDAO
926          *            the userDAO to set
927          */
928         public void setUserDAO(final UserDAO userDAO) {
929                 _userDAO = userDAO;
930         }
931
932         /**
933          * Get the publicationDAO.
934          * 
935          * @return the publicationDAO
936          */
937         public PublicationDAO getPublicationDAO() {
938                 return _publicationDAO;
939         }
940
941         /**
942          * Set the publicationDAO.
943          * 
944          * @param publicationDAO
945          *            the publicationDAO to set
946          */
947         public void setPublicationDAO(final PublicationDAO publicationDAO) {
948                 this._publicationDAO = publicationDAO;
949         }
950
951         /**
952          * Get the relationDAO.
953          * 
954          * @return the relationDAO
955          */
956         public RelationDAO getRelationDAO() {
957                 return _relationDAO;
958         }
959
960         /**
961          * Set the relationDAO.
962          * 
963          * @param relationDAO
964          *            the relationDAO to set
965          */
966         public void setRelationDAO(final RelationDAO relationDAO) {
967                 _relationDAO = relationDAO;
968         }
969 }