Salome HOME
Sort study and knowledge results functionalities are implemented
[tools/siman.git] / Workspace / Siman / src / org / splat / simer / AbstractSearchBaseAction.java
1 package org.splat.simer;
2
3 import java.text.SimpleDateFormat;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.Iterator;
9 import java.util.LinkedHashMap;
10 import java.util.List;
11 import java.util.Map;
12
13 import org.splat.dal.bo.kernel.User;
14 import org.splat.dal.bo.som.SimulationContext;
15 import org.splat.dal.bo.som.SimulationContextType;
16 import org.splat.kernel.InvalidPropertyException;
17 import org.splat.kernel.Name;
18 import org.splat.service.SimulationContextService;
19 import org.splat.service.UserService;
20 import org.splat.service.dto.Proxy;
21 import org.splat.service.dto.SearchFilterDTO;
22 import org.splat.service.dto.StudyDTO;
23 import org.splat.service.technical.ProjectSettingsService;
24 import org.splat.som.ApplicationRights;
25 import org.splat.wapp.Constants;
26
27 /**
28  * Base search action class used for searching studies and knowledge.
29  * 
30  * @param <FilterClass>
31  *            search filter class
32  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
33  */
34 public abstract class AbstractSearchBaseAction<FilterClass extends SearchFilterDTO>
35                 extends Action {
36
37         /**
38          * Serial version ID.
39          */
40         private static final long serialVersionUID = 7863055790228544510L;
41         /**
42          * Search result key in the session.
43          */
44         public static final String RESULT_KEY = "search.result";
45         /**
46          * Context type index, when selected.
47          */
48         protected transient String _ctype = null;
49         /**
50          * Context value index, when selected.
51          */
52         protected transient String _cvalue = null;
53         /**
54          * Context index, when removed.
55          */
56         protected transient String _cindex = "";
57         /**
58          * Search criteria.
59          */
60         private FilterClass _filter;
61         /**
62          * List of users who can create studies.
63          */
64         protected List<Name> _candidates = null;
65         /**
66          * Context type to be valued.
67          */
68         protected transient SimulationContextType _newtype;
69         /**
70          * Context value to be selected.
71          */
72         protected transient List<SimulationContext> _newvalue;
73         /**
74          * Addable context types.
75          */
76         protected transient List<SimulationContextType> _critext;
77         /**
78          * List of found objects.
79          */
80         protected transient List<Proxy> _result;
81         /**
82          * Injected simulation context service.
83          */
84         private SimulationContextService _simulationContextService;
85
86         /**
87          * Injected user service.
88          */
89         private UserService _userService;
90
91         /**
92          * Search action modes enumeration.
93          */
94         enum UserAction {
95                 refreshResult, selectContextType, selectContextValue, cancelSelect, removeContext
96         }
97
98         /**
99          * A criteria to sort studies by.
100          */
101         private SortCriterion _newSortedBy;
102
103         /**
104          * Sort order key in the session.
105          */
106         protected static final String ORDER_KEY = "isDescendingOrder";
107         
108         /**
109          * Sort criterion key in the session.
110          */
111         protected static final String CRITERION_KEY = "sortCriterion";
112
113         // ==============================================================================================================================
114         // Action methods
115         // ==============================================================================================================================
116
117         /**
118          * StudyDTO sort criteria.
119          */
120         enum SortCriterion {
121                 /**
122                  * Reference.
123                  */
124                 REFERENCE,
125                 /**
126                  * Name.
127                  */
128                 NAME,
129                 /**
130                  * Creation date.
131                  */
132                 CREATEDATE,
133                 /**
134                  * Modification date.
135                  */
136                 MODIFDATE,
137                 /**
138                  * The person responsible.
139                  */
140                 RESPONSIBLE
141         }
142         
143         /**
144          * StudyDTO comparator class.
145          */
146         private class StudyComparator implements Comparator<StudyDTO> {
147                 
148                 /**
149                  * The criteria by which studies are compared.
150                  */
151                 SortCriterion _criterion = SortCriterion.NAME;
152                 
153                 /**
154                  * Constructor from comparison criteria.
155                  * @param criterion
156                  *                      the criteria
157                  */
158                 public StudyComparator(final SortCriterion criterion) {
159                         _criterion = criterion;
160                 }
161                 
162                 /** 
163                  * {@inheritDoc}
164                  * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
165                  */
166                 public int compare(final StudyDTO first, final StudyDTO second) {
167                         switch (_criterion) {
168                                 case REFERENCE:
169                                         return first.getReference().compareTo(second.getReference());
170                                 case CREATEDATE:
171                                         return first.getDate().compareTo(second.getDate());
172                                 case MODIFDATE:
173                                         return first.getLastModificationDate().compareTo(
174                                                         second.getLastModificationDate());
175                                 case RESPONSIBLE:
176                                         return getText(first.getAuthorName())
177                                                         .compareTo(getText(second.getAuthorName()));
178                                 default:
179                                         return first.getTitle().compareTo(second.getTitle());
180                         }
181                 }
182         }
183         
184         /**
185          * Set search results sort order.
186          * @return 
187          *              SUCCESS if successfully found and sorted search results;
188          *              ERROR otherwise
189          */
190         public String doSetOrder() {
191                 String res = ERROR;
192                 _result = (List<Proxy>) getSession().get(RESULT_KEY);
193                 Boolean order = (Boolean) getSession().get(ORDER_KEY);
194                 SortCriterion oldSortedBy = (SortCriterion) getSession().get(CRITERION_KEY);
195                 
196                 if (_result != null) {
197                         
198                         if (_newSortedBy != null && !_newSortedBy.equals(oldSortedBy)) {        // Sort by new criterion
199                                 // Direct cast into collection of another type just won't work in Java
200                                 Collections.sort((List<StudyDTO>)(List<?>) _result, new StudyComparator(_newSortedBy));
201                                 getSession().put(CRITERION_KEY, _newSortedBy);
202                                 getSession().put(ORDER_KEY, false);
203                         } else {
204                                 if (order == null) {    
205                                         order = false;
206                                 } else {        // need to change the order
207                                         order = !order;
208                                 }
209                                 getSession().put(ORDER_KEY, order);
210                                 Collections.reverse(_result);
211                         }
212                         res = SUCCESS;
213                 }
214                         
215                 return res;
216         }
217         
218         /**
219          * Perform actions according to the current mode.
220          * 
221          * @return action result or ERROR if failed
222          */
223         public String doSubmitForm() {
224                 // Identification of the user action
225                 UserAction action = UserAction.refreshResult;
226                 if (_ctype != null && Integer.valueOf(_ctype) > 0) {
227                         action = UserAction.selectContextType;
228                 } else if (_cvalue != null && Integer.valueOf(_cvalue) > 0) {
229                         action = UserAction.selectContextValue;
230                 } else if (_cindex.length() > 0) {
231                         long index = Long.valueOf(_cindex);
232                         if (index > 0) {
233                                 action = UserAction.removeContext;
234                         } else if (index < 0) {
235                                 action = UserAction.cancelSelect;
236                         }
237                 }
238                 // Execution of the user action
239                 String done;
240                 try {
241                         saveFilter(); // Also reinitializes the form, if needed
242
243                         if (action == UserAction.selectContextType) {
244                                 done = doSelectContextType();
245                         } else if (action == UserAction.selectContextValue) {
246                                 done = doAddContext();
247                         } else if (action == UserAction.removeContext) {
248                                 done = doRemoveContext();
249                         } else if (action == UserAction.cancelSelect) {
250                                 done = doCancel();
251                         } else { // UserAction.refreshResult
252                                 done = doSearch();
253                                 setContextTypeOptions(getInvolvedContexts()); // Done in other do functions, when required
254                         }
255                         setCandidates();
256                 } catch (Exception error) {
257                         // No need to roll back the transaction as it is read only
258                         LOG.error("Reason: ", error);
259                         done = ERROR;
260                 }
261                 return done;
262         }
263
264         /**
265          * Add a selected context type to the search filter. Obsolete the current result if necessary.
266          * 
267          * @return "selectype"
268          */
269         @SuppressWarnings(Constants.UNCHECKED)
270         protected String doSelectContextType() {
271                 SimulationContext.Properties sprop = new SimulationContext.Properties();
272
273                 _newtype = getSimulationContextService().selectType(
274                                 Integer.valueOf(_ctype));
275                 _newvalue = getSimulationContextService()
276                                 .selectSimulationContextsWhere(sprop.setType(_newtype));
277                 if (_cindex.length() > 0 && Long.valueOf(_cindex) == 0) {
278                         getSession().remove(RESULT_KEY);
279                 } else {
280                         // We keep the previous result search, if valid
281                         _result = (List<Proxy>) getSession().get(RESULT_KEY);
282                 }
283                 setActionType("setContext");
284                 return "selectype";
285         }
286
287         /**
288          * Add a selected context to the search filter. Obsolete the current result.
289          * 
290          * @return "refresh"
291          */
292         protected String doAddContext() {
293                 SimulationContext selected = getSimulationContextService()
294                                 .selectSimulationContext(Integer.valueOf(_cvalue));
295
296                 getFilter().getSimContexts().add(selected);
297                 setContextTypeOptions(getInvolvedContexts()); // Sets critext
298                 getSession().remove(RESULT_KEY); // The current result is obsolete
299                 return "refresh";
300         }
301
302         /**
303          * Remove context from the search filter.
304          * 
305          * @return "refresh"
306          */
307         protected String doRemoveContext() {
308                 long index = Long.valueOf(_cindex);
309                 for (Iterator<SimulationContext> selected = getFilter()
310                                 .getSimContexts().iterator(); selected.hasNext();) {
311                         if (selected.next().getIndex() == index) {
312                                 selected.remove();
313                                 break;
314                         }
315                 }
316                 setContextTypeOptions(getInvolvedContexts()); // Sets critext
317                 getSession().remove(RESULT_KEY); // The current result is obsolete
318                 return "refresh";
319         }
320
321         /**
322          * Cancel simulation context selection.
323          * 
324          * @return "refresh"
325          */
326         @SuppressWarnings(Constants.UNCHECKED)
327         protected String doCancel() {
328                 _result = (List<Proxy>) getSession().get(RESULT_KEY); // Current result search
329                 setContextTypeOptions(getInvolvedContexts()); // Sets critext
330                 return "refresh";
331         }
332
333         // ==============================================================================================================================
334         // Getters
335         // ==============================================================================================================================
336
337         /**
338          * Get date format string.
339          * 
340          * @return date format string
341          */
342         public String getFormat() {
343                 return getText("date.format");
344         }
345
346         /**
347          * Get formatted today date as a string.
348          * 
349          * @return current date as a string
350          */
351         public String getToday() {
352                 SimpleDateFormat tostring = new SimpleDateFormat(getFormat(),
353                                 getApplicationSettings().getCurrentLocale());
354                 return tostring.format(java.util.Calendar.getInstance().getTime());
355         }
356
357         /**
358          * Get search result state.
359          * 
360          * @return "obsolete" if there is no results in the session, otherwise "uptodate"
361          */
362         public String getResultState() {
363                 String result;
364                 if (getSession().get(RESULT_KEY) == null) {
365                         result = "obsolete";
366                 } else {
367                         result = "uptodate";
368                 }
369                 return result;
370         }
371
372         public List<Name> getCandidates() {
373                 return _candidates;
374         }
375
376         public List<SimulationContextType> getContextTypeOptions() {
377                 return _critext;
378         }
379
380         public List<SimulationContext> getContextValueOptions() {
381                 return _newvalue;
382         }
383
384         public SimulationContextType getSelectedContextType() {
385                 return _newtype;
386         }
387
388         /**
389          * Get list of found objects.
390          * 
391          * @return list of found objects
392          */
393         public List<Proxy> getResult() {
394                 return _result;
395         }
396
397         // ==============================================================================================================================
398         // Setters
399         // ==============================================================================================================================
400
401         /**
402          * Set applied simulation context type id to search.
403          * 
404          * @param type
405          *            persistent simulation context type id
406          */
407         public void setContextType(final String type) {
408                 this._ctype = type;
409         }
410
411         /**
412          * Set value of simulation context to search.
413          * 
414          * @param value
415          *            the simulation context value
416          */
417         public void setContextValue(final String value) {
418                 this._cvalue = value;
419         }
420
421         /**
422          * Set simulation context value id.
423          * 
424          * @param value
425          *            the persistent id as string
426          */
427         public void setContextIndex(final String value) {
428                 this._cindex = value;
429         }
430
431         /**
432          * Build the list of study authors. If the current user also can create <BR>
433          * a study then it is placed on the top of the list.
434          */
435         protected void setCandidates() {
436                 _candidates = new ArrayList<Name>();
437                 List<User> users = getUserService().selectAllUsers();
438                 User me = getConnectedUser(); // May be null
439                 for (Iterator<User> i = users.iterator(); i.hasNext();) {
440                         User next = i.next();
441                         ApplicationRights he = new ApplicationRights(next);
442                         if (he.canCreateStudy()) {
443                                 if (next.equals(me)) {
444                                         _candidates.add(0, new ValidationFacade.ByManager(me,
445                                                         getApplicationSettings().getCurrentLocale()));
446                                 } else {
447                                         _candidates.add(next);
448                                 }
449                         }
450                 }
451         }
452
453         /**
454          * Build available context types list with localized names.
455          * 
456          * @param critext
457          *            context types already used in the search filter
458          */
459         protected void setContextTypeOptions(
460                         final List<SimulationContextType> critext) {
461                 for (SimulationContext ctx : getFilter().getSimContexts()) {
462                         critext.remove(ctx.getType()); // Already used context type
463                 }
464                 // Ordering by alphabetical order of localized context types
465                 SimulationContextType[] types = critext
466                                 .toArray(new SimulationContextType[critext.size()]);
467                 ContextTypeComparator compare = new ContextTypeComparator();
468                 ProjectSettingsService.Step step = getSimulationContextService()
469                                 .getAttachedStep(types[0]);
470                 int from = 0;
471                 int to = 0;
472                 while (to < types.length - 1) {
473                         to += 1;
474                         if (!types[to].isAttachedTo(step)) {
475                                 if (to > from + 1) {
476                                         Arrays.sort(types, from, to, compare);
477                                 }
478                                 from = to;
479                                 step = getSimulationContextService().getAttachedStep(types[to]);
480                         }
481                 }
482                 if (to > from) {
483                         Arrays.sort(types, from, to + 1, compare);
484                 }
485                 this._critext = Arrays.asList(types);
486         }
487
488         /**
489          * Load the search filter. The filter is taken from the session by its name.
490          * 
491          * @see #getFilterName()
492          * @return the loaded filter
493          */
494         @SuppressWarnings(Constants.UNCHECKED)
495         protected Map<String, Object> loadFilter() {
496                 Map<String, Object> filter = (Map<String, Object>) getSession().get(
497                                 getFilterName()); // A default filter is supposed being set at start
498
499                 setFilter((FilterClass) filter.get("criteria"));
500                 return filter;
501         }
502
503         /**
504          * Save search criteria in the session as a map with the defined name.
505          * 
506          * @see #getFilterName()
507          * @return the saved filter
508          */
509         @SuppressWarnings(Constants.UNCHECKED)
510         protected Map<String, Object> saveFilter() {
511                 Map<String, Object> filter = (Map<String, Object>) getSession().get(
512                                 getFilterName()); // A default filter is supposed being set at start
513
514                 FilterClass savedCriteria = (FilterClass) filter.get("criteria");
515                 FilterClass newCriteria = getFilter();
516                 if (savedCriteria != null) {
517                         // Only contexts are not part of the form so keep them between requests
518                         newCriteria.setSimContexts(savedCriteria.getSimContexts());
519                 }
520
521                 filter.put("criteria", getFilter());
522                 return filter;
523         }
524
525         // ==============================================================================================================================
526         // Abstract services
527         // ==============================================================================================================================
528
529         /**
530          * Search objects according to the given criteria.
531          * 
532          * @return string result key
533          * @throws InvalidPropertyException
534          *             if some criteria values are incorrect
535          */
536         protected abstract String doSearch() throws InvalidPropertyException;
537
538         /**
539          * List of context types available for filtering.
540          * 
541          * @return list of simulation context types
542          */
543         protected abstract List<SimulationContextType> getInvolvedContexts();
544
545         /**
546          * Get the name of the search criteria filter saved as a map of objects in the session.
547          * 
548          * @return the search filter name in the session
549          */
550         protected abstract String getFilterName();
551
552         /**
553          * Get search filter implementation.
554          * 
555          * @return the search filter
556          */
557         protected abstract FilterClass getNewFilter();
558
559         // ==============================================================================================================================
560         // Getters and Setters
561         // ==============================================================================================================================
562
563         /**
564          * Get match options.
565          * 
566          * @return array of options with key and value properties
567          */
568         public Map<String, String> getMatchOptions() {
569                 Map<String, String> options = new LinkedHashMap<String, String>();
570                 options.put("all", getText("field.matchall"));
571                 options.put("any", getText("field.matchany"));
572                 return options;
573         }
574
575         /**
576          * Get the simulationContextService.
577          * 
578          * @return the simulationContextService
579          */
580         public SimulationContextService getSimulationContextService() {
581                 return _simulationContextService;
582         }
583
584         /**
585          * Set the simulationContextService.
586          * 
587          * @param simulationContextService
588          *            the simulationContextService to set
589          */
590         public void setSimulationContextService(
591                         final SimulationContextService simulationContextService) {
592                 _simulationContextService = simulationContextService;
593         }
594
595         /**
596          * Get the userService.
597          * 
598          * @return the userService
599          */
600         public UserService getUserService() {
601                 return _userService;
602         }
603
604         /**
605          * Set the userService.
606          * 
607          * @param userService
608          *            the userService to set
609          */
610         public void setUserService(final UserService userService) {
611                 _userService = userService;
612         }
613
614         /**
615          * Get the filter.
616          * 
617          * @return the filter
618          */
619         public FilterClass getFilter() {
620                 if (_filter == null) {
621                         _filter = getNewFilter();
622                 }
623                 return _filter;
624         }
625
626         /**
627          * Set the filter.
628          * 
629          * @param filter
630          *            the filter to set
631          */
632         public void setFilter(final FilterClass filter) {
633                 if (filter == null) {
634                         _filter = getNewFilter();
635                 } else {
636                         _filter = filter;
637                 }
638         }
639
640         /**
641          * Get the newSortedBy.
642          * @return the newSortedBy
643          */
644         public SortCriterion getNewSortedBy() {
645                 return _newSortedBy;
646         }
647
648         /**
649          * Set the newSortedBy.
650          * @param newSortedBy the newSortedBy to set
651          */
652         public void setNewSortedBy(final SortCriterion newSortedBy) {
653                 _newSortedBy = newSortedBy;
654         }
655 }