4A Server -  2.0
 All Classes Namespaces Files Functions Variables Enumerator
SuggestionManager.java
Go to the documentation of this file.
1 /*
2  * Project: Server for annotations sharing
3  * Author: Ing. Jaroslav Dytrych idytrych@fit.vutbr.cz
4  * File: SuggestionManager.java
5  * Description: Class provides offerining of suggestion with usage of local
6  * knowledge repository.
7  */
8 
9 /**
10  * @file SuggestionManager.java
11  *
12  * @brief Class provides offerining of suggestion from local knowledge
13  * repository.
14  */
15 
16 package cz.vutbr.fit.knot.annotations.modules.suggestionManager;
17 
25 import cz.vutbr.fit.knot.annotations.entity.*;
40 import java.util.*;
41 import java.util.logging.Level;
42 import java.util.logging.Logger;
43 import javax.persistence.EntityManager;
44 import javax.persistence.EntityTransaction;
45 import javax.persistence.Query;
46 import javax.xml.xpath.XPathExpressionException;
47 import org.json.simple.JSONObject;
48 import org.json.simple.JSONValue;
49 import org.w3c.dom.Document;
50 
51 /**
52  * Class provides offerining of suggestion with usage of local knowledge repository.
53  *
54  * @brief Class provides offerining of suggestions with usage of local knowledge
55  * repository.
56  *
57  * @author Martin Petr (xpetrm05)
58  */
59 
60 /*
61  * INFO:
62  * If suggestions are created, their types are created in default group
63  * of actual user. For other users suggestions will be handled independently
64  * on types and types will be cloned to their's default group (if they
65  * are already existing, they are used). Confirmation or refusing then will be
66  * in default group so there shhould not be mess in feedback in basic scenario,
67  *
68  * TODO: In advanced scenario user will be changing own default group
69  * so feedback have to be used from all user's groups.
70  *
71  * TODO: Locking of the document should be revised.
72  */
73 
74 /**
75  * Class provides offerining of suggestions.
76  *
77  * @author Martin Petr (xpetrm05)
78  */
79 public class SuggestionManager extends Thread {
80 
81  /** Informations about request from client*/
83 
84  public static final int NOT_USABLE_CONFIDENCE = 4;
85  public static final int MINIMAL_CONFIDENCE = 5;
86  public static final int INITIAL_CONFIDENCE = 50;
87  public static final int REFUSED_CONFIDENCE = 40;
88  public static final int CONFIRMED_CONFIDENCE = 90;
89  public static final int MINIMAL_FILTER_CONFIDENCE = 5;
90  /** Name of this module */
91  public static final String MODULE_NAME = "SuggestionManager";
92 
93  /** Default user group */
95 
96  /**
97  * Source of suggestions (unknown - probably user, SEC API or NER).
98  *
99  * @brief Source of suggestions.
100  */
101  public enum SuggestionSource {
105  }
106 
107  /**
108  * Constructor
109  *
110  * @param request Informations about client request
111  */
113  super("SuggestionsManagerModuleThread");
114  this.requestInfo = request;
115  }
116 
117  /**
118  * Method start the thread code execution.
119  */
120  @Override
121  public void run() {
122  if (requestInfo.getSession() == null || requestInfo.getSession().getUser() == null
123  || requestInfo.getSession().getUser().getGroups() == null || requestInfo.getSession().getUser().getGroups().isEmpty()
124  || requestInfo.getSession().getSyncDocument() == null || requestInfo.getSession().getDefaultGroup() == null) {
125  return;
126  }
127 
128  AnnotDocument doc = requestInfo.getSession().getSyncDocument();
129 
130  if(doc != null){
131  while(true){
132  if(AppBean.getLockMaster().getDocumentLock(doc.getId()).lockForRead()){
133  break;
134  }
135  }
136  }
137 
138  try{
139  startModule();
140  }
141 
142  catch(Exception ex){
143  String msg = "Unknown exception in SuggestionManager: " + ex.getMessage();
144  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg, ex);
145  // unlock document for change
146  if(doc != null){
147  AppBean.getLockMaster().getDocumentLock(doc.getId()).unlockForRead();
148  }
149  }
150 
151  finally{
152  // unlock document for change
153  if(doc != null){
154  AppBean.getLockMaster().getDocumentLock(doc.getId()).unlockForRead();
155  }
156  }
157  } // run()
158 
159  /**
160  * Method start module
161  */
162  void startModule(){
163 
164  if (isDocUpdate(requestInfo)) {
165  while (true) {
166  if (AppBean.getLockMaster().getSuggReqLock(requestInfo.getSession().getSyncDocument().getId()).lockForChange()) {
167  break;
168  }
169  }
170  try {
172  } finally {
173  AppBean.getLockMaster().getSuggReqLock(requestInfo.getSession().getSyncDocument().getId()).unlockForChange();
174  }
175  }
176 
178  // request for new suggestions
179  String result = getSuggestions(requestInfo);
180  requestInfo.getSession().addMessageTS(result);
181  requestInfo.getSession().notifyComet();
182  }
183 
184  // positive feedback, added annotations, changed annotations
185  ArrayList<SuggestionLogEntry> rSugs = new ArrayList<SuggestionLogEntry>();
186  ArrayList<SuggestionLogEntry> sSugs = new ArrayList<SuggestionLogEntry>();
189  }
190  if (!requestInfo.getSession().getUpdateNegFeedbackForRefusedBySame()) {
191  sSugs = rSugs;
192  }
193 
195  // suggestions were refused
196  rejectSuggestions(requestInfo, sSugs, rSugs);
197  }
198 
199  if (requestInfo.getAlternativesRequestedFor() != null && !requestInfo.getAlternativesRequestedFor().isEmpty()) {
200  boolean logIt = AppBean.getLogGetAlternativesFor();
201  // alternatives for some suggestions was requested
202  Iterator<Suggestion> sugIt = requestInfo.getAlternativesRequestedFor().iterator();
203  while (sugIt.hasNext()) {
204  Suggestion sug = sugIt.next();
205  AlternativeManager.activateAlternatives(requestInfo, sug);
206  if (logIt) {
207  String msg = "getAlternativesFor " + sug.getId() + " for document " + requestInfo.getSession().getSyncDocument().getUri();
208  Logger.getLogger(SuggestionManager.class.getName()).log(Level.WARNING, msg);
209  }
210  }
211  String result = printSuggestionsDiff(requestInfo.getSession(), new ArrayList<Suggestion>(), new ArrayList<AnnotType>());
212  requestInfo.getSession().addMessageTS(result);
213  requestInfo.getSession().notifyComet();
214  }
215 
216  if (isAnnotDelete(requestInfo)) {
217  // annotations was deleted
218  String result = annotationsDelete(requestInfo);
219  requestInfo.getSession().addMessageTS(result);
220  requestInfo.getSession().notifyComet();
221  }
222 
223  // positive feedback, added annotations, changed annotations
227  // make message for client
229  }
230  }
231 
232  /**
233  * Top level method thats handle situation when there is positive feedback,
234  * added annotations or changed annotations
235  *
236  * @param request informations about client request
237  */
238  private void annotationsAddChange(RequestInfo request) {
239  // get list of added and edited annotations
240  ArrayList<Annotation> addedAnnotations = new ArrayList<Annotation>();
241  ArrayList<Annotation> editedAnnotations = new ArrayList<Annotation>();
242  addedAnnotations.addAll(requestInfo.getFlier().getAddedAnnotations());
243  editedAnnotations.addAll(requestInfo.getFlier().getEditedAnnotations());
244 
245  // lock document for suggestion change
246  lockDocForChange(requestInfo.getSession().getSyncDocument().getId());
247  ArrayList<Suggestion> suggestionsToChange = SugPersister.persist(requestInfo, addedAnnotations, editedAnnotations, null, true, new ArrayList<AnnotType>());
248  AlternativeManager.confirmSuggestions(request, suggestionsToChange);
249  // unlock document for suggestions change
250  unlockDocForChange(requestInfo.getSession().getSyncDocument().getId());
251 
252 
253  String result = printSuggestionsDiff(requestInfo.getSession(), suggestionsToChange, new ArrayList<AnnotType>());
254  requestInfo.getSession().addMessageTS(result);
255  requestInfo.clearConfirmedSuggestions();
256  requestInfo.getSession().notifyComet(); // send to client
257 
258  synchronized(AppBean.getSessions()){
259  Iterator<EditorSession> sIt = AppBean.getSessions().iterator();
260  while (sIt.hasNext()) { // send to others
261  EditorSession es = sIt.next();
262  if (es.equals(requestInfo.getSession()) || es.getSyncDocument() == null || !es.getSyncDocument().equals(request.getSession().getSyncDocument())) {
263  continue;
264  }
265  result = printSuggestionsDiff(es, suggestionsToChange, new ArrayList<AnnotType>());
266  es.addMessageTS(result);
267  es.notifyComet();
268  }
269  }
270  } // annotationsAddChange()
271 
272  /**
273  * Method finds all linked and nested suggestions of suggestions and return
274  * them as an ArrayList.
275  *
276  * @param suggestion suggestion with possible dependencies
277  * @return list of found linked and nested suggestions
278  */
279  private static ArrayList<Suggestion> getAllDependencies(Suggestion suggestion){
280  ArrayList<Suggestion> retArray = new ArrayList<Suggestion>();
281  if(suggestion != null){
282 
283  // go trough all attributes of suggestion
284  List attrObjects = suggestion.getAttributes();
285  if(attrObjects != null && !attrObjects.isEmpty()){
286  Iterator attrIt = attrObjects.iterator();
287  while(attrIt.hasNext()){
288  Object actualObject = (Object) attrIt.next();
289 
290  // try find linked suggestion attributes
291  if(actualObject instanceof SugLinkedAttribute){
292  // if find linked suggestion attribute
293  SugLinkedAttribute currentLink = (SugLinkedAttribute)actualObject;
294  if(currentLink.getValue() != null && currentLink.getValue() instanceof Suggestion){
295  // add it to return array
296  retArray.add(((Suggestion)currentLink.getValue()));
297  }
298  }
299  // find all nested suggestions
300  else if (actualObject instanceof SugNestedAttribute) {
301  SugNestedAttribute currentNested = (SugNestedAttribute)actualObject;
302  if (currentNested.getValue() != null && currentNested.getValue() instanceof Suggestion) {
303  retArray.add(((Suggestion)currentNested.getValue()));
304  }
305  }
306  }
307  }
308  // if the suggestion is nested in another one, the parent suggestion
309  // must be added to the list as a dependency
310  if (suggestion.getNestedInSuggestion() != null) {
311  retArray.add(suggestion.getNestedInSuggestion());
312  }
313  } // if(suggestion != null){
314 
315  return retArray;
316  } // getAllDependencies()
317 
318 
319  /**
320  * Top level method thats handle situation when annotations are deleted.
321  *
322  * @param request informations about client request
323  * @return string with message for client
324  */
325  private String annotationsDelete(RequestInfo request){
326  // get annotations deleted by user
327  ArrayList<Suggestion> changedSuggestions = getAffectedForDelete(request.getFlier().getRemovedAnnotations());
328 
329  return printSuggestionsDiff(request.getSession(), changedSuggestions, new ArrayList<AnnotType>());
330  }
331 
332  /**
333  * Top level method thats handle situation when user want suggestions.
334  *
335  * @param request informations about client request
336  * @return string with message for client
337  */
338  private String getSuggestions(RequestInfo request){
339  while(true){
340  if(AppBean.getLockMaster().getSuggReqLock(requestInfo.getSession().getSyncDocument().getId()).lockForChange()){
341  break;
342  }
343  }
344  try {
345  ArrayList<Suggestion> allSuggest = getSuggestionsFromDB(request.getSession().getSyncDocument().getId());
346  if (allSuggest.isEmpty()) {
347  updateDocument(request);
348  return "";
349  }
350  } finally {
351  AppBean.getLockMaster().getSuggReqLock(requestInfo.getSession().getSyncDocument().getId()).unlockForChange();
352  }
353  return printSuggestionsDiff(request.getSession(), new ArrayList<Suggestion>(), new ArrayList<AnnotType>());
354  } // getSuggestions()
355 
356  /**
357  * Top level method thats handle situation when synchronized document was updated.
358  *
359  * @param request informations about client request
360  */
361  private void updateDocument(RequestInfo request){
362  // suggestions from DB
363  ArrayList<Suggestion> oldSuggestions = new ArrayList<Suggestion>();
364  ArrayList<Suggestion> addedSuggestions = new ArrayList<Suggestion>();
365  ArrayList<Suggestion> changedSuggestions = new ArrayList<Suggestion>();
366  ArrayList<AnnotType> newTypes = new ArrayList<AnnotType>();
367 
368  // get suggestions from DB
369  oldSuggestions.addAll(getSuggestionsFromDB(request.getSession().getSyncDocument().getId()));
370  // update document and suggestions belongs to document with new suggestions from NER
371  updateDocument(request,oldSuggestions,addedSuggestions,changedSuggestions, newTypes);
372 
373  ArrayList<Suggestion> modifiedSuggestions = new ArrayList<Suggestion>();
374  modifiedSuggestions.addAll(addedSuggestions);
375  modifiedSuggestions.addAll(changedSuggestions);
376 
377  String result = printSuggestionsDiff(request.getSession(), modifiedSuggestions, newTypes);
378  request.getSession().addMessageTS(result);
379  request.getSession().notifyComet();
380 
381  synchronized(AppBean.getSessions()){
382  Iterator<EditorSession> sIt = AppBean.getSessions().iterator();
383  while (sIt.hasNext()) { // send to others
384  EditorSession es = sIt.next();
385  if (es.equals(request.getSession()) || es.getSyncDocument() == null || !es.getSyncDocument().equals(request.getSession().getSyncDocument())) {
386  continue;
387  }
388  result = printSuggestionsDiff(es, modifiedSuggestions, new ArrayList<AnnotType>()); // types was already sent
389  es.addMessageTS(result);
390  es.notifyComet();
391  }
392  }
393  } // updateDocument()
394 
395  /**
396  * Send message to other clients
397  *
398  * @param requestInfo Informations about client request
399  * @param message String with message
400  */
401  public static void sendToOthers(RequestInfo requestInfo, String message) {
402  synchronized(AppBean.getSessions()){
403  Iterator<EditorSession> sesIt = AppBean.getSessions().iterator();
404  long sessionId = requestInfo.getSession().getSessionId();
405  while (sesIt.hasNext()) {
406  EditorSession es = sesIt.next();
407  if (es.getSessionId() == sessionId) {
408  continue;
409  }
410  es.addMessageTS(message);
411  }
412  }
413  }
414 
415  /**
416  * Top level method thats handle situation when user rejected some suggestions.
417  *
418  * @param request Informations about client request
419  * @param skipSugs Suggestions for which update of negative feedback should be skipped
420  * @param noAlternatives List of suggestions for which alternatives should not be activated
421  */
422  private void rejectSuggestions(RequestInfo request, ArrayList<SuggestionLogEntry> skipSugs, ArrayList<SuggestionLogEntry> noAlternatives){
423  // get suggestions directly affected with rejection
424  ArrayList<Suggestion> suggestionsToDelete = updateNegativeFeedback(request, skipSugs, noAlternatives);
425 
426  ArrayList<Suggestion> allSug = request.getSession().getWholeSendedSuggestions();
427  suggestionsToDelete.addAll(getNestedSuggFromToDelete(allSug, suggestionsToDelete));
428  ArrayList<Suggestion> affectedSug = cutRefusedSuggLinks(allSug, suggestionsToDelete);
429  affectedSug.addAll(suggestionsToDelete);
430 
431  String result = printSuggestionsDiff(request.getSession(), affectedSug, new ArrayList<AnnotType>());
432  requestInfo.getSession().addMessageTS(result);
433  requestInfo.getSession().notifyComet();
434  synchronized(AppBean.getSessions()){
435  Iterator<EditorSession> sIt = AppBean.getSessions().iterator();
436  while (sIt.hasNext()) { // send to others
437  EditorSession es = sIt.next();
438  if (es.equals(requestInfo.getSession()) || es.getSyncDocument() == null || !es.getSyncDocument().equals(request.getSession().getSyncDocument())) {
439  continue;
440  }
441  result = printSuggestionsDiff(es, affectedSug, new ArrayList<AnnotType>());
442  es.addMessageTS(result);
443  es.notifyComet();
444  }
445  }
446  } // rejectSuggestions()
447 
448  /**
449  * Creates message with added annotation types for the client
450  *
451  * @param session Informations about client session
452  * @param newTypes Array with new types of annotations
453  * @param requestInfo Informations about client request
454  * @return Returns message for the client
455  */
456  public static String printTypes(RequestInfo requestInfo, EditorSession session, ArrayList<AnnotType> newTypes) {
457  boolean withAnc = true; // types will be send with ancestors
458  if (requestInfo.getSession().getProtocolLOD() < Constants.PROTOCOL_LOD_V1_1) {
459  withAnc = false; // old client - types will be send without ancestors
460  }
461  String addedTStr = "";
462  Iterator<AnnotType> typeIter = newTypes.iterator();
463  while (typeIter.hasNext()) { // for each added type of annotation
464  AnnotType type = typeIter.next();
465  if (isTypeInGroups(type, requestInfo)) {
466  // TODO: If client not interested, don't send type (use session.getQueriedTypes())
467  if (requestInfo.getSession().getProtocolLOD() < Constants.PROTOCOL_LOD_V2) {
468  addedTStr = addedTStr + type.toXMLString(withAnc);
469  } else {
470  addedTStr = addedTStr + type.toXMLStringV2(withAnc);
471  }
472  }
473  }
474  if (!addedTStr.isEmpty()) { // if there are any added types to send
475  if (requestInfo.getSession().getProtocolLOD() < Constants.PROTOCOL_LOD_V2) {
476  addedTStr = "<types><add>" + addedTStr + "</add></types>"; // create message
477  } else {
478  addedTStr = "<addTypes>" + addedTStr + "</addTypes>"; // create message
479  }
480  }
481  if (!addedTStr.isEmpty()) { // if there is something to send
482  return addedTStr;
483  } else {
484  return "";
485  }
486  }
487 
488  /**
489  * Checks whether type come under user groups of logged in user
490  *
491  * @param annotType Checked type of annotation
492  * @param requestInfo Informations about client request
493  * @return If type come under user groups of logged in user, returns true,
494  * false otherwise
495  */
496  public static boolean isTypeInGroups(AnnotType annotType, RequestInfo requestInfo) {
497  if (requestInfo.getSession().getUser() == null) { // if user is not logged in, there is no groups
498  return false;
499  }
500  if (annotType.getGroup() == null) { // if type of annotation isn't assigned to user group
501  return false; // it can't come under user groups
502  }
503  Iterator<UserGroup> grIter = requestInfo.getSession().getUser().getGroups().iterator();
504  while (grIter.hasNext()) { // for each user group of logged in user
505  UserGroup userGroup = grIter.next();
506  if (annotType.getGroup().equals(userGroup)) { // if group of type is matching this group
507  return true;
508  }
509  }
510  return false;
511  } // isTypeInGroups()
512 
513 
514  /**
515  * Method which prepares messages for the client and updates client's session
516  * based on now modified suggestions and previous client's session.
517  *
518  * @param session Informations about client session
519  * @param modifiedSuggestions Suggestions which was modified in this request
520  * @param newTypes List of new annotation types to send along with suggestions
521  * @return Returns string with message for client
522  */
523  public String printSuggestionsDiff(EditorSession session, ArrayList<Suggestion> modifiedSuggestions, ArrayList<AnnotType> newTypes) {
524  ArrayList<Suggestion> shouldHave = null;
525  synchronized (session) {
526  ArrayList<Suggestion> allSuggest = getSuggestionsFromDB(session.getSyncDocument().getId());
527  ArrayList<Suggestion> filteredSuggest = new ArrayList<Suggestion>(allSuggest);
528  filtrateSuggestions(requestInfo, session, filteredSuggest);
529  shouldHave = addAllDependencies(filteredSuggest, allSuggest);
530  ArrayList<Suggestion> removedSug = getSuggestionWithoutFeedback(shouldHave, modifiedSuggestions);
531  ArrayList<Suggestion> rSug = getNestedSuggFromToDelete(shouldHave, removedSug);
532  modifiedSuggestions.addAll(cutRefusedSuggLinks(shouldHave, rSug));
533  modifiedSuggestions.addAll(removedSug);
534  checkTypes(session, shouldHave, newTypes, true);
535  }
536  persistTypes(newTypes);
537  // message with types
538  String msgTypes = printTypes(requestInfo, session, newTypes);
539  // send types to others
540  sendToOthers(requestInfo, msgTypes);
541  return msgTypes + filterByClientCache(session, shouldHave, modifiedSuggestions);
542  }
543 
544  /**
545  * Gets true value if one suggestion have link to other.
546  *
547  * @param suggestion suggestion where will be link searched
548  * @param linkedSuggestion suggestion to which is link searched
549  * @return Returns true value if one suggestion have link to other, false otherwise.
550  */
551  private boolean haveLinkOn(Suggestion suggestion, Suggestion linkedSuggestion){
552  if(suggestion != null && linkedSuggestion != null){
553  // get attributes of suggestion
554  List attrList = suggestion.getAttributes();
555  if(attrList != null && !attrList.isEmpty()){
556 
557  // go trough all objects that represents attributes
558  Iterator attrIt = attrList.iterator();
559  while(attrIt.hasNext()){
560 
561  Object actualAttr = (Object) attrIt.next();
562  // test if it is linked attribute
563  if(actualAttr instanceof SugLinkedAttribute){
564 
565  // test if attribute points to Suggestion
566  SugLinkedAttribute actualLink= (SugLinkedAttribute) actualAttr;
567  if(actualLink.getValue() instanceof Suggestion){
568 
569  // test if suggestion is searched suggestion
570  if(((Suggestion)actualLink.getValue()).getId().equals(linkedSuggestion.getId())){
571  return true;
572  }
573  }
574  } // if(actualLink.getValue() instanceof Suggestion)
575  } // while(attrIt.hasNext())
576  } // if(attrList != null && !attrList.isEmpty())
577  }
578 
579  return false;
580  } // haveLinkOn()
581 
582  /**
583  * Initializes Requested types definitions in AppBean
584  */
585  public static void initReqTypes() {
586  ArrayList<SecApiReqTypeDef> availableTypes = null;
587  try {
588  SECAPIInterface sai = AppBean.getSecApiInterface();
589  String SECAPIResults = sai.makeRequest(createSecApiTypesRequest());
590  // process types and attributes
591  availableTypes = SECTypesTranslator.translate(SECAPIResults);
592  } catch (Exception ex) {
593  String message = "SEC API call error : " + ex.getMessage();
594  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, message);
595  AppBean.setReqTypeDefinitions(new ArrayList<SecApiReqTypeDef>()); // clear list
596  return;
597  }
598  if (availableTypes == null || availableTypes.isEmpty()) {
599  AppBean.setReqTypeDefinitions(new ArrayList<SecApiReqTypeDef>()); // clear list
600  return;
601  }
602 
603  AppBean.setAvTypeDefinitions(availableTypes);
604  // load desired and unnecessary type definitions from database
606  // filter types and prepare AppBean structures
607  SecApiReqTypeDef.filterTypes();
608  } // initReqTypes()
609 
610  /**
611  * Initializes Requested types definitions in AppBean from remote SEC API
612  *
613  * @param conn Connection to SEC API server
614  * @param requestInfo Info about clients request
615  */
617  ArrayList<SecApiReqTypeDef> availableTypes = null;
618  try {
619  String SECAPIResults = conn.sendReqToSECAPI(createSecApiTypesRequest(), requestInfo);
620  // process types and attributes
621  availableTypes = SECTypesTranslator.translate(SECAPIResults);
622  } catch (Exception ex) {
623  String message = "SEC API call error : " + ex.getMessage();
624  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, message);
625  AppBean.setReqTypeDefinitions(new ArrayList<SecApiReqTypeDef>()); // clear list
626  return;
627  }
628  if (availableTypes == null || availableTypes.isEmpty()) {
629  AppBean.setReqTypeDefinitions(new ArrayList<SecApiReqTypeDef>()); // clear list
630  return;
631  }
632 
633  AppBean.setAvTypeDefinitions(availableTypes);
634  // load desired and unnecessary type definitions from database
636  // filter types and prepare AppBean structures
637  SecApiReqTypeDef.filterTypes();
638  } // initReqTypesFromRemote()
639 
640  /**
641  * Loads desired and unnecessary type definitions from database
642  */
643  @SuppressWarnings("unchecked")
644  private static void loadTypeDefsFromDB() {
645  String desiredJSONData = "";
646  String unnecessaryJSONData = "";
647  String unnecessaryAtJSONData = "";
648 
649  String desiredEAJSONData = "";
650  String unnecessaryEAJSONData = "";
651  String unnecessaryAtEAJSONData = "";
652 
653  Object[] paramsD = {"name", Constants.SEC_DESIRED_TYPES_SETTINGS_NAME};
654  List<ServerSetting> settingsList = AppBean.getPersistenceManager().queryDB("ServerSetting.findByName", paramsD);
655  if (settingsList != null && !settingsList.isEmpty()) {
656  if (!settingsList.get(0).getSettingValue().isEmpty()) {
657  desiredJSONData = settingsList.get(0).getSettingValue();
658  }
659  }
660  Object[] paramsU = {"name", Constants.SEC_UNNECESSARY_TYPES_SETTINGS_NAME};
661  settingsList = AppBean.getPersistenceManager().queryDB("ServerSetting.findByName", paramsU);
662  if (settingsList != null && !settingsList.isEmpty()) {
663  if (!settingsList.get(0).getSettingValue().isEmpty()) {
664  unnecessaryJSONData = settingsList.get(0).getSettingValue();
665  }
666  }
667  Object[] paramsUA = {"name", Constants.SEC_UNNECESSARY_TYPES_SETTINGS_NAME};
668  settingsList = AppBean.getPersistenceManager().queryDB("ServerSetting.findByName", paramsUA);
669  if (settingsList != null && !settingsList.isEmpty()) {
670  if (!settingsList.get(0).getSettingValue().isEmpty()) {
671  unnecessaryAtJSONData = settingsList.get(0).getSettingValue();
672  }
673  }
674 
675  Object[] paramsDEA = {"name", Constants.SEC_DESIRED_TYPES_SETTINGS_NAME_EA};
676  settingsList = AppBean.getPersistenceManager().queryDB("ServerSetting.findByName", paramsDEA);
677  if (settingsList != null && !settingsList.isEmpty()) {
678  if (!settingsList.get(0).getSettingValue().isEmpty()) {
679  desiredEAJSONData = settingsList.get(0).getSettingValue();
680  }
681  }
682  Object[] paramsUEA = {"name", Constants.SEC_UNNECESSARY_TYPES_SETTINGS_NAME_EA};
683  settingsList = AppBean.getPersistenceManager().queryDB("ServerSetting.findByName", paramsUEA);
684  if (settingsList != null && !settingsList.isEmpty()) {
685  if (!settingsList.get(0).getSettingValue().isEmpty()) {
686  unnecessaryEAJSONData = settingsList.get(0).getSettingValue();
687  }
688  }
689  Object[] paramsUAEA = {"name", Constants.SEC_UNNECESSARY_TYPES_SETTINGS_NAME};
690  settingsList = AppBean.getPersistenceManager().queryDB("ServerSetting.findByName", paramsUAEA);
691  if (settingsList != null && !settingsList.isEmpty()) {
692  if (!settingsList.get(0).getSettingValue().isEmpty()) {
693  unnecessaryAtEAJSONData = settingsList.get(0).getSettingValue();
694  }
695  }
696 
697  ArrayList<SecApiReqTypeDef> desiredTypes = SECTypesTranslator.translate(desiredJSONData);
698  ArrayList<SecApiReqTypeDef> unnecessaryTypes = SECTypesTranslator.translate(unnecessaryJSONData);
699  ArrayList<SecApiReqTypeDef> unnecessaryAttributes = SECTypesTranslator.translate(unnecessaryAtJSONData);
700 
701  ArrayList<SecApiReqTypeDef> desiredTypesEA = SECTypesTranslator.translate(desiredEAJSONData);
702  ArrayList<SecApiReqTypeDef> unnecessaryTypesEA = SECTypesTranslator.translate(unnecessaryEAJSONData);
703  ArrayList<SecApiReqTypeDef> unnecessaryAttributesEA = SECTypesTranslator.translate(unnecessaryAtEAJSONData);
704 
705  AppBean.setDesTypeDefinitions(desiredTypes);
706  AppBean.setUnTypeDefinitions(unnecessaryTypes);
707  AppBean.setUnAtDefinitions(unnecessaryAttributes);
708 
709  AppBean.setDesTypeDefinitionsEA(desiredTypesEA);
710  AppBean.setUnTypeDefinitionsEA(unnecessaryTypesEA);
711  AppBean.setUnAtDefinitionsEA(unnecessaryAttributesEA);
712  } // loadTypeDefsFromDB()
713 
714  /**
715  * Gets suggestions from SEC API and translates them to the Suugestion objects.
716  *
717  * @param parRequestInfo Informations about client request
718  * @param doc Linearized document
719  * @param uri URI of original document
720  * @param useAlternatives True for work with alternatives, false otherwise
721  * @param validSuggestions List of valid suggestions
722  * @return Returns suggestions (ArrayList<Suggestion>) or alternatives of suggestions (ArrayList<Alternative>) for the document
723  */
724  public String getSuggestionsFromSECAPI(RequestInfo parRequestInfo, String doc, String uri, boolean useAlternatives, ArrayList<Suggestion> validSuggestions){
725  String secApiXmlData = null;
726 
727  String SECAPIResults = "";
728 
729  String secApiRequest = createSecApiSuggestionsRequest(doc, uri, useAlternatives);
730 
731  Boolean processed = false;
732  try {
733  SECAPIInterface sai = AppBean.getSecApiInterface();
734  SECAPIResults = sai.makeRequest(secApiRequest);
735  processed = true;
736  } catch (Exception ex) {
737  String message = "SEC API call error : " + ex.getMessage();
738  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, message);
739  }
740 
741  // Second attempt
742  if (SECAPIResults == null || SECAPIResults.isEmpty()) {
743  try {
744  SECAPIInterface sai = AppBean.getSecApiInterface();
745  // restart SEC API before process
746  sai.close();
747  if (!sai.init()) {
748  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, "Initialisation of SEC API failed!");
749  return secApiXmlData;
750  }
751  // it is possible that we have updated version of SEC API now
752  // (old version was killed and new was started now)
753  initReqTypes();
754  if (AppBean.getReqTypeDefinitions().isEmpty()) {
755  return secApiXmlData;
756  }
757  // update request data
758  secApiRequest = createSecApiSuggestionsRequest(doc, uri, false);
759  // process request
760  SECAPIResults = sai.makeRequest(secApiRequest);
761  processed = true;
762  } catch (Exception ex) {
763  String message = "SEC API call error : " + ex.getMessage();
764  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, message);
765  return secApiXmlData;
766  }
767  }
768 
769  // get XML from JSON
770  secApiXmlData = getSuggestionsXMLFromJSON(SECAPIResults);
771  if (secApiXmlData.isEmpty()) {
772  return null;
773  }
774  return secApiXmlData;
775  } // getSuggestionsFromSECAPI()
776 
777  /**
778  * Gets suggestions from remote SEC API and translates them to the Suggestion objects.
779  *
780  * @param parRequestInfo Informations about client request
781  * @param doc Linearized document
782  * @param uri URI of original document
783  * @param useAlternatives True for work with alternatives, false otherwise
784  * @param validSuggestions List of valid suggestions
785  * @return Returns suggestions (ArrayList<Suggestion>) or alternatives of suggestions (ArrayList<Alternative>) for the document
786  */
787  public String getSuggestionsFromRemoteSECAPI(RequestInfo parRequestInfo, String doc, String uri, boolean useAlternatives, ArrayList<Suggestion> validSuggestions){
788  String secApiXmlData = null;
789 
790  String SECAPIResults = "";
791 
792  String secApiRequest = "";
793 
794  try {
795  SECAPIConn sac = new SECAPIConn();
796  // it is possible that SEC API was updated after last request
797  // (old version was killed and new was started) so we need to refresh types
798  initReqTypesFromRemote(sac, parRequestInfo);
799  if (AppBean.getReqTypeDefinitions().isEmpty()) {
800  return secApiXmlData;
801  }
802  // create request data
803  secApiRequest = createSecApiSuggestionsRequest(doc, uri, useAlternatives);
804  // process request
805 
806 
807  SECAPIResults = sac.sendReqToSECAPI(secApiRequest, parRequestInfo);
808  } catch (Exception ex) {
809  String message = "Remote SEC API call error : " + ex.getMessage();
810  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, message);
811  }
812 
813  if(SECAPIResults == null){
814  return null;
815  }
816 
817  // get XML from JSON
818  secApiXmlData = getSuggestionsXMLFromJSON(SECAPIResults);
819  if (secApiXmlData.isEmpty()) {
820  return null;
821  }
822  return secApiXmlData;
823  } // getSuggestionsFromRemoteSECAPI()
824 
825  /**
826  * Gets XML with suggestions from JSON response data from SEC API
827  *
828  * @param responseData Response data from SEC API
829  * @return Returns XML with suggestions in String
830  */
831  private static String getSuggestionsXMLFromJSON(String responseData) {
832  JSONObject jsonData = (JSONObject)JSONValue.parse(responseData);
833  if (jsonData == null) {
835  String msg = "Unable to parse received JSON string with suggestions.";
836  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
837  }
838  return "";
839  }
840  if (checkException(jsonData)) { // check for exception
841  return "";
842  }
843  String suggXML = null;
844  // try to get XML with suggestions
845  try {
846  suggXML = (String) jsonData.get("annotation");
847  } catch (Exception e) {
849  String msg = "Unable to parse received JSON string with suggestions.";
850  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg, e);
851  }
852  return "";
853  }
854 
855  return suggXML;
856  } // getSuggestionsXMLFromJSON()
857 
858  /**
859  * Checks if JSON from SEC API contains exception and if yes, logs it
860  *
861  * @param jsonData JSON data from SEC API
862  * @return If exception was presented, returns true, false otherwise
863  */
864  private static boolean checkException(JSONObject jsonData) {
865  String exceptionData = null;
866  try { // try to get exception
867  exceptionData = (String) jsonData.get("exception");
868  } catch (Exception e) { // error never mind here
869  }
870  if (exceptionData != null && !exceptionData.isEmpty()) {
872  String msg = "SEC API returned exception: " + exceptionData;
873  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
874  }
875  return true;
876  }
877  return false;
878  }
879 
880  /**
881  * Creates SEC API request for suggestions
882  *
883  * @param doc Linearized document
884  * @param uri URI of original document
885  * @param useAlternatives True for work with alternatives, false otherwise
886  * @return Returns SEC API request for suggestions
887  */
888  private static String createSecApiSuggestionsRequest(String doc, String uri, boolean useAlternatives) {
889  StringBuilder reqTypes = new StringBuilder();
890  ArrayList<SecApiReqTypeDef> rtdList = AppBean.getReqTypeDefinitions();
891  if (rtdList == null) {
893  String msg = "Unable to get requseted type definitions while creating "
894  + "SEC API Suggestions Request.";
895  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
896  }
897  rtdList = new ArrayList<SecApiReqTypeDef>();
898  }
899  Iterator<SecApiReqTypeDef> rtdIt= rtdList.iterator();
900  if (rtdIt.hasNext()) { // first type
901  SecApiReqTypeDef rtd = rtdIt.next();
902  reqTypes.append(rtd.getRequestString());
903  }
904  while (rtdIt.hasNext()) {
905  SecApiReqTypeDef rtd = rtdIt.next();
906  reqTypes.append(", ");
907  reqTypes.append(rtd.getRequestString());
908  }
909 
910  return "{ \"annotate\": {" +
911  " \"input_text\": \"" + EscapeForSecApi(doc) + "\"," +
912  " \"annotation_format\": [\"sxml\"]," +
913  " \"disambiguate\": " + (useAlternatives ? "0" : "1") + "," +
914  " \"document_uri\": \"" + uri + "\"," +
915  " \"types_and_attributes\": { " + reqTypes + " }"+
916  " } }\n";
917  }
918  private static String disambiguate = "1";
919 
920  /**
921  * Creates SEC API request for types and attributes
922  *
923  * @return Returns SEC API request for types and attributes
924  */
925  private static String createSecApiTypesRequest() {
926  return "{ \"get_entity_types_and_attributes\": {} }\n";
927  }
928 
929  /**
930  * Finds offsets of all ocurrences of refuse border separator in linearized
931  * document (separators are defined in Constants)
932  *
933  * @param doc Linearized document
934  * @return Returns offsets of separators
935  */
936  private static ArrayList<Integer> findSeparators(String doc) {
937  ArrayList<Integer> result = new ArrayList<Integer>();
938  Iterator<String> sepIt = Constants.REFUSE_BORDER_SEPARATOR.iterator();
939  while (sepIt.hasNext()) {
940  String sep = sepIt.next();
941  int offset = doc.indexOf(sep);
942  while (offset >= 0) {
943  result.add(offset);
944  offset = doc.indexOf(sep, offset + 1);
945  }
946  }
947  Collections.sort(result);
948  return result;
949  } // findSeparators()
950 
951 
952  /**
953  * Method for updating negative feedback
954  *
955  * @param request Informations about client request
956  * @param skipSugs Suggestions for which update should be skipped
957  * @param noAlternatives List of suggestions for which alternatives should not be activated
958  * @return Refused suggestions
959  */
960  private ArrayList<Suggestion> updateNegativeFeedback(RequestInfo request, ArrayList<SuggestionLogEntry> skipSugs, ArrayList<SuggestionLogEntry> noAlternatives){
961  ArrayList<SuggestionLogEntry> suggLog = request.getRefusedSuggestions();
962  ArrayList<Suggestion> changedSuggestions = new ArrayList<Suggestion>();
963  Integer groupId = request.getSession().getDefaultGroup().getId();
964 
965  ArrayList<SuggestionLogEntry> addToLog = new ArrayList<SuggestionLogEntry>();
966 
967  ArrayList<Suggestion> allSugg = request.getSession().getWholeSendedSuggestions();
968  if (allSugg != null && !allSugg.isEmpty()) { // if there are some sended suggestions
969  HashMap<Integer, ArrayList<SuggestionFragment>> sugToLinFragments = new HashMap<Integer, ArrayList<SuggestionFragment>>();
970  SECAPISuggestionTranslator.linearizeSuggestions(sugToLinFragments, request.getSession().getParsedSyncDocument(), allSugg);
971  ArrayList<Integer> separators = findSeparators(request.getSession().getParsedLinDocument());
972  int docLength = request.getSession().getParsedLinDocument().length();
973 
974  Iterator<SuggestionLogEntry> refSugIt = suggLog.iterator();
975  while (refSugIt.hasNext()) { // for each refused suggestion
976  SuggestionLogEntry refSugLogEntry = refSugIt.next();
977  if (skipSugs.contains(refSugLogEntry)) {
978  continue;
979  }
980 
981  // get refused suggestion's annotated text
982  Integer refusedSuggestionId = Integer.parseInt(refSugLogEntry.getTmpId());
983  Suggestion refusedSuggestion = getSuggestionFromDB(refusedSuggestionId);
984  ArrayList<SuggestionFragment> suggFragList = refusedSuggestion.getFragmentsAL();
985  AnnotType refusedSuggType = refusedSuggestion.getAnnotType();
986 
987  // get refusedURI
988  String refusedURI = refusedSuggestion.getSAEntityIdentifier();
989  if (refusedURI != null && !refusedURI.isEmpty()) { // if there is URI of Entity
990  if (suggFragList != null && !suggFragList.isEmpty()) { // if suggestion have at least one fragment
991  if (suggFragList.size() >= 2) {
992  Collections.sort(suggFragList, new SuggestionFragmentComp());
993  }
994 
995  // find separators for current suggestion
996  int leftSep = 0;
997  int rightSep = docLength;
998  Integer curOffset = null;
999  ArrayList<SuggestionFragment> frags = sugToLinFragments.get(refusedSuggestionId);
1000  SuggestionFragment frag = null;
1001  if (frags != null && !frags.isEmpty()) {
1002  frag = frags.get(0);
1003  } else {
1004  frag = null; // no fragments - maybe it is for whole document
1005  }
1006  if (frag != null) {
1007  curOffset = frag.getOffset();
1008  Iterator<Integer> sepIt = separators.iterator();
1009  while (sepIt.hasNext()) {
1010  Integer s = sepIt.next();
1011  if (s < curOffset && leftSep < s) {
1012  leftSep = s;
1013  }
1014  if (s > curOffset && s < rightSep) {
1015  rightSep = s;
1016  }
1017  }
1018  }
1019 
1020  Iterator<Suggestion> allSuggIt = allSugg.iterator();
1021  while (allSuggIt.hasNext()) { // for each sended suggestion
1022  Suggestion actualSugg = allSuggIt.next();
1023 
1024  // Find offset for comparison with separators
1025  frags = sugToLinFragments.get(actualSugg.getId());
1026  if (frags != null && !frags.isEmpty()) {
1027  frag = frags.get(0);
1028  } else {
1029  frag = null;
1030  }
1031  if (frag != null) {
1032  curOffset = frag.getOffset();
1033  } else {
1034  curOffset = null;
1035  }
1036 
1037  // condition to ensure that sugg. are the same type and sugg. with the same id will be skipped
1038  Integer actualSuggId = actualSugg.getId();
1039  AnnotType actualSuggType = actualSugg.getAnnotType();
1040  String actualURI = actualSugg.getSAEntityIdentifier();
1041  if (actualSuggId != null && refusedSuggestionId != null && !actualSuggId.equals(refusedSuggestionId)
1042  && actualSuggType != null && refusedSuggType != null && actualSuggType.equals(refusedSuggType)
1043  && actualURI != null && refusedURI.equals(actualURI)) {
1044  // if it is not same suggestion but have same type and SEC API Entity URI
1045  ArrayList<SuggestionFragment> tmpFragList = actualSugg.getFragmentsAL();
1046  if (tmpFragList.size() >= 2) {
1047  Collections.sort(tmpFragList, new SuggestionFragmentComp());
1048  }
1049  // check whether both suggestion fragment lists have the same amount of fragments
1050  if (tmpFragList.size() == suggFragList.size()) {
1051  Iterator<SuggestionFragment> tmpFragListIt = tmpFragList.iterator();
1052  Iterator<SuggestionFragment> suggFragListIt = suggFragList.iterator();
1053  Boolean errFlag = false;
1054  // condition to check if !tmpFragList.isEmpty() is not needed
1055  while (tmpFragListIt.hasNext()) {
1056  // same annotated text
1057  SuggestionFragment tmpFrag1 = tmpFragListIt.next();
1058  SuggestionFragment tmpFrag2 = suggFragListIt.next();
1059  if (!(tmpFrag1.getAnnotatedText()).equals(tmpFrag2.getAnnotatedText())) {
1060  errFlag = true;
1061  break;
1062  }
1063  // different path and offset
1064  String path1 = tmpFrag1.getPath();
1065  String path2 = tmpFrag2.getPath();
1066  if (path1 != null && path2 != null && path1.equals(path2)) {
1067  Integer offset1 = tmpFrag1.getOffset();
1068  Integer offset2 = tmpFrag2.getOffset();
1069  if (offset1 != null && offset2 != null && offset1.equals(offset2)) {
1070  errFlag = true;
1071  break;
1072  }
1073  }
1074  }
1075  if (curOffset != null) {
1076  if (curOffset < leftSep || curOffset > rightSep) {
1077  errFlag = true; // out of borders given by separators
1078  }
1079  }
1080  if (!errFlag) {
1081  SuggestionLogEntry tmpLogEntry = new SuggestionLogEntry((actualSugg.getId()).toString());
1082  tmpLogEntry.setRefuseMethod(Constants.REFUSED_AUTOMATICALLY);
1083  addToLog.add(tmpLogEntry);
1084  }
1085  }
1086  } // if it is not same suggestion but have same type and SEC API Entity URI
1087  } // for each sended suggestion
1088  } // if suggestion have at least one fragment
1089  } // if there is URI of Entity
1090  } // for each refused suggestion
1091  } // if there are some sended suggestions
1092 
1093  suggLog.addAll(addToLog); // add additional suggestions found
1094 
1095  if(suggLog != null && !suggLog.isEmpty()){
1096  Iterator<SuggestionLogEntry> logIt = suggLog.iterator();
1097  while(logIt.hasNext()){
1098  SuggestionLogEntry actualLogItem = logIt.next();
1099  lockDocForChange(request.getSession().getSyncDocument().getId());
1100  boolean createAlternatives = true;
1101  if (noAlternatives.contains(actualLogItem)) {
1102  createAlternatives = false;
1103  }
1104  updateSuggNegativeFeedback(request, groupId, Integer.parseInt(actualLogItem.getTmpId()), createAlternatives);
1105  unlockDocForChange(request.getSession().getSyncDocument().getId());
1106  }
1107  }
1108 
1109  return changedSuggestions;
1110  } // updateNegativeFeedback()
1111 
1112  /**
1113  * Refuses other suggestions for fragments for which is some suggestion confirmed
1114  *
1115  * @param request Informations about client request
1116  * @return Returns list of refused suggestions
1117  */
1118  private ArrayList<SuggestionLogEntry> refuseOtherSugFromFragments(RequestInfo request) {
1119  ArrayList<SuggestionLogEntry> addToLog = new ArrayList<SuggestionLogEntry>();
1120  ArrayList<SuggestionLogEntry> confSugs = request.getConfirmedSuggestions();
1121 
1122  ArrayList<Suggestion> allSugg = request.getSession().getWholeSendedSuggestions();
1123  if (allSugg != null && !allSugg.isEmpty()) { // if there are some sended suggestions
1124  HashMap<Integer, ArrayList<SuggestionFragment>> sugToLinFragments = new HashMap<Integer, ArrayList<SuggestionFragment>>();
1125  SECAPISuggestionTranslator.linearizeSuggestions(sugToLinFragments, request.getSession().getParsedSyncDocument(), allSugg);
1126  ArrayList<Integer> separators = findSeparators(request.getSession().getParsedLinDocument());
1127  int docLength = request.getSession().getParsedLinDocument().length();
1128 
1129  Iterator<SuggestionLogEntry> confSugIt = confSugs.iterator();
1130  while (confSugIt.hasNext()) { // for each confirmed suggestion
1131  SuggestionLogEntry confSugLogEntry = confSugIt.next();
1132 
1133  // get confirmed suggestion's annotated text
1134  Integer confirmedSuggestionId = Integer.parseInt(confSugLogEntry.getTmpId());
1135  Suggestion confirmedSuggestion = getSuggestionFromDB(confirmedSuggestionId);
1136  ArrayList<SuggestionFragment> suggFragList = confirmedSuggestion.getFragmentsAL();
1137 
1138  if (suggFragList != null && !suggFragList.isEmpty()) { // if suggestion have at least one fragment
1139  if (suggFragList.size() >= 2) {
1140  Collections.sort(suggFragList, new SuggestionFragmentComp());
1141  }
1142 
1143  Iterator<Suggestion> allSuggIt = allSugg.iterator();
1144  while (allSuggIt.hasNext()) { // for each sended suggestion
1145  Suggestion actualSugg = allSuggIt.next();
1146 
1147  // sugg. with the same id will be skipped
1148  Integer actualSuggId = actualSugg.getId();
1149  if (actualSuggId != null && confirmedSuggestionId != null && !actualSuggId.equals(confirmedSuggestionId)) {
1150  // if it is not same suggestion
1151  ArrayList<SuggestionFragment> tmpFragList = actualSugg.getFragmentsAL();
1152  if (tmpFragList.size() >= 2) {
1153  Collections.sort(tmpFragList, new SuggestionFragmentComp());
1154  }
1155  // check whether both suggestion fragment lists have the same amount of fragments
1156  if (tmpFragList.size() == suggFragList.size()) {
1157  Iterator<SuggestionFragment> tmpFragListIt = tmpFragList.iterator();
1158  Iterator<SuggestionFragment> suggFragListIt = suggFragList.iterator();
1159  Boolean errFlag = false;
1160  // condition to check if !tmpFragList.isEmpty() is not needed
1161  while (tmpFragListIt.hasNext()) {
1162  // same annotated text
1163  SuggestionFragment tmpFrag1 = tmpFragListIt.next();
1164  SuggestionFragment tmpFrag2 = suggFragListIt.next();
1165  if (!(tmpFrag1.getAnnotatedText()).equals(tmpFrag2.getAnnotatedText())) {
1166  errFlag = true;
1167  break;
1168  }
1169  // same path
1170  String path1 = tmpFrag1.getPath();
1171  String path2 = tmpFrag2.getPath();
1172  if (path1 != null && path2 != null && !path1.equals(path2)) {
1173  errFlag = true;
1174  break;
1175  }
1176  // same offset
1177  Integer offset1 = tmpFrag1.getOffset();
1178  Integer offset2 = tmpFrag2.getOffset();
1179  if (offset1 != null && offset2 != null && !offset1.equals(offset2)) {
1180  errFlag = true;
1181  break;
1182  }
1183  }
1184  if (!errFlag) {
1185  SuggestionLogEntry tmpLogEntry = new SuggestionLogEntry((actualSugg.getId()).toString());
1186  tmpLogEntry.setRefuseMethod(Constants.REFUSED_AUTOMATICALLY);
1187  addToLog.add(tmpLogEntry);
1188  }
1189  }
1190  } // if it is not same suggestion
1191  } // for each sended suggestion
1192  } // if suggestion have at least one fragment
1193  } // for each confirmed suggestion
1194  } // if there are some sended suggestions
1195 
1196  request.getRefusedSuggestions().addAll(addToLog);
1197  return addToLog;
1198  } //refuseOtherSugFromFragments()
1199 
1200 
1201  /**
1202  * Class which implements Comparator to sort arrayList of SuggestionFragment alphabetically
1203  *
1204  * @brief Class which implements Comparator to sort arrayList of SuggestionFragment alphabetically
1205  */
1206  class SuggestionFragmentComp implements java.util.Comparator<SuggestionFragment>{
1207 
1208  /**
1209  * Compares two fragments according to offset and length
1210  *
1211  * @param frag1 First fragment
1212  * @param frag2 Second fragment
1213  * @return Returns a negative integer, zero, or a positive integer as first
1214  * fragment is less than, equal to, or greater than the second fragment.
1215  */
1216  @Override
1218  return (frag1.getAnnotatedText()).compareTo(frag2.getAnnotatedText());
1219  }
1220  }
1221 
1222  /**
1223  * Method for updating negative feedback for one suggestion
1224  *
1225  * @param request Informations about client request
1226  * @param groupId Group ID of the current user
1227  * @param refusedSuggID ID of the refused Suggestion
1228  * @param processAlternatives Flag to processing alternatives
1229  * @return Reference to the updated suggestion
1230  */
1231  public static Suggestion updateSuggNegativeFeedback(RequestInfo request, Integer groupId, int refusedSuggID, boolean processAlternatives){
1232  SuggestionFeedback feedback = getFeedbackSFromDB(refusedSuggID, groupId);
1233  if(feedback != null){
1234  feedback.setAnnot(null);
1235  feedback.setAnnotationId(null);
1236  feedback.getSuggestion().setConfidence(REFUSED_CONFIDENCE);
1237  Suggestion sug4update = feedback.getSuggestion();
1238  Iterator<SugBaseAttribute> attrIt = sug4update.getAttributes().iterator();
1239  while(attrIt.hasNext()){
1240  SugBaseAttribute attr = attrIt.next();
1241  if(attr.getNestedSuggestion() != null){
1242  Suggestion updatedSugg = updateSuggNegativeFeedback(request, groupId, attr.getNestedSuggestion().getId(), processAlternatives);
1243  attr.setNestedSuggestion(updatedSugg);
1244  }
1245  }
1246  AppBean.getPersistenceManager().saveEntityChanges(sug4update);
1247  updateFeedback(feedback);
1248  return sug4update;
1249  }else{
1250  Suggestion actualSuggestion = getSuggestionFromDB(refusedSuggID);
1251  if(actualSuggestion != null){
1252  feedback = new SuggestionFeedback();
1253  feedback.setAnnot(null);
1254  feedback.setAnnotationId(null);
1255  feedback.setGroup(request.getSession().getDefaultGroup());
1256  feedback.setGroupId(request.getSession().getDefaultGroup().getId());
1257  feedback.setSuggestion(actualSuggestion);
1258  feedback.setSuggestionId(actualSuggestion.getId());
1259  actualSuggestion.setConfidence(REFUSED_CONFIDENCE);
1260  Iterator<SugBaseAttribute> attrIt = actualSuggestion.getAttributes().iterator();
1261  while(attrIt.hasNext()){
1262  SugBaseAttribute attr = attrIt.next();
1263  if(attr.getNestedSuggestion() != null){
1264  Suggestion updatedSugg = updateSuggNegativeFeedback(request, groupId, attr.getNestedSuggestion().getId(), processAlternatives);
1265  attr.setNestedSuggestion(updatedSugg);
1266  }
1267  }
1268  AppBean.getPersistenceManager().saveEntityChanges(actualSuggestion);
1269  persistFeedback(feedback);
1270  if (processAlternatives) {
1271  AlternativeManager.activateAlternatives(request, actualSuggestion);
1272  }
1273  return actualSuggestion;
1274  }
1275  else{
1276  return null;
1277  }
1278  }
1279  }
1280 
1281  /**
1282  * Main method to update suggestion database after document change. Method
1283  * retrieves the new suggestions and compares them with existing old suggestions
1284  * and save changes and new suggestions.
1285  *
1286  * @param request informations about client request
1287  * @param oldSuggestions existing suggestions for document that are in DB
1288  * @param addedSuggestions there will be new annotations saved
1289  * @param changedSuggestions there will be changed annotations saved
1290  * @param newTypes Array for adding new types of annotations
1291  */
1292  private void updateDocument(RequestInfo request, ArrayList<Suggestion> oldSuggestions, ArrayList<Suggestion> addedSuggestions, ArrayList<Suggestion> changedSuggestions, ArrayList<AnnotType> newTypes){
1293  userGroup = requestInfo.getSession().getDefaultGroup();
1294  if (userGroup == null) {
1295  return;
1296  }
1297  String rawNewSuggestions = null;
1298  ArrayList<Suggestion> newSuggestions = null;
1299  String document = request.getSession().getParsedLinDocument();
1300  String uri = request.getSession().getSyncDocument().getUri();
1301 
1302  // select source of suggestions
1303  SuggestionSource suggestionSource = sourceOfSuggestions(document);
1304 
1305  // get suggestions as raw data
1306  if (suggestionSource == SuggestionSource.SEC_API) {
1308  rawNewSuggestions = getSuggestionsFromRemoteSECAPI(request, document, uri, false, null);
1309  } else {
1310  rawNewSuggestions = getSuggestionsFromSECAPI(request, document, uri, false, null);
1311  }
1312  }
1313  if (rawNewSuggestions == null) {
1314  return;
1315  }
1316 
1317  // lock document for suggestion change
1318  lockDocForChange(requestInfo.getSession().getSyncDocument().getId());
1319 
1320  // process suggestions
1321  try{ // thread have to unlock doc for change
1322  // convert raw data to suggestions
1323  if (suggestionSource == SuggestionSource.SEC_API) {
1325  newSuggestions = st.translateSugFromSecApi(request, rawNewSuggestions, newTypes);
1326  }
1327 
1328  if(newSuggestions != null && !newSuggestions.isEmpty()){
1329  // update fragments of suggestions
1330  updateSuggestionsFragments(oldSuggestions,request, changedSuggestions);
1331  // some suggestions may be devastated be updateSuggestionsFragments,
1332  // fragments of more suggestions may be same, only one of this suggestions should have high confidence
1333  compareFragments(oldSuggestions, changedSuggestions);
1334  // save updated suggestions
1335  SugPersister.persist(request, null, null, changedSuggestions, false, newTypes);
1336 
1337  // get suggestions from DB
1338  oldSuggestions.clear();
1339  oldSuggestions.addAll(getSuggestionsFromDB(request.getSession().getSyncDocument().getId()));
1340 
1341  // check if suggestions have right types, if don't have, convert it and hold it
1342  checkTypes(request.getSession(), oldSuggestions, newTypes, false);
1343  checkTypes(request.getSession(), changedSuggestions, newTypes, true);
1344  persistTypes(newTypes);
1345 
1346  // insert new suggestions from NER to DB
1347  insertNewSuggestions(newSuggestions,oldSuggestions,addedSuggestions,changedSuggestions);
1348 
1349  // persis new suggestions
1350  SugPersister.persist(request, null, null, addedSuggestions, false, newTypes);
1351  // save updated suggestions
1352  SugPersister.persist(request, null, null, changedSuggestions, false, newTypes);
1353 
1354  // process alternatives of suggestions
1355  ArrayList<Suggestion> validSuggestions = getSuggestionsForAlternatives(request.getSession().getSyncDocument().getId(), MINIMAL_CONFIDENCE);
1356  AlternativeManager alternativesThread = new AlternativeManager(request, document, uri, validSuggestions, this, requestInfo.getSession().getSyncDocument().getId());
1357  alternativesThread.start();
1358  }
1359  } catch(Exception ex){
1360  String msg = "Unknown exception in SuggestionManager: " + ex.getMessage();
1361  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg, ex);
1362  }
1363  // unlock document for suggestions change
1364  unlockDocForChange(requestInfo.getSession().getSyncDocument().getId());
1365  } // updateDocument()
1366 
1367  /**
1368  * Return source of suggestions.
1369  *
1370  * @param document Document.
1371  * @return Source of suggestions.
1372  */
1373  public static SuggestionSource sourceOfSuggestions(String document) {
1374  SuggestionSource suggestionSource = SuggestionSource.NONE;
1375  if (document != null && !document.isEmpty()) {
1377  suggestionSource = SuggestionSource.SEC_API;
1378  }
1379  }
1380  return suggestionSource;
1381  }
1382  /**
1383  * Method make message with suggestions from given array.
1384  *
1385  * @param suggestions list of suggestions
1386  * @return string with added suggestions
1387  */
1388  private String getAddMessagesString(ArrayList<Suggestion> suggestions){
1389  Collections.sort(suggestions, new ConfidenceComparator());
1390  StringBuilder result = new StringBuilder();
1391  if(suggestions != null && !suggestions.isEmpty()){
1392  ArrayList<String> attFilter = requestInfo.getSession().getAttFilter();
1393  Boolean KBRefMode = requestInfo.getSession().getKBRefMode();
1394  int lNum = requestInfo.getSession().getLanguageNum();
1395  Iterator<Suggestion> suggIt = suggestions.iterator();
1396  while(suggIt.hasNext()){
1397  Suggestion actualSugg = suggIt.next();
1398  if(this.requestInfo.getSession().getProtocolLOD() == Constants.PROTOCOL_LOD_V2){
1399  result.append(actualSugg.toXMLStringV2(attFilter, lNum, KBRefMode));
1400  }else{
1401  Integer id = actualSugg.getId();
1402  String params = " tmpId=\"" + ((id == null) ? "null" : id.toString()) + "\" confidence=\"" + actualSugg.getConfidence().toString() + "\"";
1403  result.append(actualSugg.toXMLString(true, params, false));
1404  }
1405  }
1406  }
1407 
1408  return result.toString();
1409  }
1410 
1411  /**
1412  * @brief The object implements comparator of Alternative objects that are
1413  * compared by confidence (from highest to lowest confidence).
1414  */
1415  public class ConfidenceComparator implements java.util.Comparator<Suggestion> {
1416 
1417  @Override
1418  public int compare(Suggestion s1, Suggestion s2) {
1419  int result = s1.getConfidence().compareTo(s2.getConfidence());
1420  if (result == 0) {
1421  return result;
1422  } else {
1423  return (result * (-1));
1424  }
1425  }
1426  } // public class ConfidenceComparator
1427 
1428  /**
1429  * Method make message with suggestions to delete from given array.
1430  *
1431  * @param suggestions list of suggestions to delete
1432  * @return string with suggestions to delete
1433  */
1434  private String getDeleteMessagesString(ArrayList<Integer> suggestions){
1435  StringBuilder result = new StringBuilder();
1436  if(suggestions != null && !suggestions.isEmpty() && requestInfo.getSession().getProtocolLOD() < Constants.PROTOCOL_LOD_V2){
1437  Iterator<Integer> suggIt = suggestions.iterator();
1438  while(suggIt.hasNext()){
1439  result.append("<delete tmpId=\"");
1440  result.append(suggIt.next().toString());
1441  result.append("\"/>");
1442  }
1443  } else if (suggestions != null && !suggestions.isEmpty()) {
1444  ArrayList<Integer> skipSug = new ArrayList<Integer>();
1445  if (requestInfo.getOrigRefusedSuggestions() != null && !requestInfo.getOrigRefusedSuggestions().isEmpty()) {
1446  Iterator<SuggestionLogEntry> sleIt = requestInfo.getOrigRefusedSuggestions().iterator();
1447  while (sleIt.hasNext()) {
1448  SuggestionLogEntry sle = sleIt.next();
1449  Integer sid;
1450  try {
1451  sid = Integer.parseInt(sle.getTmpId());
1452  } catch (NumberFormatException numberFormatException) {
1453  continue;
1454  }
1455  skipSug.add(sid);
1456  }
1457  }
1458  if (requestInfo.getConfirmedSuggestions() != null && !requestInfo.getConfirmedSuggestions().isEmpty()) {
1459  Iterator<SuggestionLogEntry> sleIt = requestInfo.getConfirmedSuggestions().iterator();
1460  while (sleIt.hasNext()) {
1461  SuggestionLogEntry sle = sleIt.next();
1462  Integer sid;
1463  try {
1464  sid = Integer.parseInt(sle.getTmpId());
1465  } catch (NumberFormatException numberFormatException) {
1466  continue;
1467  }
1468  skipSug.add(sid);
1469  }
1470  }
1471  Iterator<Integer> suggIt = suggestions.iterator();
1472  while(suggIt.hasNext()){
1473  Integer sugId = suggIt.next();
1474  if (skipSug.contains(sugId)) {
1475  continue;
1476  }
1477  result.append("<suggestion uri=\"");
1478  result.append(AppBean.getBaseUri());
1479  result.append("/sugg/");
1480  result.append(sugId.toString());
1481  result.append("\"/>");
1482  }
1483  }
1484 
1485  return result.toString();
1486  }
1487 
1488  /**
1489  * Method make from added suggestions string and added suggestion strings message
1490  * for client.
1491  *
1492  * @param suggestionToAddM string with added suggestions
1493  * @param suggestionToRemoveM string with removed suggestions
1494  */
1495  private String makeClientMessage(String suggestionToAddM,String suggestionToRemoveM){
1496  StringBuilder result = new StringBuilder();
1497  if(!suggestionToAddM.isEmpty() || !suggestionToRemoveM.isEmpty()){
1498 
1499  if(requestInfo.getSession().getProtocolLOD() == Constants.PROTOCOL_LOD_V2){
1500  result.append("<removeSuggestions>");
1501  result.append(suggestionToRemoveM);
1502  result.append("</removeSuggestions>");
1503  result.append("<addSuggestions>");
1504  result.append(suggestionToAddM);
1505  result.append("</addSuggestions>");
1506  }else{
1507  result.append("<suggestions>");
1508  result.append(suggestionToRemoveM);
1509  result.append(suggestionToAddM);
1510  result.append("</suggestions>");
1511  }
1512  } else if (requestInfo.getSession().getProtocolLOD() == Constants.PROTOCOL_LOD_V2
1513  && requestInfo.getSession().getSugRequestFlag()) {
1514  result.append("<addSuggestions/>");
1515  }
1516  return result.toString();
1517  }
1518 
1519  private void getNewClientCache(ArrayList<Suggestion> addedSugg, ArrayList<Integer> deletedSugg, ArrayList<Integer> actualCache){
1520  // starts with deleted
1521  if(deletedSugg != null && !deletedSugg.isEmpty()){
1522  Iterator<Integer> deletedIt = deletedSugg.iterator();
1523  while(deletedIt.hasNext()){
1524  Integer actualForDelete = deletedIt.next();
1525  if(actualCache.contains(actualForDelete)){
1526  actualCache.remove(actualForDelete);
1527  }
1528  }
1529  }
1530 
1531  // check adds
1532  if(addedSugg != null && !addedSugg.isEmpty()){
1533  Iterator<Suggestion> addedIt = addedSugg.iterator();
1534  while(addedIt.hasNext()){
1535  Suggestion actualForAdd = addedIt.next();
1536  if(!actualCache.contains(actualForAdd.getId())){
1537  actualCache.add(actualForAdd.getId());
1538  }
1539  }
1540  }
1541  }
1542 
1543  /**
1544  * Method filter list with suggestions which client should have and leave only
1545  * suggestions that are interested for client (new or changed). Client's session
1546  * is updated and message for client generated.
1547  *
1548  * @param session Informations about client session
1549  * @param shouldHave List with suggestions which client should have
1550  * @param changedSuggestions List with changed suggestions
1551  * @return String with messages for client
1552  */
1553  private String filterByClientCache(EditorSession session, ArrayList<Suggestion> shouldHave, ArrayList<Suggestion> changedSuggestions){
1554  ArrayList<Suggestion> sugToAdd = new ArrayList<Suggestion>();
1555  ArrayList<Integer> sugToDelete = new ArrayList<Integer>();
1556 
1557  synchronized (session) {
1558  // create clientCach list
1559  ArrayList<Integer> clientCacheID = session.getSendedSuggestions();
1560  ArrayList<Suggestion> clientCache = new ArrayList<Suggestion>();
1561  for (Iterator<Integer> it = clientCacheID.iterator(); it.hasNext();) {
1562  Integer id = it.next();
1563  clientCache.add(getSuggestionFromDB(id));
1564  }
1565 
1566  ArrayList<Suggestion> helpList = new ArrayList<Suggestion>();
1567  helpList.addAll(clientCache);
1568  for (Iterator<Suggestion> it = helpList.iterator(); it.hasNext();) {
1569  Suggestion sg = it.next();
1570  if ((!shouldHave.contains(sg)) || changedSuggestions.contains(sg)) {
1571  if (!sugToDelete.contains(sg.getId())) {
1572  sugToDelete.add(sg.getId());
1573  }
1574  clientCache.remove(sg);
1575  }
1576  }
1577 
1578  for (Iterator<Suggestion> it = shouldHave.iterator(); it.hasNext();) {
1579  Suggestion sg = it.next();
1580  if (!clientCache.contains(sg)) {
1581  clientCache.add(sg);
1582  if (!sugToAdd.contains(sg)) {
1583  sugToAdd.add(sg);
1584  }
1585  }
1586  }
1587 
1588  ArrayList<Suggestion> closed = new ArrayList<Suggestion>(sugToAdd);
1589  ArrayList<Suggestion> visited = new ArrayList<Suggestion>();
1590  while (!closed.isEmpty()) {
1591  Suggestion actualSugg = closed.get(0);
1592  visited.add(actualSugg);
1593  closed.remove(0);
1594  Iterator<Suggestion> linkedSuggIt = getAllDependencies(actualSugg).iterator();
1595  while (linkedSuggIt.hasNext()) {
1596  Suggestion actualLinkedSugg = linkedSuggIt.next();
1597  if (clientCache.contains(actualLinkedSugg)) {
1598  if (!sugToDelete.contains(actualLinkedSugg.getId())) {
1599  sugToDelete.add(actualLinkedSugg.getId());
1600  }
1601  if (!sugToAdd.contains(actualLinkedSugg)) {
1602  sugToAdd.add(actualLinkedSugg);
1603  }
1604  if (!visited.contains(actualLinkedSugg)) {
1605  closed.add(actualLinkedSugg);
1606  }
1607  }
1608  }
1609  }
1610 
1611  getNewClientCache(sugToAdd, sugToDelete, clientCacheID);
1612  session.setSendedSugg(clientCacheID);
1613 
1614  for (Iterator<Suggestion> sugIt = sugToAdd.iterator(); sugIt.hasNext();) {
1615  Suggestion suggestion = sugIt.next();
1616  if (suggestion.getNestedInAnnot() != null || suggestion.getNestedInSuggestion() != null) {
1617  sugIt.remove();
1618  }
1619  }
1620 
1621  String addMessage = getAddMessagesString(sugToAdd);
1622  String removMessage = getDeleteMessagesString(sugToDelete);
1623  String clientMessage = makeClientMessage(addMessage, removMessage);
1624  return clientMessage;
1625 
1626  } // synchronized
1627  } // filterByClientCache()
1628 
1629  /**
1630  * Method filter document suggestions by user group feedback, method builds
1631  * suggestion list without suggestions with negative references.
1632  *
1633  * @param request request from user
1634  * @param docSuggestions all document suggestions
1635  */
1636  private ArrayList<Suggestion> filtrateRefusedSugg(RequestInfo request, ArrayList<Suggestion> docSuggestions){
1637  Integer documentId = request.getSession().getSyncDocument().getId();
1638  Integer userGroupId = request.getSession().getDefaultGroup().getId();
1639  ArrayList<Suggestion> result = new ArrayList<Suggestion>();
1640 
1641  // Get negative feedback for current document and group
1642  ArrayList<SuggestionFeedback> negFeedback = getNegFeedbackFromDB(documentId,userGroupId);
1643  if(negFeedback != null && !negFeedback.isEmpty() && docSuggestions != null && !docSuggestions.isEmpty()){
1644 
1645  // Check all suggestions if is refused by group
1646  Iterator<Suggestion> docSugIt = docSuggestions.iterator();
1647  while(docSugIt.hasNext()){
1648  Suggestion actualSuggestion = docSugIt.next();
1649  Iterator<SuggestionFeedback> negFeedbackIt = negFeedback.iterator();
1650  while(negFeedbackIt.hasNext()){
1651  // If suggestion is in negative feedback list
1652  if(actualSuggestion.getId().equals(negFeedbackIt.next().getSuggestionId())){
1653  // Add suggestion to result list
1654  result.add(actualSuggestion);
1655  // Delete it from suggestions for user
1656  docSugIt.remove();
1657  }
1658  }
1659  }
1660  }
1661 
1662  return result;
1663  } // filtrateRefusedSugg()
1664 
1665  /**
1666  * Return suggestion from list by id. Return null if not found.
1667  *
1668  * @param suggestionId Id of suggestion
1669  * @param list List of suggestion
1670  * @return Founded suggestion
1671  */
1672  public static Suggestion getSuggestionFromList(Integer suggestionId, List<Suggestion> list) {
1673  if (suggestionId == null || list == null) {
1674  return null;
1675  }
1676  for (Iterator<Suggestion> it = list.iterator(); it.hasNext();) {
1677  Suggestion sg = it.next();
1678  if (sg.getId() == null) {
1679  continue;
1680  }
1681  if (sg.getId().equals(suggestionId)) {
1682  return sg;
1683  }
1684  }
1685  return null;
1686  }
1687 
1688  /**
1689  * Removes suggestions with feedback from the list and replaces all references
1690  * to them by annotations from feedback (for negative feedback by null).
1691  *
1692  * @param list List of suggestions
1693  * @param modified List to which modified suggestions will be added
1694  * @return Removed suggestions from list.
1695  */
1696  private ArrayList<Suggestion> getSuggestionWithoutFeedback(ArrayList<Suggestion> list, ArrayList<Suggestion> modified) {
1697  ArrayList<Suggestion> removedSuggestions = new ArrayList<Suggestion>();
1698  UserGroup defGroup = requestInfo.getSession().getDefaultGroup();
1699  Integer defaultUserGroupID = null;
1700  if (defGroup != null) {
1701  defaultUserGroupID = defGroup.getId();
1702  } else {
1703  if (this.userGroup != null) {
1704  defaultUserGroupID = this.userGroup.getId();
1705  } else {
1706  // if it is not possible to get feedback, it is better to remove all
1707  removedSuggestions.addAll(list);
1708  list.removeAll(list);
1709  return removedSuggestions;
1710  }
1711  }
1712 
1713  List<SuggestionFeedback> feedList = getFeedbackFromDB(requestInfo.getSession().getSyncDocument().getId(), defaultUserGroupID);
1714  ArrayList<SuggestionFeedback> feedListOtherGroups = new ArrayList<SuggestionFeedback>();
1715 
1716  if (requestInfo.getSession().getUser() != null) {
1717  Iterator<UserGroup> allUserGroups = requestInfo.getSession().getUser().getGroupsAL().iterator();
1718  while(allUserGroups.hasNext()){
1719  UserGroup group = allUserGroups.next();
1720  if(group.getId() != defaultUserGroupID){
1721  List<SuggestionFeedback> feed = getFeedbackFromDB(requestInfo.getSession().getSyncDocument().getId(), group.getId());
1722  feedListOtherGroups.addAll(feed);
1723  }
1724  }
1725  }
1726 
1727  // delete suggestions with positiveFeedback in default group
1728  for (Iterator<SuggestionFeedback> it = feedList.iterator(); it.hasNext();) {
1729  SuggestionFeedback fb = it.next();
1730  if (fb.getSuggestion() == null) {
1731  continue;
1732  }
1733  Suggestion sgFromList = getSuggestionFromList(fb.getSuggestion().getId(), list);
1734  if (sgFromList != null) { // suggestion was found
1735  feedbackChangeRef(list, sgFromList, modified, fb, removedSuggestions);
1736  }
1737  }
1738 
1739  // delete suggestions with positiveFeedback in other group
1740  for (Iterator<SuggestionFeedback> it = feedListOtherGroups.iterator(); it.hasNext();) {
1741  SuggestionFeedback fb = it.next();
1742  if (fb.getSuggestion() == null) {
1743  continue;
1744  }
1745  Suggestion sgFromList = getSuggestionFromList(fb.getSuggestion().getId(), list);
1746  if (sgFromList != null) { // suggestion was found
1747  feedbackChangeRef(list, sgFromList, modified, fb, removedSuggestions);
1748  }
1749  }
1750 
1751  return removedSuggestions;
1752  } // getSuggestionWithoutFeedback()
1753 
1754  // iterate all other suggestion and change references
1755 
1756  /**
1757  * Adds links in suggestion to modified suggs
1758  *
1759  * @param list List of suggestions
1760  * @param sgFromList Suggestion to check for links
1761  * @param modified List to which modified suggestions will be added
1762  * @param fb feedback for this suggestion
1763  * @param removedSuggestions Removed suggestions from list.
1764  */
1765  private void feedbackChangeRef(ArrayList<Suggestion> list,
1766  Suggestion sgFromList, ArrayList<Suggestion> modified, SuggestionFeedback fb,
1767  ArrayList<Suggestion> removedSuggestions)
1768  {
1769  for (Iterator<Suggestion> itList = list.iterator(); itList.hasNext(); ) {
1770  Suggestion sg = itList.next();
1771  List atrs = sg.getAttributes();
1772  // iterate in all atributes
1773  for (Iterator it2 = atrs.iterator(); it2.hasNext();) {
1774  Object obj = (Object) it2.next();
1775  Object value = null;
1776  if (obj instanceof SugLinkedAttribute) {
1777  value = ((SugLinkedAttribute) obj).getValue();
1778  }
1779  if (obj instanceof SugNestedAttribute) {
1780  value = ((SugNestedAttribute) obj).getValue();
1781  }
1782  if (value instanceof Suggestion) {
1783  if (((Suggestion) value).equals(sgFromList)) {
1784  if (obj instanceof SugLinkedAttribute) {
1785  ((SugLinkedAttribute) obj).setValue(fb.getAnnot());
1786  if (modified != null && !modified.contains(sg)) {
1787  modified.add(sg);
1788  }
1789  }
1790  if (obj instanceof SugNestedAttribute) {
1791  ((SugNestedAttribute) obj).setValue(fb.getAnnot());
1792  if (modified != null && !modified.contains(sg)) {
1793  modified.add(sg);
1794  }
1795  }
1796  }
1797  }
1798  }
1799  }
1800  list.remove(sgFromList);
1801  removedSuggestions.add(sgFromList);
1802  }
1803 
1804  /**
1805  * Finds suggestion in feedback
1806  *
1807  * @param feedbackList List with feedback
1808  * @param searchedSugg Searched suggestion
1809  * @return If suggestion is in feedback, returns true, false otherwise.
1810  */
1811  private boolean isSuggestionInFeedback(ArrayList<SuggestionFeedback> feedbackList, Suggestion searchedSugg){
1812  if(feedbackList != null){
1813  Iterator<SuggestionFeedback> feedbackgIterator = feedbackList.iterator();
1814  while(feedbackgIterator.hasNext()){
1815  SuggestionFeedback actualFeedback = feedbackgIterator.next();
1816  if(actualFeedback.getAnnot() != null && actualFeedback.getSuggestionId().equals(searchedSugg.getId())){
1817  return true;
1818  }
1819  }
1820  }
1821 
1822  return false;
1823  }
1824 
1825  /**
1826  * Method searches for those suggestions from the input array that are nested
1827  * in ones included in the second array.
1828  *
1829  * @param inputSuggs All current suggestions
1830  * @param suggsToDelete Suggestions that are going removed
1831  * @return Suggestions that are nested in removed suggestions
1832  */
1833  public static ArrayList<Suggestion> getNestedSuggFromToDelete(ArrayList<Suggestion> inputSuggs, ArrayList<Suggestion> suggsToDelete) {
1834  ArrayList<Suggestion> toRet = new ArrayList<Suggestion>();
1835  if (!inputSuggs.isEmpty()) {
1836  Iterator<Suggestion> inputSuggsIt = inputSuggs.iterator();
1837  // for every suggestion
1838  while (inputSuggsIt.hasNext()) {
1839  Suggestion inputSug = inputSuggsIt.next();
1840  // if the suggestion is nested in another one
1841  if (inputSug.getNestedInSuggestion() != null) {
1842  // get the identificator of the parent suggestion
1843  Integer nestedIn = null;
1844  if (inputSug.getNestedInSuggestion().getId() != null) {
1845  nestedIn = inputSug.getNestedInSuggestion().getId();
1846  }
1847  Iterator<Suggestion> suggsToDeleteIt = suggsToDelete.iterator();
1848  // for every suggestion that's been marked for removal
1849  while (suggsToDeleteIt.hasNext()) {
1850  Suggestion suggToDelete = suggsToDeleteIt.next();
1851  // ID match
1852  if (suggToDelete.getId() != null && nestedIn != null && suggToDelete.getId() == nestedIn) {
1853  // insert nested suggestion to the array for return
1854  toRet.add(inputSug);
1855  // remove the suggestion from the input array
1856  inputSuggsIt.remove();
1857  break;
1858  }
1859  }
1860  }
1861  }
1862  }
1863  return toRet;
1864  } // getNestedSuggFromToDelete()
1865 
1866  /**
1867  * Method sets the rejected references to null and return changed suggestions.
1868  *
1869  * @param userSuggestions list of filtered suggestions
1870  * @param refusedSuggestions list of refused suggestions by users
1871  * @return changed suggestions
1872  */
1873  private ArrayList<Suggestion> cutRefusedSuggLinks(ArrayList<Suggestion> userSuggestions, ArrayList<Suggestion> refusedSuggestions){
1874  ArrayList<Suggestion> changedSuggestions = new ArrayList<Suggestion>();
1875  if(userSuggestions != null && !userSuggestions.isEmpty() && refusedSuggestions != null && !refusedSuggestions.isEmpty()){
1876  Iterator<Suggestion> userSuggIt = userSuggestions.iterator();
1877  while(userSuggIt.hasNext()){
1878  Suggestion actualSugg = userSuggIt.next();
1879  List attrList = actualSugg.getAttributes();
1880  Iterator attrListIt = attrList.iterator();
1881  // Go trough all attributes of suggestion
1882  while(attrListIt.hasNext()){
1883  Object actualObject = (Object) attrListIt.next();
1884  // Search for suggestion link
1885  if(actualObject instanceof SugLinkedAttribute){
1886  SugLinkedAttribute actualLink = (SugLinkedAttribute)actualObject;
1887  if(actualLink.getValue() != null && actualLink.getValue() instanceof Suggestion){
1888  Iterator<Suggestion> refSugIterator = refusedSuggestions.iterator();
1889  while(refSugIterator.hasNext()){
1890  // Check if linked suggestion parameter points to refused suggestion
1891  if(((Suggestion)actualLink.getValue()).getId().equals(refSugIterator.next().getId())){
1892  // Then set link to null (cut off refused suggestion)
1893  actualLink.setValue(null);
1894  if(!changedSuggestions.contains(actualSugg)){
1895  changedSuggestions.add(actualSugg);
1896  }
1897  }
1898  } // while(refSugIterator.hasNext())
1899  } // ... instanceof Suggestion){
1900  } // if(actualObject instanceof SugLinkedAttribute
1901  else if(actualObject instanceof SugNestedAttribute){
1902  SugNestedAttribute actualLink = (SugNestedAttribute)actualObject;
1903  if(actualLink.getValue() != null && actualLink.getValue() instanceof Suggestion){
1904  Iterator<Suggestion> refSugIterator = refusedSuggestions.iterator();
1905  while(refSugIterator.hasNext()){
1906  // Check if nested suggestion parameter points to refused suggestion
1907  if(((Suggestion)actualLink.getValue()).getId().equals(refSugIterator.next().getId())){
1908  // Then set link to null (cut off refused suggestion)
1909  actualLink.setValue(null);
1910  if(!changedSuggestions.contains(actualSugg)){
1911  changedSuggestions.add(actualSugg);
1912  }
1913  }
1914  } // while(refSugIterator.hasNext())
1915  } // ... instanceof Suggestion){
1916  } // if(actualObject instanceof SugNestedAttribute
1917  } // while(attrListIt.hasNext())
1918  } // while(userSuggIt.hasNext())
1919  } // if(userSuggestions != null && ...
1920  return changedSuggestions;
1921  } // cutRefusedSuggLinks()
1922 
1923  /**
1924  * Method filter list of suggestions by attributes in request.
1925  *
1926  * @param requestInfo Informations about client request
1927  * @param session session where are stored attributes specified by user
1928  * @param userSuggestions suggestions that will be filtered
1929  */
1930  public static void filtrateSuggestions(RequestInfo requestInfo, EditorSession session, ArrayList<Suggestion> userSuggestions){
1931  if(requestInfo != null && requestInfo.getSession().getMinConfidence() != null && requestInfo.getSession().getMinConfidence() != 0)
1932  filtrateByConfidence(requestInfo.getSession().getMinConfidence(),userSuggestions);
1933  else
1935  filtrateByType(session,userSuggestions);
1936  filtrateByFragments(session,userSuggestions);
1937  }
1938 
1939  /**
1940  * Method filter list of suggestions by confidence.
1941  *
1942  * @param minimalConfidence suggestions lower than this confidence will be removed from list
1943  * @param userSuggestions suggestions that will be filtered
1944  */
1945  private static void filtrateByConfidence(Integer minimalConfidence, ArrayList<Suggestion> userSuggestions){
1946  if(userSuggestions != null && !userSuggestions.isEmpty()){
1947  Iterator<Suggestion> suggIt = userSuggestions.iterator();
1948  while(suggIt.hasNext()){
1949  Suggestion actualSuggeston = suggIt.next();
1950  if(actualSuggeston.getConfidence().compareTo(minimalConfidence) < 0){
1951  suggIt.remove();
1952  }
1953  }
1954  }
1955  }
1956 
1957  /**
1958  * Method go through filtered suggestions list and searches dependencies (
1959  * linked and nested suggestions and parents) that are in non filtered
1960  * suggestion list and add them to filtered suggestion list.
1961  *
1962  * @param filteredSuggestions Filtered suggestion list
1963  * @param nonFilteredSuggestion Non-filtered suggestions list
1964  * @return Returns resulting list with suggestions
1965  */
1966  public static ArrayList<Suggestion> addAllDependencies(ArrayList<Suggestion> filteredSuggestions, ArrayList<Suggestion> nonFilteredSuggestion) {
1967  ArrayList<Suggestion> open = new ArrayList<Suggestion>(nonFilteredSuggestion);
1968  ArrayList<Suggestion> closed = new ArrayList<Suggestion>(filteredSuggestions);
1969  ArrayList<Suggestion> result = new ArrayList<Suggestion>(filteredSuggestions);
1970  open.removeAll(result); // can't add to result something, that has been there already
1971 
1972  while(!closed.isEmpty()) {
1973  Suggestion actualSugg = closed.get(0);
1974  closed.remove(0);
1975 
1976  Iterator<Suggestion> linkedSuggIt = getAllDependencies(actualSugg).iterator();
1977  while(linkedSuggIt.hasNext()){
1978  Suggestion actualLinkedSugg = linkedSuggIt.next();
1979  if(open.contains(actualLinkedSugg)){
1980  open.remove(actualLinkedSugg);
1981  closed.add(actualLinkedSugg);
1982  result.add(actualLinkedSugg);
1983  }
1984  }
1985  }
1986 
1987  return result;
1988  } // addAllDependencies()
1989 
1990  /**
1991  * Method searches in pair of suggestions and annots for pair that is specified
1992  * by annotation.
1993  *
1994  * @param pairs list where will be pair searched
1995  * @param annot annotation that specify pair
1996  */
1997  private AnnotSugPair getPairByAnnot(ArrayList<AnnotSugPair> pairs, Annotation annot){
1998  if(!pairs.isEmpty()){
1999  Iterator<AnnotSugPair> pairsIt = pairs.iterator();
2000  while(pairsIt.hasNext()){
2001  AnnotSugPair actualPair = pairsIt.next();
2002  if(actualPair.getAnnotation().getId().equals(annot.getId())){
2003  return actualPair;
2004  }
2005  }
2006  }
2007 
2008  return null;
2009  }
2010 
2011  /**
2012  * Method changes group id in annotation attribute uri.
2013  *
2014  * @param uri old annotation type uri
2015  * @param groupId new group id
2016  */
2017  public static String changeGroupInUri(String uri, Integer groupId){
2018  if (uri == null) {
2019  return null;
2020  }
2021  String namesStr = uri.replace(AppBean.getBaseTypeUri(), "");
2022  int index = namesStr.indexOf('/');
2023  String withoutGroup = namesStr.substring(index);
2024  String result = AppBean.getBaseTypeUri() + "g" + groupId.toString() + withoutGroup;
2025  return result;
2026  }
2027 
2028  /**
2029  * Get annotType from list with specific URI.
2030  *
2031  * @param list List of annotType
2032  * @param uri URI of AnnotType
2033  * @return If found - type, else null.
2034  */
2035  private static AnnotType getTypeWithSameURI(List<AnnotType> list, String uri) {
2036  if (list != null && !list.isEmpty()) {
2037  Iterator<AnnotType> newTypesIt = list.iterator();
2038  while (newTypesIt.hasNext()) {
2039  AnnotType newType = newTypesIt.next();
2040  // if the comparison of URIs is equal, set new type
2041  if (newType.getUri().equals(uri)) {
2042  return newType;
2043  }
2044  }
2045  }
2046  return null;
2047  }
2048  /**
2049  * Method check types of given suggestions, if finds unknown type create it, if
2050  * finds known type change it and if type is ok (for current user group) leave
2051  * type alone.
2052  *
2053  * @param session session of user
2054  * @param suggestions list of suggestions which types will be checked
2055  * @param newTypes list of types, that was/will be created by this function
2056  * @param solveAtribute False - this function don't clone attribute type (although it is necessary)
2057  */
2058  public static void checkTypes(EditorSession session, ArrayList<Suggestion> suggestions, ArrayList<AnnotType> newTypes, boolean solveAtribute){
2059  boolean someTypesWasCloned = false;
2060  if(suggestions != null && !suggestions.isEmpty()){
2061  Iterator<Suggestion> suggIt = suggestions.iterator();
2062 
2063  // go trough all suggestions
2064  while(suggIt.hasNext()){
2065  Suggestion actualSuggestion = suggIt.next();
2066  AnnotType actualType = actualSuggestion.getAnnotType();
2067  String changedUri = changeGroupInUri(actualType.getUri(),session.getDefaultGroup().getId());
2068 
2069  // search also in the newTypes array
2070  AnnotType typeFromList = getTypeWithSameURI(newTypes, changedUri);
2071  if (typeFromList != null) {
2072  actualSuggestion.setAnnotType(typeFromList);
2073  } else { // type not found in the newTypes, will be created
2074  AnnotType typeFromDB = getAnnotTypeFromDB(changedUri);
2075  if(typeFromDB == null){
2076  // user's default group don't have this annotation type
2077  // make new annot type from suggestion annotation type
2078  AnnotType newType = cloneTypesTree(actualType, session.getDefaultGroup(), newTypes);
2079  actualSuggestion.setAnnotType(newType);
2080  someTypesWasCloned = true;
2081  } else {
2082  // user default group have this annotation type
2083  actualSuggestion.setAnnotType(typeFromDB);
2084  }
2085  }
2086  }
2087  }
2088  // clone and set annotType in cloned types
2089  if (solveAtribute && someTypesWasCloned) {
2090  int newTypesCount;
2091  List<AnnotType> wasProcessed = new ArrayList<AnnotType>();
2092  // clone types in attribute in cloned types, while any new attribute is added
2093  do { // do {} while (newTypesCount != newTypes.size());
2094  newTypesCount = newTypes.size();
2095  ArrayList<AnnotType> currentProcessedTypes = new ArrayList<AnnotType>(newTypes);
2096  for (Iterator<AnnotType> itType = currentProcessedTypes.iterator(); itType.hasNext();) {
2097  AnnotType type = itType.next();
2098  if (getTypeWithSameURI(wasProcessed, type.getUri()) != null) {
2099  continue;
2100  }
2101  for (Iterator<AnnotTypeAttr> itAttr = type.getAttributes().iterator(); itAttr.hasNext();) {
2102  AnnotTypeAttr atr = itAttr.next();
2103  AnnotType atrType = atr.getAttributeType();
2104  if (atrType != null) {
2105  String changedUri = changeGroupInUri(atrType.getUri(),session.getDefaultGroup().getId());
2106  // test, if this type has already been cloned
2107  if (getTypeWithSameURI(newTypes, changedUri) == null) {
2108  // test, if this type has already been in DB
2109  AnnotType typeFromDB = getAnnotTypeFromDB(changedUri);
2110  if(typeFromDB == null){
2111  cloneTypesTree(atrType, session.getDefaultGroup(), newTypes);
2112  }
2113  }
2114  }
2115  }
2116  wasProcessed.add(type);
2117  }
2118  } while (newTypesCount != newTypes.size());
2119  // fix atribute type (atribute type has to be in user default group
2120  for (Iterator<AnnotType> itType = newTypes.iterator(); itType.hasNext();) {
2121  AnnotType type = itType.next();
2122  for (Iterator<AnnotTypeAttr> itAttr = type.getAttributes().iterator(); itAttr.hasNext();) {
2123  AnnotTypeAttr atr = itAttr.next();
2124  AnnotType atrType = atr.getAttributeType();
2125  if (atrType != null) {
2126  String changedUri = changeGroupInUri(atrType.getUri(),session.getDefaultGroup().getId());
2127  // test, if this type has already been cloned
2128  AnnotType clonedType = getTypeWithSameURI(newTypes, changedUri);
2129  if (clonedType == null) {
2130  // test, if this type has already been in DB
2131  AnnotType typeFromDB = getAnnotTypeFromDB(changedUri);
2132  if(typeFromDB != null){
2133  atr.setAttributeType(typeFromDB);
2134  } else {
2136  String msg = "Cloning of type " + changedUri + " was unsuccessful.";
2137  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
2138  }
2139  }
2140  } else {
2141  atr.setAttributeType(clonedType);
2142  }
2143  }
2144  }
2145  }
2146  }
2147  } // checkTypes()
2148 
2149  /************************************************************
2150  * UTILITY METHODS
2151  ************************************************************/
2152 
2153  /**
2154  * Method searches suggestions that will be affectedy by removing annotations.
2155  *
2156  * @param removedAnnot list of removed annotations
2157  * @return list of changed suggestions
2158  */
2159  private ArrayList<Suggestion> getAffectedForDelete(ArrayList<Annotation> removedAnnot){
2160  ArrayList<Suggestion> changedSuggestions = new ArrayList<Suggestion>();
2161  if(removedAnnot != null && !removedAnnot.isEmpty()){ // if there are removed annotations
2162  Iterator<Annotation> annotIt = removedAnnot.iterator();
2163  while(annotIt.hasNext()){ // for each removed annotation
2164  Annotation currentAnnot = annotIt.next();
2165  SuggestionFeedback foundedFeedback = getFeedbackByAnnot(currentAnnot.getId());
2166  if(foundedFeedback != null){
2167 
2168  ArrayList<SugLinkedAttribute> attrList = getLinkedSugAttrsByLink(foundedFeedback.getSuggestionId());
2169  Iterator<SugLinkedAttribute> attrIt = attrList.iterator();
2170  while(attrIt.hasNext()){
2171  SugLinkedAttribute actualAttr = attrIt.next();
2172  changedSuggestions.add(((SugBaseAttribute)actualAttr).getRefSuggestion());
2173  }
2174 
2175  ArrayList<SugNestedAttribute> nAttrsList = getNestedSugAttrsByNested(foundedFeedback.getSuggestionId());
2176  Iterator<SugNestedAttribute> nAttrIt = nAttrsList.iterator();
2177  while(nAttrIt.hasNext()){
2178  SugNestedAttribute actualAttr = nAttrIt.next();
2179  changedSuggestions.add(((SugBaseAttribute)actualAttr).getRefSuggestion());
2180  }
2181 
2182  foundedFeedback.setAnnot(null);
2183  updateFeedback(foundedFeedback);
2184  } else {
2186  String msg = "Annotation without feedback found.";
2187  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
2188  }
2189  }
2190  } // for each removed annotation
2191  } // if there are removed annotation
2192  return changedSuggestions;
2193  }
2194 
2195  /**
2196  * Set low confidence to suggestions with same fragments.
2197  * Some suggestions may be devastated be updateSuggestionsFragments,
2198  * fragments of more suggestions may be same, only one of this suggestions
2199  * should have high confidence.
2200  *
2201  * @param suggestions List of suggestions
2202  * @param changedSuggestions List of changed suggestions
2203  */
2204  private void compareFragments(ArrayList<Suggestion> suggestions, ArrayList<Suggestion> changedSuggestions) {
2205  ArrayList<Suggestion> processedSuggestions = new ArrayList<Suggestion>();
2206  for (Iterator<Suggestion> it = suggestions.iterator(); it.hasNext();) {
2207  Suggestion sg = it.next();
2208  // skip suggestion, that has been already processed
2209  if (processedSuggestions.contains(sg)) {
2210  continue;
2211  }
2212  // skip suggestion, that is nested in another suggestion
2213  if (sg.getNestedIn() != null) {
2214  continue;
2215  }
2216  // find same suggestions
2217  ArrayList<Suggestion> sameSuggestion = findSuggestions(suggestions, sg);
2218  if (sameSuggestion.size() <= 1) {
2219  continue;
2220  }
2221  // more suggestions are same, only one can have
2222  boolean oneCorrect = false;
2223  for (Iterator<Suggestion> itSame = sameSuggestion.iterator(); itSame.hasNext();) {
2224  Suggestion someSuggestion = itSame.next();
2225  processedSuggestions.add(someSuggestion);
2226  if (!oneCorrect && someSuggestion.getConfidence().compareTo(MINIMAL_FILTER_CONFIDENCE) >= 0) {
2227  oneCorrect = true;
2228  } else {
2229  setConfidenceToAllNested(someSuggestion, NOT_USABLE_CONFIDENCE, changedSuggestions);
2230  }
2231  }
2232  }
2233  }
2234 
2235  /**
2236  * Set confidence to suggestion and to its all nested suggestions.
2237  *
2238  * @param sg Suggestion
2239  * @param confidence Confidence
2240  * @param changedSuggestions List of changed suggestions
2241  */
2242  private void setConfidenceToAllNested(Suggestion sg, Integer confidence, ArrayList<Suggestion> changedSuggestions) {
2243  sg.setConfidence(confidence);
2244  changedSuggestions.add(sg);
2245  List atrList = sg.getAttributes();
2246  if (atrList == null) {
2247  return;
2248  }
2249  for (Iterator itAtr = atrList.iterator(); itAtr.hasNext();) {
2250  Object obj = itAtr.next();
2251  if (!(obj instanceof SugNestedAttribute)) {
2252  continue;
2253  }
2254  SugNestedAttribute atr = (SugNestedAttribute) obj;
2255  if (atr.getNestedSuggestion() != null) {
2256  setConfidenceToAllNested(atr.getNestedSuggestion(), confidence, changedSuggestions);
2257  }
2258  }
2259  }
2260 
2261  /**
2262  * Method goes through all suggestions and their fragments and try to update
2263  * them. If some suggestion have bad fragment sets that suggestions minimal
2264  * confidence.
2265  *
2266  * @param suggestions old suggestions to update
2267  * @param request informations about client request
2268  * @param changedSugg Array for changed suggestions
2269  */
2270  private ArrayList<Suggestion> updateSuggestionsFragments(ArrayList<Suggestion> suggestions, RequestInfo request, ArrayList<Suggestion> changedSugg){
2271  if(suggestions != null && !suggestions.isEmpty()){
2272 
2273  // go trough all suggestions
2274  Iterator<Suggestion> suggIt = suggestions.iterator();
2275  while(suggIt.hasNext()){
2276 
2277  Suggestion actualSuggestion = suggIt.next();
2278  // if suggestion have any fragment
2279  if(actualSuggestion.getFragments() != null){
2280  // indicate if any suggestion fragment was changed
2281  boolean isChanged;
2282  // update suggestion fragments
2283  isChanged = updateSuggestion(actualSuggestion,request);
2284  // check updated suggestion fragment if there is some bad fragment
2285  Iterator<SuggestionFragment> fragIt = actualSuggestion.getFragments().iterator();
2286  while(fragIt.hasNext()){
2287  SuggestionFragment actualFragment = fragIt.next();
2288  // if some fragment is bad, set suggestion minimal confidence
2289  if(!actualFragment.getIsGood()){
2290  actualSuggestion.setConfidence(NOT_USABLE_CONFIDENCE);
2291  }
2292  }
2293 
2294  if(isChanged){
2295  changedSugg.add(actualSuggestion);
2296  }
2297  }
2298  }
2299  }
2300 
2301  return changedSugg;
2302  } // updateSuggestionsFragments()
2303 
2304  /**
2305  * Method adds a new suggestions to the old suggestions. Method uses these
2306  * rules:
2307  * - If the new suggestion is found in the old suggestions then is increased
2308  * its confidence
2309  * - If the new suggestion isn't found in the old suggestions then is added
2310  * to old suggestions
2311  * - If there is suggestion in old suggestion that isn't in new suggestion
2312  * then is decreased its confidence
2313  *
2314  * @param newSuggestions new suggestions from ner
2315  * @param oldSuggestions existing suggestions for document that are in DB
2316  * @param addedSugg there will be new annotations saved
2317  * @param changedSugg there will be changed annotations saved
2318  */
2319  private void insertNewSuggestions(ArrayList<Suggestion> newSuggestions, ArrayList<Suggestion> oldSuggestions, ArrayList<Suggestion> addedSugg, ArrayList<Suggestion> changedSugg){
2320  if(newSuggestions != null && !newSuggestions.isEmpty() && oldSuggestions != null){
2321 
2322  if(!oldSuggestions.isEmpty()){
2323  // is important to find corresponding suggestions
2324  Iterator<Suggestion> newSugIt = newSuggestions.iterator();
2325  while(newSugIt.hasNext()){
2326  Suggestion actualNewSuggestion = newSugIt.next();
2327  // try to find current new suggestion in old suggestions (by comparing contents)
2328  Suggestion findedSugg = findSuggestion(oldSuggestions,actualNewSuggestion);
2329  // test if corresponding suggestion is founded
2330  if(findedSugg != null){
2331  // suggestion survived update
2332  Suggestion finded = findSuggInArray(findedSugg.getId(),changedSugg);
2333  if(finded != null){
2334  if (!finded.contentEquals(actualNewSuggestion, false, true)) {
2335  finded.setConfidence(NOT_USABLE_CONFIDENCE);
2336  actualNewSuggestion.setConfidence(INITIAL_CONFIDENCE);
2337  addedSugg.add(actualNewSuggestion);
2338  }
2339  }else{
2340  //findedSugg.setConfidence(MINIMAL_CONFIDENCE);
2341  //changedSugg.add(findedSugg);
2342  }
2343  }else{
2344  // suggestion is new
2345  actualNewSuggestion.setConfidence(INITIAL_CONFIDENCE);
2346  addedSugg.add(actualNewSuggestion);
2347  }
2348  }
2349 
2350  // try to find suggestions that aren't in new suggestions but they are in old, they are abandoned
2351  //
2352  // Idea of this code is good but effect is wrong as NER is not able to find all usable
2353  // suggestions and we can not determine the source of suggestion. So it is better to comment
2354  // it out now.
2355  /*Iterator<Suggestion> oldSugIt = oldSuggestions.iterator();
2356  while(oldSugIt.hasNext()){
2357  Suggestion actualOldSugg = oldSugIt.next();
2358  if(findSuggestion(newSuggestions,actualOldSugg) == null && findSuggestion(changedSugg,actualOldSugg) == null){
2359  // suggestion is abandoned
2360  actualOldSugg.setConfidence(MINIMAL_CONFIDENCE);
2361  changedSugg.add(actualOldSugg);
2362  }
2363  }*/
2364 
2365  }else{
2366  // nothing to compare, newSuggestions will be inserted to oldSuggestions
2367  Iterator<Suggestion> newSugIt = newSuggestions.iterator();
2368  while(newSugIt.hasNext()){
2369  Suggestion sug = newSugIt.next();
2370  if (sug != null && sug.getConfidence() == null) {
2371  sug.setConfidence(INITIAL_CONFIDENCE);
2372  }
2373  }
2374  addedSugg.addAll(newSuggestions);
2375  }
2376  }
2377  } // insertNewSuggestions()
2378 
2379  /**
2380  * Method finds suggestion by id in suggestions array.
2381  *
2382  * @param id id of searched suggestion
2383  * @param list Array to search in
2384  */
2385  private Suggestion findSuggInArray(Integer id, ArrayList<Suggestion> list){
2386  if(list != null && !list.isEmpty()){
2387  Iterator<Suggestion> listIt = list.iterator();
2388  while(listIt.hasNext()){
2389  Suggestion actualSuggestion = listIt.next();
2390  if(actualSuggestion.getId() != null && actualSuggestion.getId().equals(id)){
2391  return actualSuggestion;
2392  }
2393  }
2394  }
2395  return null;
2396  }
2397 
2398  /**
2399  * Updates fragments in suggestion. (Method copied from CoreFuncMOdule)
2400  *
2401  * @param suggestion Suggestion to update
2402  * @param request Informations about client request
2403  * @return If suggestion was updated, returns true, if no update needed or
2404  * error occurred, returns false
2405  */
2406  public static boolean updateSuggestion(Suggestion suggestion, RequestInfo request) {
2407 
2408  // Provider of matchers for finding fragments (exact matches only)
2409  MatcherProvider exactMatcherProvider;
2410  // Provider of matchers for finding fragments (nearest matches only)
2411  MatcherProvider nearestMatcherProvider;
2412  // Provider of matchers for finding fragments (sequence iterator)
2413  MatcherProvider sequenceMatcherProvider;
2414 
2415  exactMatcherProvider = new MatcherProvider();
2416  nearestMatcherProvider = new MatcherProvider();
2417  sequenceMatcherProvider = new MatcherProvider();
2418 
2419  // create nearest matcher
2420  nearestMatcherProvider.add(new Matcher(new BidirectionallyUnNestNodeIterator(), new Comparator(new ExactMethod(), Comparator.TraversingMethod.CHARACTER_BIDIRECTIONALLY)), 0);
2421  nearestMatcherProvider.add(new Matcher(new BidirectionallyUnNestNodeIterator(), new Comparator(new LevenshteinMethod(0.8), Comparator.TraversingMethod.WORD)), 1);
2422  nearestMatcherProvider.add(new Matcher(new BidirectionallyUnNestNodeIterator(), new Comparator(new LevenshteinMethod(0.8), Comparator.TraversingMethod.FIRST_AND_LAST_WORD_THEN_LETTER, 2.0, 2.0)), 2);
2423 
2424  // create sequence mathcer
2425  sequenceMatcherProvider.add(new Matcher(new SequenceNodeIterator(), new Comparator(new ExactMethod(), Comparator.TraversingMethod.CHARACTER_BIDIRECTIONALLY)), 0);
2426  sequenceMatcherProvider.add(new Matcher(new SequenceNodeIterator(), new Comparator(new LevenshteinMethod(0.8), Comparator.TraversingMethod.FIRST_AND_LAST_WORD_THEN_LETTER, 2.0, 2.0)), 1);
2427  sequenceMatcherProvider.add(new Matcher(new SequenceNodeIterator(), new Comparator(new LevenshteinMethod(0.5), Comparator.TraversingMethod.WORD)), 2);
2428 
2429  // create exact matcher
2430  exactMatcherProvider.add(new Matcher(new XPathNodeIterator(), new Comparator(new ExactMethod(), Comparator.TraversingMethod.STATIC)), 0);
2431 
2432  if (suggestion.getFragments().size() < 1) {
2433  // if annotation haven't fragments, it can't be updated
2434  return false;
2435  }
2436 
2437  // get synchronized document
2438  Document parsedDoc = request.getSession().getParsedSyncDocument();
2439  if (parsedDoc == null) {
2440  //make message about error and throw it
2441  //"Bad document for update of the suggestion."
2442  return false; // updating is not possible
2443  }
2444 
2445  int badFragCnt = 0; // total count of bad fragments
2446  int nowOrphFragCnt = 0; // count of just orphaned fragments
2447  int updatedFragCnt = 0; // count of just updated fragments
2448  Iterator<SuggestionFragment> fragIt = suggestion.getFragments().iterator();
2449  while (fragIt.hasNext()) { // for each suggestion fragment
2450  SuggestionFragment fragment = fragIt.next();
2451  try {
2452  // find fragment
2453  UpdatableFragment uf = exactMatcherProvider.match(parsedDoc, fragment.toUpdatableFragment());
2454  if (uf != null) { // if fragment was found
2455  if (fragment.getIsGood() == false) { // if fragment was marked as bad
2456  fragment.setIsGood(true); // mark as good
2457  updatedFragCnt++; // fragment was now updated
2458  }
2459  } else { // if fragment was not found
2460  // find fragment in document with full matching capability
2461  //ArrayList <UpdatableFragment> ufl = matcherProvider.matchAllIncrementally(parsedDoc, fragment.toUpdatableFragment());
2462  ArrayList<UpdatableFragment> ufl = new ArrayList<UpdatableFragment>();
2463  // find nearest fragment
2464  UpdatableFragment ufTemp = nearestMatcherProvider.matchInClosestNode(parsedDoc, fragment.toUpdatableFragment());
2465  if (ufTemp != null) {
2466  ufl.add(ufTemp);
2467  } else {
2468  // find fragment with sequence iterator
2469  ufl = sequenceMatcherProvider.matchAllIncrementally(parsedDoc, fragment.toUpdatableFragment());
2470  }
2471  if (ufl.size() == 1) { // if one fragment was found
2472  // get fragment (index unknown)
2473  Iterator<UpdatableFragment> ufIt = ufl.iterator();
2474  uf = ufIt.next();
2475  fragment.updateWithUpdatableFragment(uf); // update fragment in suggestion
2476  updatedFragCnt++;
2477  if (fragment.getIsGood() == false) { // if fragment was marked as bad
2478  fragment.setIsGood(true); // mark as good
2479  }
2480  } else if (ufl.isEmpty()) { // if no fragment found
2481  if (fragment.getIsGood() == true) { // if fragment was not bad
2482  fragment.setIsGood(false); // mark as bad
2483  nowOrphFragCnt++; // fragment was now orphaned
2484  }
2485  badFragCnt++;
2486  } else { // if searching is ambiguous
2487  // select the best fragment
2488  int minBadness = Integer.MAX_VALUE; // minimal badness
2489  UpdatableFragment minBFR = null; // fragment with minimal L.D.
2490  String origPath = fragment.getPath(); // original XPath
2491  String origText = fragment.getAnnotatedText(); // original annotated text
2492  int origOffset = fragment.getOffset(); // original offset
2493  for (Iterator<UpdatableFragment> uflIt = ufl.iterator(); uflIt.hasNext();) {
2494  UpdatableFragment ufr = uflIt.next();
2495  int lD = Util.levenshtein(origPath, ufr.getXPathString());
2496  int lDT = Util.levenshtein(origText, ufr.getText());
2497  int offDistance = Math.abs(origOffset - ufr.getOffset());
2498  int badness = 10000 * lD + 1000 * lDT + offDistance;
2499  if (badness < minBadness) {
2500  minBadness = badness;
2501  minBFR = ufr;
2502  }
2503  }
2504  uf = minBFR;
2505  fragment.updateWithUpdatableFragment(uf); // update fragment in annotation
2506  updatedFragCnt++;
2507  if (fragment.getIsGood() == false) { // if fragment was marked as bad
2508  fragment.setIsGood(true); // mark as good
2509  }
2510  } // if searching is ambiguous
2511  } // if fragment was not found
2512  } catch (XPathExpressionException ex) { // bad XPath in fragment
2513  if (fragment.getIsGood() == true) { // if fragment was not bad
2514  fragment.setIsGood(false); // mark as bad
2515  nowOrphFragCnt++; // fragment was now orphaned
2516  }
2517  badFragCnt++;
2518  } catch (Exception e) {
2520  String msg = "Update of suugestion fragments failed.";
2521  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg, e);
2522  }
2523  badFragCnt++;
2524  break;
2525  }
2526  } // for each annotated fragment
2527 
2528  if (badFragCnt == suggestion.getFragments().size() && nowOrphFragCnt > 0) {
2529  // if annotation was just orphaned
2530  } else if (nowOrphFragCnt > 0) {
2531  // if suggestion was just partially orphaned (bad fragments found)
2532  }
2533  if (nowOrphFragCnt > 0 || updatedFragCnt > 0) {
2534  // if new bad fragments found or some fragments was updated
2535  return true;
2536  }
2537  return false; // nothing updated (no update needed)
2538  } // updateSuggestion()
2539 
2540  /**
2541  * Method finds suggestion in the suggestion list by its content.
2542  *
2543  * @param suggestions suggestion list where method will search
2544  * @param suggestion suggestion which will be seek
2545  * @return founded suggestion
2546  */
2547  private Suggestion findSuggestion(ArrayList<Suggestion> suggestions, Suggestion suggestion){
2548  Iterator<Suggestion> newSugIt = suggestions.iterator();
2549  while(newSugIt.hasNext()){
2550  Suggestion actualSugg = newSugIt.next();
2551  if(actualSugg.contentEquals(suggestion, false, true)){
2552  return actualSugg;
2553  }
2554  }
2555 
2556  return null;
2557  }
2558 
2559  /**
2560  * Method finds suggestions in the suggestion list by its content.
2561  * Suggestions, not suggestion.
2562  *
2563  * @param suggestions suggestion list where method will search
2564  * @param suggestion suggestion which will be seek
2565  * @return founded suggestions in list.
2566  */
2567  private ArrayList<Suggestion> findSuggestions(ArrayList<Suggestion> suggestions, Suggestion suggestion){
2568  ArrayList<Suggestion> findedSuggestions = new ArrayList<Suggestion>();
2569  Iterator<Suggestion> newSugIt = suggestions.iterator();
2570  while(newSugIt.hasNext()){
2571  Suggestion actualSugg = newSugIt.next();
2572  if(actualSugg.contentEquals(suggestion, false, true)){
2573  findedSuggestions.add(actualSugg);
2574  }
2575  }
2576 
2577  return findedSuggestions;
2578  }
2579 
2580  /**
2581  * Method converts list of fragments to list of SuggestionFragments.
2582  *
2583  * @param fragments list of fragments
2584  * @param reference Suggestion to which new fragment should belong
2585  * @return list of converted fragments
2586  */
2587  private static ArrayList<SuggestionFragment> fragToSuggFrag(ArrayList<Fragment> fragments, Suggestion reference){
2588  ArrayList<SuggestionFragment> result = new ArrayList<SuggestionFragment>();
2589  if(fragments != null && !fragments.isEmpty()){
2590  // go trough all fragments
2591  Iterator<Fragment> fragIt = fragments.iterator();
2592  while(fragIt.hasNext()){
2593  Fragment currentFragment = fragIt.next();
2594  // create new suggestion fragment and set its prarameters
2595  SuggestionFragment newFragment = new SuggestionFragment();
2596  newFragment.setAnnotatedText(currentFragment.getAnnotatedText());
2597  newFragment.setIsGood(currentFragment.getIsGood());
2598  newFragment.setLength(currentFragment.getLength());
2599  newFragment.setOffset(currentFragment.getOffset());
2600  newFragment.setPath(currentFragment.getPath());
2601  newFragment.setRefSuggestion(reference);
2602  result.add(newFragment);
2603  }
2604  }
2605 
2606  return result;
2607  } // fragToSuggFrag()
2608 
2609  /**
2610  * Method filter list of suggestions by fragments.
2611  *
2612  * @param session session where are stored fragments specified by user
2613  * @param userSuggestions suggestions that will be filtered
2614  */
2615  private static void filtrateByFragments(EditorSession session, ArrayList<Suggestion> userSuggestions){
2616  if(userSuggestions != null && !userSuggestions.isEmpty()
2617  && session.getSuggestionsFr() != null
2618  && !session.getSuggestionsFr().isEmpty()){
2619  // get document
2620  Document doc = session.getParsedSyncDocument();
2621  // linearize fragments for suggestions defined by user
2622  Integer offset = session.getSuggestionsFr().get(0).getOffset();
2623  Integer length = session.getSuggestionsFr().get(0).getLength();
2624 
2625  // turn suggestions off
2626  if(length != null && length == 0) {
2627  session.getSuggestionsFr().clear();
2628  userSuggestions.clear();
2629  return;
2630  }
2631  // request for the whole document
2632  else if (offset == null && length == null) {
2633  return;
2634  }
2635  ArrayList<SuggestionFragment> linFragments = getLinearized(doc,fragToSuggFrag(session.getSuggestionsFr(),null));
2636  if(linFragments != null && !linFragments.isEmpty()){
2637 
2638  // gotrough all suggestions
2639  Iterator<Suggestion> suggIterator = userSuggestions.iterator();
2640  while(suggIterator.hasNext()){
2641  Suggestion actualSuggestion = suggIterator.next();
2642 
2643  // linearize suggestion fragment
2644  Iterator<SuggestionFragment> linFragIt = linFragments.iterator();
2645  // try to find by user defined fragent of document where suggestion fits
2646  while(linFragIt.hasNext()){
2647  if(!isInFragment(doc,actualSuggestion,linFragIt.next())){
2648  suggIterator.remove();
2649  }
2650  }
2651  }
2652  }
2653 
2654  if(session.getSuggestionsFr() != null) {
2655  session.getSuggestionsFr().clear();
2656  }
2657  } else if(userSuggestions != null && !userSuggestions.isEmpty()){
2658  userSuggestions.clear();
2659  }
2660  } // filtrateByFragments()
2661 
2662  /**
2663  * Method filter list of suggestions by their type.
2664  *
2665  * @param session session from user where is stored type that specifies suggestions
2666  * @param userSuggestions suggestions that will be filtered
2667  */
2668  private static void filtrateByType(EditorSession session, ArrayList<Suggestion> userSuggestions){
2669  if(userSuggestions != null && !userSuggestions.isEmpty()){
2670  // Get type of annotations requested by user
2671  ArrayList<String> requestedTypeUris = session.getSuggestionsTypes();
2672  if(requestedTypeUris != null && !requestedTypeUris.isEmpty()){
2673  if (!(requestedTypeUris.size() == 1 && requestedTypeUris.get(0) == null)) {
2674  // go trough all suggestions
2675  Iterator<Suggestion> suggIterator = userSuggestions.iterator();
2676  while (suggIterator.hasNext()) {
2677  boolean fits = false;
2678  /* As URIs may come from different groups for e.g.
2679  * http://localhost:8080/Annotations/types/g1/Person/Coreference_to_Person
2680  * and
2681  * http://localhost:8080/Annotations/types/g2/Person
2682  * it's needed to cut off group prefix from both URIs and after that comparison
2683  * can be used
2684  */
2685  Suggestion actualSuggestion = suggIterator.next();
2686  String actualUri = actualSuggestion.getAnnotType().getUri();
2687 
2688  /* Cut off prefix from URI */
2689  actualUri = actualUri.replace(AppBean.getBaseTypeUri(), "");
2690  actualUri = actualUri.substring(actualUri.indexOf("/")+1);
2691 
2692  Iterator<String> urisIterator = requestedTypeUris.iterator();
2693  while (urisIterator.hasNext()) {
2694  String suggType = urisIterator.next();
2695  /* Cut off prefix from URI */
2696  suggType = suggType.replace(AppBean.getBaseTypeUri(), "");
2697  suggType= suggType.substring(suggType.indexOf("/")+1);
2698 
2699  if ((actualUri.startsWith(suggType) && actualUri.length() > suggType.length() && actualUri.charAt(suggType.length()) == '/')
2700  || actualUri.equals(suggType)) {
2701  fits = true;
2702  }
2703  }
2704 
2705  // if suggestion is not requested type
2706  if (!fits) {
2707  // delete it
2708  suggIterator.remove();
2709  }
2710  }
2711  }
2712  }
2713  } // if(userSuggestions != null...
2714  } // filtrateByType()
2715 
2716  /**
2717  * Method make from list of structured fragments list of linearized fragments.
2718  *
2719  * @param doc document that fragments belongs
2720  * @param fragments list of structured fragments
2721  * @return list of linearized fragments
2722  */
2723  public static ArrayList<SuggestionFragment> getLinearized(Document doc, ArrayList<SuggestionFragment> fragments){
2724  ArrayList<ArrayList<SuggestionFragment>> notConverted = new ArrayList<ArrayList<SuggestionFragment>>();
2725  ArrayList<ArrayList<SuggestionFragment>> comFragments = new ArrayList<ArrayList<SuggestionFragment>>();
2726 
2727  comFragments.add(fragments);
2728 
2729  ArrayList<SuggestionFragment> linearizedList;
2730  linearizedList = Linearizer.fragmentsToLinSugFragments(comFragments,doc, notConverted, true);
2731 
2732  if (!notConverted.isEmpty()) {
2733  // notConverted is an array of arrays, so we need to go deeper...
2734  Iterator<ArrayList<SuggestionFragment>> notCIT = notConverted.iterator();
2735  while (notCIT.hasNext()) {
2736  ArrayList<SuggestionFragment> notC = notCIT.next();
2737  // one array contains fragments within
2738  if (!notC.isEmpty()) {
2740  String msg = "Some fragments was not linearized successfully.";
2741  Logger.getLogger(SuggestionManager.class.getName()).log(Level.WARNING, msg);
2742  }
2743  }
2744  }
2745  }
2746 
2747  return linearizedList;
2748  }
2749 
2750  /**
2751  * Method check if suggestion is in linear document fragment.
2752  *
2753  * @param doc document that suggestion and fragment belongs
2754  * @param sugg suggestion that will be tested
2755  * @param linFragment linearized document fragment that will be tested
2756  */
2757  private static boolean isInFragment(Document doc, Suggestion sugg, SuggestionFragment linFragment){
2758  Iterator<SuggestionFragment> linSuggFragmentsIt;
2759 
2760  if(sugg.getFragmentsAL().isEmpty() || sugg.getFragmentsAL().get(0) == null){
2761  return false;
2762  }
2763 
2764  try{
2765  linSuggFragmentsIt = getLinearized(doc, sugg.getFragmentsAL()).iterator();
2766  }catch(RuntimeException ex){
2768  String msg = ex + "Can't convert fragments of suggestion: " + sugg.toString();
2769  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
2770  }
2771 
2772  return false;
2773  }
2774 
2775  // get position of reference fragment content in linearized document
2776  int fragStart = linFragment.getOffset().intValue();
2777  int fragEnd = fragStart + linFragment.getLength().intValue();
2778 
2779  while(linSuggFragmentsIt.hasNext()){
2780  SuggestionFragment actualSuggFragment = linSuggFragmentsIt.next();
2781 
2782  // get position of current suggestion fragment content in linearized document
2783  int sugFragStart = actualSuggFragment.getOffset().intValue();
2784  int sugFragEnd = sugFragStart + actualSuggFragment.getLength().intValue();
2785 
2786  if(fragStart <= sugFragStart && fragEnd >= sugFragStart){
2787  // suggestion fragment starts in reference fragment
2788  return true;
2789  }else if(fragStart <= sugFragEnd && fragEnd >= sugFragEnd){
2790  // suggestion fragment ends in reference fragment
2791  return true;
2792  }
2793  }
2794  return false;
2795  } // isInFragment()
2796 
2797  /**
2798  * Method finds all linked suggestions of suggestions and return them as ArrayList.
2799  *
2800  * @param suggestion suggestion for which will be linked suggestions searched
2801  * @return list of founded linked suggestions
2802  */
2803  private ArrayList<Suggestion> getAllLinkedSugg(Suggestion suggestion){
2804  ArrayList<Suggestion> retArray = new ArrayList<Suggestion>();
2805  if(suggestion != null){
2806 
2807  // go trough all attributes of suggestion
2808  List attrObjects = suggestion.getAttributes();
2809  if(attrObjects != null && !attrObjects.isEmpty()){
2810  Iterator attrIt = attrObjects.iterator();
2811  while(attrIt.hasNext()){
2812  Object actualObject = (Object) attrIt.next();
2813 
2814  // try find linked suggestion attributes
2815  if(actualObject instanceof SugLinkedAttribute){
2816  // if find linked suggestion attribute
2817  SugLinkedAttribute currentLink = (SugLinkedAttribute)actualObject;
2818  if(currentLink.getValue() != null && currentLink.getValue() instanceof Suggestion){
2819  // add it to return array
2820  retArray.add(((Suggestion)currentLink.getValue()));
2821  }
2822  }
2823  }
2824  }
2825  }
2826 
2827  return retArray;
2828  } // getAllLinkedSugg()
2829 
2830  /**
2831  * Method clone attributes annot type without group, id, uri and attributes.
2832  *
2833  * @param referenceType annotation type that will be clone
2834  * @return new annotation type cloned from referenced type
2835  */
2836  private static AnnotType cloneType(AnnotType referenceType){
2837  AnnotType newType = new AnnotType();
2838  newType.setComment(referenceType.getComment());
2839  newType.setGroup(null);
2840  newType.setName(referenceType.getName());
2841  newType.setRestrictedAtt(referenceType.getRestrictedAtt());
2842  newType.setUriInOntology(referenceType.getUriInOntology());
2843  return newType;
2844  }
2845 
2846  /**
2847  * Method clone attributes reference annot type and copy them to new type.
2848  *
2849  * @param referenceType attributes of this annotation type will be clone
2850  * @param newType cloned atributes will be copied to this annotation type
2851  */
2852  private static void cloneTypeAttributes(AnnotType referenceType, AnnotType newType){
2853  ArrayList<AnnotTypeAttr> clonedAttr = new ArrayList<AnnotTypeAttr>();
2854  if(referenceType.getAttributes() != null){
2855  // go trough all annotation type attributes
2856  Iterator<AnnotTypeAttr> attrIt = referenceType.getAttributes().iterator();
2857  while(attrIt.hasNext()){
2858  // make list of new annotation type attributes
2859  AnnotTypeAttr newAttr = new AnnotTypeAttr(attrIt.next());
2860  newAttr.setAnnotationType(newType);
2861  clonedAttr.add(newAttr);
2862  }
2863  }
2864  newType.setAttributes(clonedAttr);
2865  }
2866 
2867  /**
2868  * Method tests if array of annotation types contains type with specific uri.
2869  *
2870  * @param types array of types
2871  * @param uri searched type uri
2872  * @return true if type is found
2873  */
2874  private static boolean isAnnotTypeInArray(ArrayList<AnnotType> types, String uri){
2875  if(types != null && !types.isEmpty()){
2876  Iterator<AnnotType> typesIt = types.iterator();
2877  while(typesIt.hasNext()){
2878  if(typesIt.next().getUri().equals(uri)){
2879  return true;
2880  }
2881  }
2882  }
2883 
2884  return false;
2885  }
2886 
2887  /**
2888  * Method clone given type and all his ancestors tree if they aren't stored in
2889  * DB under given user group.
2890  *
2891  * @param currentType type of otrer group for clone
2892  * @param currentGroup current group of clonned type
2893  * @param clonedTypes list of cloned types, this list is filled in this function, out of this function is this list processed
2894  * @return cloned currentType
2895  */
2896  private static AnnotType cloneTypesTree(AnnotType currentType, UserGroup currentGroup, ArrayList<AnnotType> clonedTypes){
2897  String changedURI = changeGroupInUri(currentType.getUri(),currentGroup.getId());
2898 
2899  // process same type again - have to stop recursion
2900  for (Iterator<AnnotType> it = clonedTypes.iterator(); it.hasNext();) {
2901  AnnotType type = it.next();
2902  if (type.getUri().equals(changedURI)) {
2903  return type;
2904  }
2905  }
2906 
2907  // clone current type (without ancestors)
2908  AnnotType clonedType = cloneType(currentType);
2909  clonedType.setUri(changedURI);
2910  clonedType.setGroup(currentGroup);
2911  // clone attributes of current ancestor
2912  cloneTypeAttributes(currentType, clonedType);
2913 
2914  // don't add same already added ancestors
2915  if(!isAnnotTypeInArray(clonedTypes,clonedType.getUri())){
2916  clonedTypes.add(clonedType);
2917  }
2918 
2919  ArrayList<AnnotType> ancestorsOfType = currentType.getAncestorTypesAL();
2920  if(ancestorsOfType != null && !ancestorsOfType.isEmpty()){
2921  // go trough all ancestors
2922  Iterator<AnnotType> ancestorsOfTypeIt = ancestorsOfType.iterator();
2923  while(ancestorsOfTypeIt.hasNext()){
2924 
2925  // try to find if current ancestor is already in DB for current user group
2926  AnnotType currentAncestorType = ancestorsOfTypeIt.next();
2927  String changedUri = changeGroupInUri(currentAncestorType.getUri(),currentGroup.getId());
2928  AnnotType dbType = getAnnotTypeFromDB(changedUri);
2929  if(dbType == null){
2930  // this ancestor isn't in DB for current user group
2931  // recursively call ths method
2932  dbType = cloneTypesTree(currentAncestorType,currentGroup,clonedTypes);
2933  // if current ancestor have any ancestor
2934  if(dbType != null){
2935  // add all tree of ancestors to array of ancestors to save
2936  if (!clonedTypes.contains(dbType)) {
2937  clonedTypes.add(dbType);
2938  }
2939  }else{
2940  // this part of tree is already added
2941  continue;
2942  }
2943  }
2944 
2945  // if it is first add of ancestor, set him as main ancestor
2946  if(clonedType.getAncestorType() == null){
2947  clonedType.setAncestorType(dbType);
2948  }
2949 
2950  // add ancestor to list of ancestors
2951  clonedType.addAncestorType(dbType);
2952  }
2953  }
2954 
2955  return clonedType;
2956  }
2957 
2958 
2959  /**
2960  * If ancestor of type of annotation is not exists, but should and name
2961  * is probably composed of path in type tree, this method breakdowns path,
2962  * sets name properly and generate ancestors.
2963  * New names are generated from URI.
2964  * Ancestors are stored into informations about client request.
2965  *
2966  * @param type Type of annotation to check and breakdown
2967  * @param requestInfo Informations about client request
2968  * @param newTypes List of newly added types
2969  */
2970  public static ArrayList<AnnotType> breakdownType(AnnotType type, RequestInfo requestInfo, ArrayList<AnnotType> newTypes) {
2971  ArrayList<AnnotType> changedTypes = new ArrayList<AnnotType>();
2972  // get user group to which this type belongs
2973  UserGroup group = type.getGroup();
2974  // get string with name of type and names of his ancestors
2975  String namesStr = type.getUri().replace(AppBean.getBaseTypeUri(), "");
2976  // get array with name of type and names of his ancestors
2977  String[] namesArr = namesStr.split("/");
2978  ArrayList<String> names = new ArrayList<String>(Arrays.asList(namesArr));
2979  int nSize = names.size(); // compute number of names
2980  if (nSize > 2) { // if there is more then name of type and id of group
2981  // get name of type and remove it from list
2982  String typeName = names.remove(nSize - 1);
2983  nSize--;
2984  type.setName(typeName); // set proper name to type
2985  AnnotType nextType = type; // set actually checked type to checked type
2986  while (nSize > 1) { // create ancestor types (last name is group name)
2987  // get name of actual (next to now generated) type
2988  String nextName = nextType.getName();
2989  // get name of ancestor (previous in hierarchy)
2990  String prevName = names.remove(nSize - 1);
2991  nSize--;
2992  // get URI of actual type
2993  String nUri = nextType.getUri();
2994  // get URI of ancestor type
2995  // prevUri = uri of next without "/" and name of next
2996  String prevUri = nUri.substring(0, nUri.lastIndexOf("/"));
2997  // flag represents a successful search for a type in the newTypes array
2998  boolean foundInNewTypes = false;
2999 
3000  // query database for ancestor type
3001  Object[] params = new Object[2];
3002  params[0] = "uri";
3003  params[1] = prevUri;
3004  List tList = AppBean.getPersistenceManager().queryDB("AnnotType.findByUri", params);
3005  if (tList != null && !tList.isEmpty()) { // if ancestor was found
3006  AnnotType prevType = (AnnotType) tList.get(0);
3007  nextType.setAncestorType(prevType); // set ancestor properly
3008  nextType.addAncestorType(prevType);
3009  break; // end of checking (all other is in database)
3010  }
3011  else if (newTypes != null && !newTypes.isEmpty()) {
3012  Iterator<AnnotType> newTypesIt = newTypes.iterator();
3013  while (newTypesIt.hasNext()) {
3014  AnnotType newType = newTypesIt.next();
3015  if (newType.getUri().equals(prevUri)) {
3016  nextType.setAncestorType(newType); // set ancestor properly
3017  nextType.addAncestorType(newType);
3018  foundInNewTypes = true;
3019  break;
3020  }
3021  }
3022  }
3023 
3024  // if not found in DB nor newTypes, create ancestor type
3025  if (!foundInNewTypes) {
3026  AnnotType newType = new AnnotType(prevUri, prevName, null, group);
3027  nextType.setAncestorType(newType); // set ancestor of actual type to new ancestor
3028  nextType.addAncestorType(newType);
3029  changedTypes.add(newType); // add new ancestor type to flier
3030  nextType = newType; // set ancestor as actually checked type
3031  }
3032  } // create ancestor types (last name is group name)
3033  } // if there is more then name of type and id of group
3034  return changedTypes;
3035  } // breakdownType()
3036 
3037  /**
3038  * Persist types of annotations to DB
3039  *
3040  * @param types Types of annotations to persist
3041  * @return In case of success returns false, true otherwise
3042  */
3043  public static boolean persistTypes(ArrayList<AnnotType> types) {
3044  EntityManager em = AppBean.getPersistenceManager().getEM();
3045  EntityTransaction transaction = em.getTransaction();
3046  try {
3047  transaction.begin();
3048 
3049  ArrayList<AnnotType> alreadyStored = new ArrayList<AnnotType>();
3050 
3051  // create list without attributes and ansestors and map with original types
3052  ArrayList<AnnotType> nTWA = new ArrayList<AnnotType>();
3053  Map<String, AnnotType> nTMap = new HashMap<String, AnnotType>();
3054  for (Iterator<AnnotType> ntIt = types.iterator(); ntIt.hasNext();) {
3055  AnnotType type = ntIt.next();
3056  if (type.getId() != null) {
3057  alreadyStored.add(type);
3058  continue;
3059  }
3060  AnnotType nT = new AnnotType(type.getUri(), type.getName(), null, type.getGroup());
3061  nT.setRestrictedAtt(type.getRestrictedAtt());
3062  nT.setUriInOntology(type.getUriInOntology());
3063  nT.setComment(type.getComment());
3064  nTWA.add(nT);
3065  nTMap.put(type.getUri(), type);
3066  }
3067 
3068  // merge types without attributes and create map with merged types
3069  ArrayList<AnnotType> mergedTypes = new ArrayList<AnnotType>();
3070  Map<String, AnnotType> mTypesMap = new HashMap<String, AnnotType>();
3071  for (Iterator<AnnotType> nTWAIt = nTWA.iterator(); nTWAIt.hasNext();) {
3072  AnnotType type = nTWAIt.next();
3073  if (type.getId() != null) {
3074  continue;
3075  }
3076  type = em.merge(type);
3077  mergedTypes.add(type);
3078  mTypesMap.put(type.getUri(), type);
3079  }
3080 
3081  // fix, add and merge attributes and ancestors
3082  for (Iterator<AnnotType> mIt = mergedTypes.iterator(); mIt.hasNext();) {
3083  AnnotType mType = mIt.next();
3084  AnnotType oType = nTMap.get(mType.getUri()); // get original type
3085 
3086  // skip type, that is stored in DB
3087  if (oType == null || mType == null || mType.getId() != null || oType.getId() != null){
3088  continue;
3089  }
3090 
3091  // attributes
3092  List<AnnotTypeAttr> aList = oType.getAttributes();
3093  for (Iterator<AnnotTypeAttr> aIt = aList.iterator(); aIt.hasNext();) {
3094  AnnotTypeAttr aTA = aIt.next();
3095  AnnotType aTAAT = aTA.getAttributeType();
3096  if (aTAAT != null) { // if it is structured attribute
3097  // replace type with merged one
3098  AnnotType rType = mTypesMap.get(aTAAT.getUri());
3099  if (rType == null) { // it is not new type, it is in database
3100  rType = queryType(aTAAT.getUri(), em);
3101  }
3102  aTA.setAttributeType(rType);
3103  }
3104  // fix back reference to annotation type
3105  aTA.setAnnotationType(mTypesMap.get(aTA.getAnnotationType().getUri()));
3106  }
3107  mType.setAttributes(new ArrayList<AnnotTypeAttr>(aList));
3108 
3109  // primary ancestor
3110  if (oType.getAncestorType() != null) {
3111  // replace type with merged one
3112  AnnotType rType = mTypesMap.get(oType.getAncestorType().getUri());
3113  if (rType == null) { // it is not new type, it is in database
3114  rType = queryType(oType.getAncestorType().getUri(), em);
3115  }
3116  mType.setAncestorType(rType);
3117  }
3118 
3119  // ancestors
3120  ArrayList<AnnotType> newAncestors = new ArrayList<AnnotType>();
3121  if (oType.getAncestorTypes() != null) {
3122  for (Iterator<AnnotType> ancIt = oType.getAncestorTypes().iterator(); ancIt.hasNext();) {
3123  AnnotType ancType = ancIt.next();
3124  AnnotType mAnc = mTypesMap.get(ancType.getUri());
3125  if (mAnc == null) { // it is not new type, it is in database
3126  mAnc = queryType(ancType.getUri(), em);
3127  }
3128  // skip type, that is stored in DB
3129  if (mAnc != null && (ancType.getId() != null || mAnc.getId() != null)) {
3130  continue;
3131  }
3132  newAncestors.add(mAnc);
3133  }
3134  }
3135  mType.setAncestorTypes(newAncestors);
3136 
3137  em.merge(mType);
3138  } // fix, add and merge attributes and ancestors
3139 
3140  em.flush();
3141  transaction.commit();
3142  mergedTypes.addAll(alreadyStored);
3143  types.clear();
3144  types.addAll(mergedTypes);
3145  return false;
3146  } catch (Exception e) {
3147  transaction.rollback();
3149  String msg = "Persisting of types of annotations failed.";
3150  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg, e);
3151  }
3152  return true;
3153  } finally {
3154  em.close();
3155  }
3156  } // persistTypes()
3157 
3158  /************************************************************
3159  * DATABASE MANIPULATION METHODS
3160  ************************************************************/
3161 
3162  /**
3163  * Query database for type of annotation
3164  *
3165  * @param uri URI of type of annotation
3166  * @param em Entity manager
3167  * @return Returns type of annotation with given URI
3168  * @throws RuntimeException If type of annotation was not found, throws exception
3169  */
3170  public static AnnotType queryType(String uri, EntityManager em) throws RuntimeException {
3171  AnnotType annotType = null;
3172  Object[] params = new Object[2];
3173  params[0] = "uri";
3174  params[1] = uri;
3175  Query q = em.createNamedQuery("AnnotType.findByUri");
3176  for (int p = 0; p < params.length; p = p + 2) {
3177  q.setParameter((String) params[p], params[p + 1]);
3178  }
3179  List aList = q.getResultList();
3180  if (aList != null && !aList.isEmpty()) { // if type was found
3181  annotType = (AnnotType) aList.get(0);
3182  } else { // if type was not found (merge failed)
3184  String msg = "New type of annotation was not found.";
3185  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
3186  }
3187  throw new RuntimeException("New type not found!");
3188  }
3189  return annotType;
3190  } // queryType()
3191 
3192  /**
3193  * Method loads suggestions specified by document and confidence from the database.
3194  *
3195  * @param documentId document id that specify suggestions
3196  * @param minimalConfidence minimal confidence of suggestions
3197  * @return list of querried suggestions
3198  */
3199  private ArrayList<Suggestion> getSuggestionsForAlternatives(Integer documentId, int minimalConfidence){
3200  ArrayList<Suggestion> result = new ArrayList<Suggestion>();
3201 
3202  // get suggestions for document from database
3203  Object[] params = {"sourceDocId",documentId,"minCon",minimalConfidence};
3204  @SuppressWarnings("unchecked")
3205  List<Suggestion> suggestionList = AppBean.getPersistenceManager().queryDB("Suggestion.findForAlternatives",params);
3206 
3207  processSugAttributes(suggestionList, result);
3208  return result;
3209  }
3210 
3211  /**
3212  * Method loads suggestions specified by document from the database.
3213  *
3214  * @param documentId document id that specify suggestions
3215  * @return list of querried suggestions
3216  */
3217  public static ArrayList<Suggestion> getSuggestionsFromDB(Integer documentId){
3218  ArrayList<Suggestion> result = new ArrayList<Suggestion>();
3219 
3220  // get suggestions for document from database
3221  Object[] params = {"sourceDocId",documentId};
3222  @SuppressWarnings("unchecked")
3223  List<Suggestion> suggestionList = AppBean.getPersistenceManager().queryDB("Suggestion.findBySourceDocId",params);
3224 
3225  processSugAttributes(suggestionList, result);
3226  return result;
3227  }
3228 
3229  /**
3230  * Process suggestion attributes
3231  *
3232  * @param suggestionList Original list of suggestions
3233  * @param result New list of suggestions
3234  */
3235  public static void processSugAttributes(List<Suggestion> suggestionList, ArrayList<Suggestion> result) {
3236  if(suggestionList != null && !suggestionList.isEmpty()){
3237  Iterator<Suggestion> suggestionListIt = suggestionList.iterator();
3238  while(suggestionListIt.hasNext()){
3239  Suggestion actualSug = suggestionListIt.next();
3240  List<SugBaseAttribute> originalAttributes = actualSug.getAttributes();
3241  Iterator<SugBaseAttribute> attrIt = originalAttributes.iterator();
3242  ArrayList<SugBaseAttribute> newAttributes = new ArrayList<SugBaseAttribute>();
3243  while(attrIt.hasNext()){
3244  SugBaseAttribute attr = attrIt.next();
3246  SugBaseAttribute newAttr = SugAttributeManager.changeAttributeInstance(attr);
3247  newAttributes.add(newAttr);
3248  attrIt.remove();
3249  }
3250  }
3251  if(!newAttributes.isEmpty()){
3252  originalAttributes.addAll(newAttributes);
3253  actualSug.setAttributes(new ArrayList<SugBaseAttribute>(originalAttributes));
3254  }
3255  }
3256  result.addAll(suggestionList);
3257  }
3258  }
3259  /**
3260  * Method loads annotation type specified by group and uri from the database.
3261  *
3262  * @param groupId id of group of querried annotation type
3263  * @param uri uri of querried annotation type
3264  * @return annotation type that fits by groupId and uri
3265  */
3266  private static AnnotType getAnnotTypeFromDB(Integer groupId, String uri){
3267  Object[] params = {"uri",uri,"groupId",groupId};
3268  @SuppressWarnings("unchecked")
3269  List<AnnotType> types = AppBean.getPersistenceManager().queryDB("AnnotType.findByUriAndGroup",params);
3270  if(types == null || types.isEmpty()){
3271  return null;
3272  }
3273 
3274  return types.get(0);
3275  }
3276 
3277  /**
3278  * Method loads annotation type specified by uri from the database.
3279  *
3280  * @param uri Uri of queried annotation type
3281  * @return Returns annotation type that fits by uri
3282  */
3283  public static AnnotType getAnnotTypeFromDB(String uri){
3284  Object[] params = {"uri",uri};
3285  @SuppressWarnings("unchecked")
3286  List<AnnotType> types = AppBean.getPersistenceManager().queryDB("AnnotType.findByUri",params);
3287  if(types == null || types.isEmpty()){
3288  return null;
3289  }
3290 
3291  return types.get(0);
3292  }
3293 
3294  /**
3295  * Method loads suggestion attributes specified by suggestion link.
3296  *
3297  * @param suggId id of suggestion
3298  * @return list of founded linked suggestion attributes
3299  */
3300  private ArrayList<SugLinkedAttribute> getLinkedSugAttrsByLink(Integer suggId){
3301  ArrayList<SugLinkedAttribute> result = new ArrayList<SugLinkedAttribute>();
3302  Object[] params = {"linked",suggId};
3303  @SuppressWarnings("unchecked")
3304  List<SugLinkedAttribute> attr = AppBean.getPersistenceManager().queryDB("SuggestionAttribute.findByLinked",params);
3305  if(attr != null && !attr.isEmpty()){
3306  result.addAll(attr);
3307  }
3308 
3309  return result;
3310  }
3311 
3312  /**
3313  * Method loads suggestion attributes specified by nested suggestion.
3314  *
3315  * @param suggId id of nested suggestion
3316  * @return list of founded linked suggestion attributes
3317  */
3318  private ArrayList<SugNestedAttribute> getNestedSugAttrsByNested(Integer suggId){
3319  ArrayList<SugNestedAttribute> result = new ArrayList<SugNestedAttribute>();
3320  Object[] params = {"nested",suggId};
3321  @SuppressWarnings("unchecked")
3322  List<SugNestedAttribute> attr = AppBean.getPersistenceManager().queryDB("SuggestionAttribute.findByNested",params);
3323  if(attr != null && !attr.isEmpty()){
3324  result.addAll(attr);
3325  }
3326 
3327  return result;
3328  }
3329 
3330  /**
3331  * Method store new suggestion feedback to DB.
3332  *
3333  * @param feedback suggestion feedback that will be stored
3334  */
3335  private static void persistFeedback(SuggestionFeedback feedback){
3336  if(feedback != null){
3337  if(AppBean.getPersistenceManager().persistEntity(feedback)){
3338  // Error, input path is null
3340  String msg = "Can't save feedback to DB. Object: \n" + feedback.toString();
3341  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
3342  }
3343  }
3344  }
3345  }
3346 
3347  /**
3348  * Method updates suggestion feedback in DB.
3349  *
3350  * @param feedback suggestion feedback that will be update
3351  */
3352  private static void updateFeedback(SuggestionFeedback feedback){
3353  if(feedback != null){
3354  SuggestionFeedback savedSuggestionF = (SuggestionFeedback)AppBean.getPersistenceManager().saveEntityChanges(feedback);
3355  if(savedSuggestionF == null){
3356  // Error, input path is null
3358  String msg = "Can't save feedback to DB. Object: \n" + feedback.toString();
3359  Logger.getLogger(SuggestionManager.class.getName()).log(Level.SEVERE, msg);
3360  }
3361  }
3362  }
3363  }
3364 
3365  /**
3366  * Method loads suggestion feedback specified by group and document from the database.
3367  *
3368  * @param documentId document id that specify suggestion feedback
3369  * @param groupId group id that specify suggestion feedback
3370  */
3371  public static ArrayList<SuggestionFeedback> getFeedbackFromDB(Integer documentId, Integer groupId){
3372  ArrayList<SuggestionFeedback> result = new ArrayList<SuggestionFeedback>();
3373 
3374  Object[] params = {"groupId",groupId,"docId",documentId};
3375  @SuppressWarnings("unchecked")
3376  List<SuggestionFeedback> feedbackList = AppBean.getPersistenceManager().queryDB("SuggestionFeedback.findByDoc",params);
3377  if(feedbackList != null && !feedbackList.isEmpty()){
3378  result.addAll(feedbackList);
3379  }
3380 
3381  return result;
3382  }
3383 
3384  /**
3385  * Method loads suggestion positive feedback specified by annotation.
3386  *
3387  * @param annotId annotation id that specify suggestion feedback
3388  * @return array list with founded negative suggestions feedback
3389  */
3390  public static SuggestionFeedback getFeedbackByAnnot(Integer annotId){
3391  Object[] params = {"annotationId",annotId};
3392  @SuppressWarnings("unchecked")
3393  List<SuggestionFeedback> feedbackList = AppBean.getPersistenceManager().queryDB("SuggestionFeedback.findByAnnot",params);
3394  if(feedbackList != null && !feedbackList.isEmpty()){
3395  return feedbackList.get(0);
3396  }
3397 
3398  return null;
3399  }
3400 
3401  /**
3402  * Method loads negative suggestion feedback specified by group and document from
3403  * the database.
3404  *
3405  * @param documentId document id that specify suggestion feedback
3406  * @param groupId group id that specify suggestion feedback
3407  * @return array list with founded negative suggestions feedback
3408  */
3409  private ArrayList<SuggestionFeedback> getNegFeedbackFromDB(Integer documentId, Integer groupId){
3410  ArrayList<SuggestionFeedback> result = new ArrayList<SuggestionFeedback>();
3411 
3412  Object[] params = {"groupId",groupId,"docId",documentId};
3413  @SuppressWarnings("unchecked")
3414  List<SuggestionFeedback> feedbackList = AppBean.getPersistenceManager().queryDB("SuggestionFeedback.findByDocNeg",params);
3415  if(feedbackList != null && !feedbackList.isEmpty()){
3416  result.addAll(feedbackList);
3417  }
3418 
3419  return result;
3420  }
3421 
3422  /**
3423  * Method loads suggestion feedback specified by suggestion ID and group ID.
3424  *
3425  * @param suggestionId Id of suggestion for which we are searching suggestion feedback
3426  * @param groupId ID of group to which feedback belongs
3427  * @return Returns querried suggestion feedback or null if feedback isn't found
3428  */
3429  private static SuggestionFeedback getFeedbackSFromDB(Integer suggestionId, Integer groupId){
3430  Object[] params = {"suggestionId",suggestionId,"groupId",groupId};
3431  @SuppressWarnings("unchecked")
3432  List<SuggestionFeedback> feedbackList = AppBean.getPersistenceManager().queryDB("SuggestionFeedback.findBySuggestionId",params);
3433  if(feedbackList != null && !feedbackList.isEmpty()){
3434  return feedbackList.get(0);
3435  }
3436  return null;
3437  }
3438 
3439  /**
3440  * Method loads suggestion specified by id from the database.
3441  *
3442  * @param id id that specify suggestions
3443  * @return querried suggestion or null if suggestion isn't found
3444  */
3445  public static Suggestion getSuggestionFromDB(Integer id){
3446  Object[] params = {"id",id};
3447  @SuppressWarnings("unchecked")
3448  List<Suggestion> suggestionList = AppBean.getPersistenceManager().queryDB("Suggestion.findById",params);
3449  if(suggestionList != null && !suggestionList.isEmpty()){
3450  return suggestionList.get(0);
3451  }
3452 
3453  return null;
3454  }
3455 
3456  /************************************************************
3457  * DOCUMENT LOCK METHODS
3458  ************************************************************/
3459 
3460  /**
3461  * Method locks the document suggestions for change.
3462  *
3463  * @param documentId id of document
3464  */
3465  public void lockDocForChange(Integer documentId){
3466  while(true){
3467  if(AppBean.getLockMaster().getSuggestionLock(documentId).lockForChange()){
3468  break;
3469  }
3470  }
3471  }
3472 
3473  /**
3474  * Method unlocks the document suggestions for change.
3475  *
3476  * @param documentId id of document
3477  */
3478  public void unlockDocForChange(Integer documentId){
3479  AppBean.getLockMaster().getSuggestionLock(documentId).unlockForChange();
3480  }
3481 
3482  /**
3483  * Method test if is there request for document update.
3484  *
3485  * @param request informations about client request
3486  * @return true if is ther request for document update
3487  */
3488  private boolean isDocUpdate(RequestInfo request){
3489  if((request.getTextModifications() != null && !request.getTextModifications().isEmpty())
3490  || (requestInfo.getSyncDocument() != null
3491  && (getSuggestionsFromDB(requestInfo.getSyncDocument().getId()).isEmpty()
3492  || !requestInfo.getFlier().getTextModifications().isEmpty()))
3493  || requestInfo.getResyncDocContent() != null){
3494  return true;
3495  }
3496  return false;
3497  }
3498 
3499  /**
3500  * Method test if is there request for suggestions.
3501  *
3502  * @param request informations about client request
3503  * @return true if is ther request for suggestions
3504  */
3505  private boolean isSuggestionsRequest(RequestInfo request){
3506  if((request.isSuggFragmentChanged() && request.getSyncDocument() == null)){
3507  return true;
3508  }
3509  return false;
3510  }
3511 
3512  /**
3513  * Method test if is there request with positive feedback.
3514  *
3515  * @param request informations about client request
3516  * @return true if is ther request with positive feedback
3517  */
3518  private boolean isPositiveFeedback(RequestInfo request){
3519  if(request.getConfirmedSuggestions() != null && !request.getConfirmedSuggestions().isEmpty()){
3520  return true;
3521  }
3522 
3523  return false;
3524  }
3525 
3526  /**
3527  * Method test if is there request with negative feedback.
3528  *
3529  * @param request informations about client request
3530  * @return true if is ther request with negative feedback
3531  */
3532  private boolean isNegativeFeedback(RequestInfo request){
3533  if(request.getRefusedSuggestions() != null && !request.getRefusedSuggestions().isEmpty()){
3534  return true;
3535  }
3536 
3537  return false;
3538  }
3539 
3540  /**
3541  * Method test if is there request with changed annotations.
3542  *
3543  * @param request informations about client request
3544  * @return true if is ther request with changed annotations
3545  */
3546  private boolean isAnnotChange(RequestInfo request){
3547  if(request.getFlier().getEditedAnnotations() != null
3548  && !request.getFlier().getEditedAnnotations().isEmpty()){
3549  return true;
3550  }
3551 
3552  return false;
3553  }
3554 
3555  /**
3556  * Method test if is there request with removed annotations.
3557  *
3558  * @param request informations about client request
3559  * @return true if is ther request with removed annotations
3560  */
3561  private boolean isAnnotDelete(RequestInfo request){
3562  if(request.getFlier().getRemovedAnnotations() != null
3563  && !request.getFlier().getRemovedAnnotations().isEmpty()){
3564  return true;
3565  }
3566 
3567  return false;
3568  }
3569 
3570  /**
3571  * Method test if is there request with added annotations.
3572  *
3573  * @param request informations about client request
3574  * @return true if is ther request with added annotations
3575  */
3576  private boolean isAnnotAdded(RequestInfo request){
3577  if(request.getFlier().getAddedAnnotations() != null
3578  && !request.getFlier().getAddedAnnotations().isEmpty()){
3579  return true;
3580  }
3581 
3582  return false;
3583  }
3584 
3585  /**
3586  * Creates escaped version of the provided textual data for use in JSON format
3587  * for SEC API.
3588  * Method expects SEC API to store strings enclosed in double quote.
3589  * That's why double quote character needs to be escaped and single quote not.
3590  *
3591  * @param source string with characters to be escaped
3592  * @return Returns escaped veersion of string
3593  */
3594  private static String EscapeForSecApi(String source) {
3595  String result = source;
3596  if (result != null) {
3597  result = result.replace("\\", "\\\\");
3598  result = result.replace("\"", "\\\"");
3599  result = result.replace("\n", " ");
3600  result = result.replace("\t", " ");
3601  }
3602  return result;
3603  } // EscapeForSecApi()
3604 
3605 } // class SuggestionManager
void updateDocument(RequestInfo request, ArrayList< Suggestion > oldSuggestions, ArrayList< Suggestion > addedSuggestions, ArrayList< Suggestion > changedSuggestions, ArrayList< AnnotType > newTypes)
ArrayList< SugLinkedAttribute > getLinkedSugAttrsByLink(Integer suggId)
static void processSugAttributes(List< Suggestion > suggestionList, ArrayList< Suggestion > result)
static ArrayList< SuggestionFragment > fragToSuggFrag(ArrayList< Fragment > fragments, Suggestion reference)
void insertNewSuggestions(ArrayList< Suggestion > newSuggestions, ArrayList< Suggestion > oldSuggestions, ArrayList< Suggestion > addedSugg, ArrayList< Suggestion > changedSugg)
ArrayList< SuggestionLogEntry > refuseOtherSugFromFragments(RequestInfo request)
void feedbackChangeRef(ArrayList< Suggestion > list, Suggestion sgFromList, ArrayList< Suggestion > modified, SuggestionFeedback fb, ArrayList< Suggestion > removedSuggestions)
void setConfidenceToAllNested(Suggestion sg, Integer confidence, ArrayList< Suggestion > changedSuggestions)
Utility functions for document linearization.
Definition: Linearizer.java:40
Attribute manager provides a way how to create new attributes for prupose of suggestion.
String makeClientMessage(String suggestionToAddM, String suggestionToRemoveM)
Class representing attribute of type of annotation.
ArrayList< TextModification > getTextModifications()
String printSuggestionsDiff(EditorSession session, ArrayList< Suggestion > modifiedSuggestions, ArrayList< AnnotType > newTypes)
String filterByClientCache(EditorSession session, ArrayList< Suggestion > shouldHave, ArrayList< Suggestion > changedSuggestions)
static boolean updateSuggestion(Suggestion suggestion, RequestInfo request)
ArrayList< Suggestion > cutRefusedSuggLinks(ArrayList< Suggestion > userSuggestions, ArrayList< Suggestion > refusedSuggestions)
void rejectSuggestions(RequestInfo request, ArrayList< SuggestionLogEntry > skipSugs, ArrayList< SuggestionLogEntry > noAlternatives)
static void filtrateSuggestions(RequestInfo requestInfo, EditorSession session, ArrayList< Suggestion > userSuggestions)
Class representing annotated copy of document.
Class representing attribute of type NestedAnnotation for peupose of suggestion.
static void initReqTypesFromRemote(SECAPIConn conn, RequestInfo requestInfo)
ArrayList< Suggestion > findSuggestions(ArrayList< Suggestion > suggestions, Suggestion suggestion)
Singleton for storing global variables.
Definition: AppBean.java:47
static void filtrateByFragments(EditorSession session, ArrayList< Suggestion > userSuggestions)
Class providing access to available matchers.
Suggestion findSuggestion(ArrayList< Suggestion > suggestions, Suggestion suggestion)
static ArrayList< Suggestion > getNestedSuggFromToDelete(ArrayList< Suggestion > inputSuggs, ArrayList< Suggestion > suggsToDelete)
Class holds pair of suggestion and corresponding anntation.
boolean haveLinkOn(Suggestion suggestion, Suggestion linkedSuggestion)
Interface for call of SEC API as external program (deamon)
static ArrayList< SuggestionFragment > getLinearized(Document doc, ArrayList< SuggestionFragment > fragments)
Suggested annotation with informations about suggestion.
Class representing user group.
Definition: UserGroup.java:47
String getSuggestionsFromSECAPI(RequestInfo parRequestInfo, String doc, String uri, boolean useAlternatives, ArrayList< Suggestion > validSuggestions)
boolean isSuggestionInFeedback(ArrayList< SuggestionFeedback > feedbackList, Suggestion searchedSugg)
static AnnotType cloneTypesTree(AnnotType currentType, UserGroup currentGroup, ArrayList< AnnotType > clonedTypes)
static void cloneTypeAttributes(AnnotType referenceType, AnnotType newType)
static void checkTypes(EditorSession session, ArrayList< Suggestion > suggestions, ArrayList< AnnotType > newTypes, boolean solveAtribute)
static ArrayList< Suggestion > getAllDependencies(Suggestion suggestion)
Methods for translating output from SEC API to the Suggestion objects.
Suggestion findSuggInArray(Integer id, ArrayList< Suggestion > list)
ArrayList< SuggestionLogEntry > getOrigRefusedSuggestions()
ArrayList< Suggestion > getAlternativesRequestedFor()
static boolean isTypeInGroups(AnnotType annotType, RequestInfo requestInfo)
ArrayList< Suggestion > updateNegativeFeedback(RequestInfo request, ArrayList< SuggestionLogEntry > skipSugs, ArrayList< SuggestionLogEntry > noAlternatives)
Class provides offerining of suggestions with usage of local knowledge repository.
static boolean isInFragment(Document doc, Suggestion sugg, SuggestionFragment linFragment)
static boolean isAnnotTypeInArray(ArrayList< AnnotType > types, String uri)
Class for creating of requested type definition for SEC API.
static ArrayList< SecApiReqTypeDef > getReqTypeDefinitions()
Definition: AppBean.java:863
Class representing type of annotation.
Definition: AnnotType.java:58
Compare class using Levenshtein approximate string matching method.
Class representing attribute of type AnnotationLink for prupose of suggestion.
ArrayList< Suggestion > updateSuggestionsFragments(ArrayList< Suggestion > suggestions, RequestInfo request, ArrayList< Suggestion > changedSugg)
static String printTypes(RequestInfo requestInfo, EditorSession session, ArrayList< AnnotType > newTypes)
String getSuggestionsFromRemoteSECAPI(RequestInfo parRequestInfo, String doc, String uri, boolean useAlternatives, ArrayList< Suggestion > validSuggestions)
Class consisting of traversing method and compare method.
Definition: Comparator.java:37
static Suggestion getSuggestionFromList(Integer suggestionId, List< Suggestion > list)
static ArrayList< SuggestionFeedback > getFeedbackFromDB(Integer documentId, Integer groupId)
static Suggestion updateSuggNegativeFeedback(RequestInfo request, Integer groupId, int refusedSuggID, boolean processAlternatives)
ArrayList< SuggestionLogEntry > getConfirmedSuggestions()
Class implementing functions for communication with remote SEC API.
Definition: SECAPIConn.java:37
ArrayList< Suggestion > getSuggestionWithoutFeedback(ArrayList< Suggestion > list, ArrayList< Suggestion > modified)
static SuggestionFeedback getFeedbackSFromDB(Integer suggestionId, Integer groupId)
Class for matcher consisting of comparator and node iterator.
Definition: Matcher.java:32
Processed informations about client request.
static void sendToOthers(RequestInfo requestInfo, String message)
Class representing suggestion of annotation.
Definition: Suggestion.java:87
static ArrayList< Suggestion > addAllDependencies(ArrayList< Suggestion > filteredSuggestions, ArrayList< Suggestion > nonFilteredSuggestion)
static void filtrateByConfidence(Integer minimalConfidence, ArrayList< Suggestion > userSuggestions)
static ArrayList< AnnotType > breakdownType(AnnotType type, RequestInfo requestInfo, ArrayList< AnnotType > newTypes)
void compareFragments(ArrayList< Suggestion > suggestions, ArrayList< Suggestion > changedSuggestions)
ArrayList< SuggestionFeedback > getNegFeedbackFromDB(Integer documentId, Integer groupId)
Informations about client session.
Represents database entitiy with suggestion feedback. feedback.
ArrayList< SuggestionLogEntry > getRefusedSuggestions()
Utility class (manipulates RFC 3339 dates)
Definition: Util.java:29
Class representing annotated fragment.
Definition: Fragment.java:48
ArrayList< Suggestion > filtrateRefusedSugg(RequestInfo request, ArrayList< Suggestion > docSuggestions)
ArrayList< Suggestion > getSuggestionsForAlternatives(Integer documentId, int minimalConfidence)
ArrayList< SugNestedAttribute > getNestedSugAttrsByNested(Integer suggId)
static AnnotType getTypeWithSameURI(List< AnnotType > list, String uri)
ArrayList< Suggestion > getAffectedForDelete(ArrayList< Annotation > removedAnnot)
AnnotSugPair getPairByAnnot(ArrayList< AnnotSugPair > pairs, Annotation annot)
static void filtrateByType(EditorSession session, ArrayList< Suggestion > userSuggestions)
Class which implements Comparator to sort arrayList of SuggestionFragment alphabetically.
The object implements comparator of Alternative objects that are compared by confidence (from highest...
static String createSecApiSuggestionsRequest(String doc, String uri, boolean useAlternatives)
static ArrayList< Suggestion > getSuggestionsFromDB(Integer documentId)
void getNewClientCache(ArrayList< Suggestion > addedSugg, ArrayList< Integer > deletedSugg, ArrayList< Integer > actualCache)