]> SALOME platform Git repositories - tools/siman.git/blob - Workspace/Siman-Common/src/org/splat/service/SearchServiceImpl.java
Salome HOME
beaf1afde47f128c7c9ab20a3bb4668da3772833
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / SearchServiceImpl.java
1 /*****************************************************************************
2  * Company         OPEN CASCADE
3  * Application     SIMAN
4  * File            $Id$ 
5  * Creation date   05.10.2012
6  * @author         $Author$
7  * @version        $Revision$
8  *****************************************************************************/
9
10 package org.splat.service;
11
12 import java.io.File;
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.Iterator;
16 import java.util.List;
17
18 import org.apache.log4j.Logger;
19 import org.apache.lucene.index.Term;
20 import org.apache.lucene.search.BooleanClause;
21 import org.apache.lucene.search.BooleanFilter;
22 import org.apache.lucene.search.BooleanQuery;
23 import org.apache.lucene.search.FilterClause;
24 import org.apache.lucene.search.IndexSearcher;
25 import org.apache.lucene.search.ScoreDoc;
26 import org.apache.lucene.search.Sort;
27 import org.apache.lucene.search.SortField;
28 import org.apache.lucene.search.TermQuery;
29 import org.apache.lucene.search.TermsFilter;
30 import org.apache.lucene.search.TopFieldDocs;
31 import org.apache.lucene.store.Directory;
32 import org.apache.lucene.store.FSDirectory;
33 import org.hibernate.Criteria;
34 import org.hibernate.Hibernate;
35 import org.hibernate.criterion.DetachedCriteria;
36 import org.hibernate.criterion.Disjunction;
37 import org.hibernate.criterion.Junction;
38 import org.hibernate.criterion.Order;
39 import org.hibernate.criterion.Restrictions;
40 import org.hibernate.type.Type;
41 import org.splat.dal.bo.kernel.User;
42 import org.splat.dal.bo.som.KnowledgeElement;
43 import org.splat.dal.bo.som.KnowledgeElementType;
44 import org.splat.dal.bo.som.ProgressState;
45 import org.splat.dal.bo.som.Scenario;
46 import org.splat.dal.bo.som.SimulationContext;
47 import org.splat.dal.bo.som.Study;
48 import org.splat.dal.bo.som.Visibility;
49 import org.splat.dal.bo.som.Study.Properties;
50 import org.splat.dal.dao.som.StudyDAO;
51 import org.splat.service.dto.ImportedStudyDTO;
52 import org.splat.service.dto.Proxy;
53 import org.splat.service.dto.StudyDTO;
54 import org.splat.service.technical.IndexService;
55 import org.splat.service.technical.IndexServiceImpl;
56 import org.splat.service.technical.RepositoryService;
57 import org.splat.util.BeanHelper;
58 import org.springframework.transaction.annotation.Transactional;
59
60 /**
61  * Search service implementation.
62  * 
63  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
64  */
65 public class SearchServiceImpl implements SearchService {
66
67         /**
68          * The service logger.
69          */
70         public final static Logger LOG = Logger
71                         .getLogger(org.splat.service.SearchServiceImpl.class);
72
73         /**
74          * Injected repository service.
75          */
76         private RepositoryService _repositoryService;
77         /**
78          * Injected index service.
79          */
80         private IndexService _indexService;
81         /**
82          * Injected study service.
83          */
84         private StudyService _studyService;
85         /**
86          * Injected study DAO.
87          */
88         private StudyDAO _studyDAO;
89
90         /**
91          * Get a list of studies which are currently not presented in the lucene index.
92          * 
93          * @return list of ImportedStudy DTO
94          */
95         @Transactional(readOnly = true)
96         public List<ImportedStudyDTO> selectStudies() {
97                 List<ImportedStudyDTO> table = new ArrayList<ImportedStudyDTO>();
98                 Study.Properties sprop = new Study.Properties();
99                 List<Study> dbStudies = getStudyDAO().getAll();
100
101                 for (Study aStudy : dbStudies) {
102                         try {
103                                 sprop.clear();
104                                 if (selectStudiesWhere(
105                                                 sprop.setReference(aStudy.getReference())).size() != 0) {
106                                         // If this study was already indexed and found in the lucene index
107                                         // then skip it to avoid adding to the index it again.
108                                         continue;
109                                 }
110                         } catch (Exception error) {
111                                 continue;
112                         }
113                         // Add the study to the list of studies which are
114                         // currently not presented in the lucene index.
115                         table.add(BeanHelper.copyBean(aStudy, ImportedStudyDTO.class));
116                 }
117                 return table;
118         }
119
120         /**
121          * Refresh lucene index for studies.
122          * 
123          * @param ridlist
124          *            list of studies id's
125          */
126         @Transactional(readOnly = true)
127         @Deprecated
128         public void reindexStudies(final String[] ridlist) {
129                 for (int i = 0; i < ridlist.length; i++) {
130                         long index = Long.valueOf(ridlist[i].trim());
131                         Study study = getStudyService().selectStudy(index);
132                         indexStudy(study);
133                 }
134         }
135
136         /**
137          * {@inheritDoc}
138          * 
139          * @see org.splat.service.SearchService#selectKnowledgeElementsWhere(org.splat.dal.bo.som.KnowledgeElement.Properties[])
140          */
141         public List<Proxy> selectKnowledgeElementsWhere(
142                         final KnowledgeElement.Properties... kprop) {
143                 List<Proxy> result = new ArrayList<Proxy>();
144                 int hitsize = 20;
145                 try {
146
147                         // Creation of the Lucene query
148                         File indir = getRepositoryService().getRepositoryIndexDirectory();
149                         Directory index = FSDirectory.open(indir);
150                         IndexSearcher searcher = new IndexSearcher(index, true);
151                         BooleanQuery fulquery = new BooleanQuery();
152
153                         for (int i = 0; i < kprop.length; i++) {
154                                 BooleanQuery query = new BooleanQuery();
155                                 Term input; // Supposed initialized below at least by the visibility
156
157                                 Visibility area = kprop[i].getVisibility(); // Visibility
158                                 if (area != null) {
159                                         input = new Term("area");
160                                         query.add(new TermQuery(input.createTerm(area.toString())),
161                                                         BooleanClause.Occur.MUST);
162                                 }
163                                 ProgressState state = kprop[i].getProgressState(); // State
164                                 if (state != null) {
165                                         input = new Term("state");
166                                         query.add(
167                                                         new TermQuery(input.createTerm(state.toString())),
168                                                         BooleanClause.Occur.MUST);
169                                 }
170                                 String refid = kprop[i].getReference(); // Reference
171                                 if (refid != null) {
172                                         input = new Term("ref");
173                                         query.add(new TermQuery(input.createTerm(refid)),
174                                                         BooleanClause.Occur.MUST);
175                                 }
176                                 KnowledgeElementType type = kprop[i].getType(); // Type
177                                 if (type != null) {
178                                         input = new Term("type");
179                                         query.add(new TermQuery(input.createTerm(type.getName())),
180                                                         BooleanClause.Occur.MUST);
181                                 }
182                                 User manager = kprop[i].getAuthor(); // Author
183                                 if (manager != null) {
184                                         input = new Term("author");
185                                         query.add(new TermQuery(input
186                                                         .createTerm(manager.toString())),
187                                                         BooleanClause.Occur.MUST);
188                                 }
189                                 User actor = kprop[i].getActor(); // Contributor, Reviewer or Approver of the owner study
190                                 if (actor != null) {
191                                         input = new Term("actor");
192                                         query.add(
193                                                         new TermQuery(input.createTerm(actor.toString())),
194                                                         BooleanClause.Occur.MUST);
195                                 }
196                                 String title = kprop[i].getTitle(); // Title
197                                 if (title != null) {
198                                         input = new Term("contents");
199                                         BooleanQuery critext = new BooleanQuery();
200                                         String operator = "AND"; // Future user input
201                                         BooleanClause.Occur clause = BooleanClause.Occur.MUST;
202                                         if (operator.equals("OR")) {
203                                                 clause = BooleanClause.Occur.SHOULD;
204                                         }
205                                         String[] word = title.split(" ");
206                                         for (int j = 0; j < word.length; j++) {
207                                                 critext.add(new TermQuery(input.createTerm(word[j])),
208                                                                 clause);
209                                         }
210                                         query.add(critext, BooleanClause.Occur.MUST);
211                                 }
212                                 List<SimulationContext> context = kprop[i]
213                                                 .getSimulationContexts();
214                                 if (context != null && context.size() > 0) {
215                                         BooleanQuery critext = new BooleanQuery();
216                                         for (Iterator<SimulationContext> j = context.iterator(); j
217                                                         .hasNext();) {
218                                                 SimulationContext seltext = j.next();
219                                                 input = new Term(String.valueOf(seltext.getType()
220                                                                 .getIndex()));
221                                                 critext.add(new TermQuery(input.createTerm(seltext
222                                                                 .getValue())), BooleanClause.Occur.MUST);
223                                         }
224                                         query.add(critext, BooleanClause.Occur.MUST);
225                                 }
226                                 fulquery.add(query, BooleanClause.Occur.SHOULD);
227                         }
228                         if (LOG.isInfoEnabled()) {
229                                 LOG.info("Searching knowledges by Lucene query \""
230                                                 + fulquery.toString() + "\".");
231                         }
232                         // Creation of the knowledge filter
233                         BooleanFilter filter = new BooleanFilter();
234                         TermsFilter select = new TermsFilter();
235                         Term mytype = new Term("class");
236                         select.addTerm(mytype.createTerm("KnowledgeElement"));
237                         filter.add(new FilterClause(select, BooleanClause.Occur.SHOULD));
238
239                         // Creation of the sort criteria
240                         Sort sort = new Sort(new SortField("title", SortField.STRING));
241
242                         // Search
243                         TopFieldDocs found = searcher.search(fulquery, filter, hitsize,
244                                         sort);
245
246                         if (found.totalHits < 1) {
247                                 return result; // No study found
248                         }
249
250                         // Construction of the result list
251                         ScoreDoc[] hits = found.scoreDocs;
252                         for (int i = 0; i < hits.length; i++) {
253                                 result.add(new IndexServiceImpl.ObjectProxy(searcher
254                                                 .doc(hits[i].doc)));
255                         }
256                         searcher.close();
257                 } catch (Exception error) {
258                         LOG.error("Error during Lucene search, reason:", error);
259                 }
260                 return result;
261         }
262
263         /**
264          * {@inheritDoc}
265          * 
266          * @see org.splat.service.SearchService#selectStudiesWhere(org.splat.dal.bo.som.Study.Properties[])
267          */
268         public List<Proxy> selectStudiesWhere(final boolean allCriteria,
269                         final boolean allContexts, final Study.Properties sprop) {
270                 List<Proxy> result = new ArrayList<Proxy>();
271
272                 DetachedCriteria query = DetachedCriteria
273                                 .forClass(Study.class, "study");
274                 // Creation of the query
275                 initQuery(query, sprop);
276
277                 String title = sprop.getTitle(); // Title
278                 if (title != null) {
279                         // Look for given words in study titles
280                         Junction critext;
281                         if (allCriteria) { // AND
282                                 critext = Restrictions.conjunction();
283                         } else { // OR
284                                 critext = Restrictions.disjunction();
285                         }
286
287                         String[] word = title.split(" ");
288                         for (int j = 0; j < word.length; j++) {
289                                 critext.add(Restrictions.like("title", "%" + word[j] + "%"));
290                         }
291                         query.add(critext);
292                 }
293
294                 List<SimulationContext> context = sprop.getSimulationContexts();
295                 if (context != null && (!context.isEmpty())) {
296                         // Get only studies which have given contexts
297                         query.createAlias("contex", "ctx", Criteria.INNER_JOIN);
298                         Junction critctx;
299                         if (allContexts) { // AND
300                                 critctx = Restrictions.conjunction();
301                         } else { // OR
302                                 critctx = Restrictions.disjunction();
303                         }
304                         for (SimulationContext seltext : context) {
305                                 // (simctxType = seltext.getType() AND simctxValue = seltext.getValue())
306                                 critctx.add(Restrictions.and(Restrictions.eq("ctx.value",
307                                                 seltext.getValue()), Restrictions.eq("ctx.type",
308                                                 seltext.getType())));
309
310                         }
311                         query.add(critctx);
312                 }
313
314                 // Group by study
315                 query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
316                 // Creation of the sort criteria
317                 query.addOrder(Order.asc("title"));
318
319                 if (LOG.isInfoEnabled()) {
320                         LOG.info("Searching studies: \"" + query.toString() + "\".");
321                 }
322
323                 // Search
324                 List<Study> found = getStudyDAO().getFilteredList(query);
325
326                 // Construction of the result list
327                 for (Study std : found) {
328                         result.add(new StudyDTO(std.getIndex(), std.getReference(), std
329                                         .getProgressState(), std.getTitle(), std.getAuthor()
330                                         .getDisplayName()));
331                 }
332                 return result;
333         }
334
335         /**
336          * Initialize query with base criteria.
337          * 
338          * @param query
339          *            the query
340          * @param sprop
341          *            the criteria
342          */
343         private void initQuery(final DetachedCriteria query, final Properties sprop) {
344                 ProgressState state = sprop.getProgressState(); // State
345                 if (state != null) {
346                         query.add(Restrictions.eq("state", state));
347                 }
348                 String refid = sprop.getReference(); // Reference
349                 if (refid != null) {
350                         query.add(Restrictions.eq("sid", refid));
351                 }
352                 User manager = sprop.getManager(); // Author
353                 if (manager != null) {
354                         query.add(Restrictions.eq("manager", manager));
355                 }
356
357                 User actor = sprop.getActor(); // Contributor, Reviewer or Approver
358                 if (actor == null) {
359                         // User is not logged in - show only public studies
360                         query.add(Restrictions.eq("visibility", Visibility.PUBLIC));
361                 } else {
362                         // User is loggen in - show public studies and studies where he is participating
363                         Disjunction orCrit = Restrictions.disjunction();
364                         query
365                                         .add(orCrit
366                                                         .add(
367                                                                         /* If the user is a validation cycle participant */
368                                                                         Restrictions
369                                                                                         .sqlRestriction(
370                                                                                                         "{alias}.rid in (select vcrel.owner from cycle_rel vcrel inner join cycle vc on vcrel.refer = vc.rid where {alias}.rid = vcrel.owner AND (vc.publisher = ? OR vc.reviewer = ? OR vc.approver = ? OR vc.signatory = ?) group by vcrel.owner)",
371                                                                                                         new Object[] {
372                                                                                                                         actor.getIndex(),
373                                                                                                                         actor.getIndex(),
374                                                                                                                         actor.getIndex(),
375                                                                                                                         actor.getIndex() },
376                                                                                                         new Type[] {
377                                                                                                                         Hibernate.LONG,
378                                                                                                                         Hibernate.LONG,
379                                                                                                                         Hibernate.LONG,
380                                                                                                                         Hibernate.LONG }))
381                                                         .add(
382                                                                         /* If the user is contributor */
383                                                                         Restrictions
384                                                                                         .sqlRestriction(
385                                                                                                         "{alias}.rid in (select rel.owner from contributor_rel rel where {alias}.rid = rel.owner AND rel.refer = ?)",
386                                                                                                         actor.getIndex(),
387                                                                                                         Hibernate.LONG)).add(
388                                                         /* If the user is author */
389                                                         Restrictions.eq("study.manager", actor)).add(
390                                                                         /* If the study is public */
391                                                                         Restrictions.eq("study.visibility",
392                                                                                         Visibility.PUBLIC)));
393                 }
394         }
395
396         /**
397          * {@inheritDoc}
398          * 
399          * @see org.splat.service.SearchService#selectStudiesWhere(org.splat.dal.bo.som.Study.Properties[])
400          */
401         @Deprecated
402         public List<Proxy> selectStudiesWhere(final Study.Properties... sprop) {
403                 List<Proxy> result = new ArrayList<Proxy>();
404                 int hitsize = 20;
405                 try {
406
407                         // Creation of the Lucene query
408                         File indir = getRepositoryService().getRepositoryIndexDirectory();
409                         Directory index = FSDirectory.open(indir);
410                         IndexSearcher searcher = new IndexSearcher(index, true);
411                         BooleanQuery fulquery = new BooleanQuery();
412
413                         for (int i = 0; i < sprop.length; i++) {
414                                 BooleanQuery query = new BooleanQuery();
415                                 Term input; // Supposed initialized below at least by the visibility
416
417                                 Visibility area = sprop[i].getVisibility(); // Visibility
418                                 if (area != null) {
419                                         input = new Term("area");
420                                         query.add(new TermQuery(input.createTerm(area.toString())),
421                                                         BooleanClause.Occur.MUST);
422                                 }
423                                 ProgressState state = sprop[i].getProgressState(); // State
424                                 if (state != null) {
425                                         input = new Term("state");
426                                         if (state == ProgressState.inPROGRESS) {
427                                                 BooleanQuery cristate = new BooleanQuery();
428                                                 cristate.add(new TermQuery(input.createTerm("inWORK")),
429                                                                 BooleanClause.Occur.SHOULD);
430                                                 cristate.add(
431                                                                 new TermQuery(input.createTerm("inDRAFT")),
432                                                                 BooleanClause.Occur.SHOULD);
433                                                 cristate.add(
434                                                                 new TermQuery(input.createTerm("inCHECK")),
435                                                                 BooleanClause.Occur.SHOULD);
436                                                 query.add(cristate, BooleanClause.Occur.MUST);
437                                         } else {
438                                                 query.add(new TermQuery(input.createTerm(state
439                                                                 .toString())), BooleanClause.Occur.MUST);
440                                         }
441                                 }
442                                 String refid = sprop[i].getReference(); // Reference
443                                 if (refid != null) {
444                                         input = new Term("ref");
445                                         query.add(new TermQuery(input.createTerm(refid)),
446                                                         BooleanClause.Occur.MUST);
447                                 }
448                                 User manager = sprop[i].getManager(); // Author
449                                 if (manager != null) {
450                                         input = new Term("author");
451                                         query.add(new TermQuery(input
452                                                         .createTerm(manager.toString())),
453                                                         BooleanClause.Occur.MUST);
454                                 }
455                                 User actor = sprop[i].getActor(); // Contributor, Reviewer or Approver
456                                 if (actor != null) {
457                                         input = new Term("actor");
458                                         query.add(
459                                                         new TermQuery(input.createTerm(actor.toString())),
460                                                         BooleanClause.Occur.MUST);
461                                 }
462                                 String title = sprop[i].getTitle(); // Title
463                                 if (title != null) {
464                                         input = new Term("contents");
465                                         BooleanQuery critext = new BooleanQuery();
466                                         String operator = "AND"; // Future user input
467                                         BooleanClause.Occur clause = BooleanClause.Occur.MUST;
468                                         if (operator.equals("OR")) {
469                                                 clause = BooleanClause.Occur.SHOULD;
470                                         }
471                                         String[] word = title.split(" ");
472                                         for (int j = 0; j < word.length; j++) {
473                                                 critext.add(new TermQuery(input.createTerm(word[j])),
474                                                                 clause);
475                                         }
476                                         query.add(critext, BooleanClause.Occur.MUST);
477                                 }
478                                 List<SimulationContext> context = sprop[i]
479                                                 .getSimulationContexts();
480                                 if (context != null && context.size() > 0) {
481                                         BooleanQuery critext = new BooleanQuery();
482                                         for (Iterator<SimulationContext> j = context.iterator(); j
483                                                         .hasNext();) {
484                                                 SimulationContext seltext = j.next();
485                                                 input = new Term(String.valueOf(seltext.getType()
486                                                                 .getIndex()));
487                                                 critext.add(new TermQuery(input.createTerm(seltext
488                                                                 .getValue())), BooleanClause.Occur.MUST);
489                                         }
490                                         query.add(critext, BooleanClause.Occur.MUST);
491                                 }
492                                 fulquery.add(query, BooleanClause.Occur.SHOULD);
493                         }
494                         if (LOG.isInfoEnabled()) {
495                                 LOG.info("Searching studies by Lucene query \""
496                                                 + fulquery.toString() + "\".");
497                         }
498                         // Creation of the studies filter
499                         BooleanFilter filter = new BooleanFilter();
500                         TermsFilter select = new TermsFilter();
501                         Term mytype = new Term("class");
502                         select.addTerm(mytype.createTerm("Study"));
503                         filter.add(new FilterClause(select, BooleanClause.Occur.SHOULD));
504
505                         // Creation of the sort criteria
506                         Sort sort = new Sort(new SortField("title", SortField.STRING));
507
508                         // Search
509                         TopFieldDocs found = searcher.search(fulquery, filter, hitsize,
510                                         sort);
511
512                         if (found.totalHits < 1) {
513                                 return result; // No study found
514                         }
515
516                         // Construction of the result list
517                         ScoreDoc[] hits = found.scoreDocs;
518                         for (int i = 0; i < hits.length; i++) {
519                                 result.add(new IndexServiceImpl.ObjectProxy(searcher
520                                                 .doc(hits[i].doc)));
521                         }
522                         searcher.close();
523                 } catch (Exception error) {
524                         LOG.error("Error during Lucene search, reason:", error);
525                 }
526                 return result;
527         }
528
529         /**
530          * {@inheritDoc}
531          * 
532          * @see org.splat.service.SearchService#indexStudy(org.splat.dal.bo.som.Study)
533          */
534         @Deprecated
535         public void indexStudy(final Study study) {
536                 LOG.debug("Index study: id=" + study.getRid() + "; reference="
537                                 + study.getReference());
538                 try {
539                         Study.Properties sprop = new Study.Properties();
540                         List<Proxy> index = selectStudiesWhere(sprop.setReference(study
541                                         .getReference()));
542
543                         if (index.size() != 0) {
544                                 LOG.debug("The given study is already indexed.");
545                                 return; // The given study is already indexed
546                         }
547
548                         IndexService lucin = getIndex();
549                         Scenario[] scenes = study.getScenarii();
550
551                         LOG.debug("Number of study " + study.getReference() + " actors: "
552                                         + study.getActor().size());
553                         lucin.add(study);
554                         if (study.getProgressState() != ProgressState.inWORK) {
555                                 for (int i = 0; i < scenes.length; i++) {
556                                         List<KnowledgeElement> list = scenes[i]
557                                                         .getAllKnowledgeElements();
558                                         for (Iterator<KnowledgeElement> j = list.iterator(); j
559                                                         .hasNext();) {
560                                                 lucin.add(j.next());
561                                                 LOG.debug("Knowlegge added: id=" + j.next().getIndex());
562                                         }
563                                 }
564                         }
565                 } catch (Exception error) {
566                         LOG.error("Unable to index the study '" + study.getIndex()
567                                         + "', reason:", error);
568                 }
569         }
570
571         /**
572          * Get lucene index handler. Create the index if it is not exist.
573          * 
574          * @return IndexService
575          * @throws IOException
576          *             if error when creating a new lucene index
577          */
578         private IndexService getIndex() throws IOException {
579                 IndexService lucin = getIndexService();
580                 if (!lucin.exists()) {
581                         lucin.create(); // Happens when re-indexing all studies
582                 }
583                 return lucin;
584         }
585
586         /**
587          * Get the repositoryService.
588          * 
589          * @return the repositoryService
590          */
591         public RepositoryService getRepositoryService() {
592                 return _repositoryService;
593         }
594
595         /**
596          * Set the repositoryService.
597          * 
598          * @param repositoryService
599          *            the repositoryService to set
600          */
601         public void setRepositoryService(final RepositoryService repositoryService) {
602                 _repositoryService = repositoryService;
603         }
604
605         /**
606          * Get the indexService.
607          * 
608          * @return the indexService
609          */
610         public IndexService getIndexService() {
611                 return _indexService;
612         }
613
614         /**
615          * Set the indexService.
616          * 
617          * @param indexService
618          *            the indexService to set
619          */
620         public void setIndexService(final IndexService indexService) {
621                 _indexService = indexService;
622         }
623
624         /**
625          * Get the studyService.
626          * 
627          * @return the studyService
628          */
629         public StudyService getStudyService() {
630                 return _studyService;
631         }
632
633         /**
634          * Set the studyService.
635          * 
636          * @param studyService
637          *            the studyService to set
638          */
639         public void setStudyService(final StudyService studyService) {
640                 _studyService = studyService;
641         }
642
643         /**
644          * Get the studyDAO.
645          * 
646          * @return the studyDAO
647          */
648         public StudyDAO getStudyDAO() {
649                 return _studyDAO;
650         }
651
652         /**
653          * Set the studyDAO.
654          * 
655          * @param studyDAO
656          *            the studyDAO to set
657          */
658         public void setStudyDAO(final StudyDAO studyDAO) {
659                 _studyDAO = studyDAO;
660         }
661 }