4A Server -  2.0
 All Classes Namespaces Files Functions Variables Enumerator
RenameTypes.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: RenameTypes.java
5  * Description: Backbean for page for batch renaming and commenting of types
6  * of annotations
7  */
8 
9 /**
10  * @file RenameTypes.java
11  *
12  * @brief Backbean for page for batch renaming of types of annotations
13  */
14 package cz.vutbr.fit.knot.annotations.web;
15 
24 import java.io.IOException;
25 import java.io.Serializable;
26 import java.io.StringReader;
27 import java.io.StringWriter;
28 import java.util.ArrayList;
29 import java.util.Iterator;
30 import java.util.List;
31 import javax.faces.bean.ManagedBean;
32 import javax.faces.bean.ViewScoped;
33 import javax.persistence.EntityManager;
34 import javax.persistence.EntityTransaction;
35 import javax.persistence.Query;
36 import javax.xml.parsers.DocumentBuilder;
37 import javax.xml.parsers.DocumentBuilderFactory;
38 import javax.xml.parsers.ParserConfigurationException;
39 import org.apache.commons.io.IOUtils;
40 import org.apache.myfaces.custom.fileupload.UploadedFile;
41 import org.w3c.dom.Document;
42 import org.w3c.dom.Element;
43 import org.w3c.dom.NodeList;
44 import org.xml.sax.InputSource;
45 import org.xml.sax.SAXException;
46 
47 /**
48  * Backbean for page for batch renaming and commenting of types of annotations
49  *
50  * @brief Backbean for page for batch renaming of types of annotations
51  * @author idytrych
52  */
53 @ManagedBean
54 @ViewScoped
55 public class RenameTypes implements Serializable {
56  /**
57  * Error message displayed in form
58  */
59  private String errorMessage = "";
60  /**
61  * Success message displayed in form
62  */
63  private String successMessage = "";
64  /**
65  * Uploaded file
66  */
67  private UploadedFile uploadedFile;
68  /**
69  * File name
70  */
71  private String fileName;
72  /**
73  * User group in which uploaded types will be renamed
74  */
75  private String uGroup;
76 
77 
78  /**
79  * Action listener for upload button
80  *
81  * @return Returns page outcome (identificator of next page or null to stay here)
82  */
83  public String btnUploadAction() {
84 
85  errorMessage = "";
86  successMessage = "";
87 
88  if (uGroup.isEmpty()) {
89  errorMessage = MessageProvider.getMessage("groupMustBeSet");
90  return null;
91  }
92  // query database for user group
93  Object[] params = new Object[2]; // parameters for database query
94  params[0] = "name";
95  params[1] = uGroup;
96  List gList = AppBean.getPersistenceManager().queryDB("UserGroup.findByName", params);
97  UserGroup userGroup = null;
98  if (gList != null && !gList.isEmpty()) { // if group was found
99  userGroup = (UserGroup) gList.get(0);
100  } else {
101  errorMessage = MessageProvider.getMessage("unknownGroup");
102  return null;
103  }
104 
105  // Informations about uploaded file
106  // String fileType = uploadedFile.getContentType();
107  // String fileNameStr = uploadedFile.getName();
108  // Long fileSize = uploadedFile.getSize(); // bytes
109 
110  // Create writer with file data
111  StringWriter fWriter = new StringWriter();
112  try {
113  IOUtils.copy(uploadedFile.getInputStream(), fWriter);
114  } catch (IOException ex) {
115  errorMessage = MessageProvider.getMessage("uploadingError");
116  return null;
117  }
118 
119  // parse XML witch changes
120  Document changesDoc = parseXml(fWriter.toString());
121  Element docEl = changesDoc.getDocumentElement();
122 
123  List<AnnotType> affectedTypes = new ArrayList<AnnotType>();
124 
125  NodeList changeNodes = docEl.getElementsByTagName("change");
126  int changesCnt = changeNodes.getLength();
127  for (int i = 0; i < changesCnt; i++) { // for each change
128  Element changeEl = (Element) changeNodes.item(i);
129  String uri = changeEl.getAttribute("uri");
130  if (uri == null || uri.isEmpty()) {
131  errorMessage = errorMessage + MessageProvider.getMessage("badUriPatternFound") + "<br/>";
132  continue;
133  }
134 
135  // process new name
136  String name = changeEl.getAttribute("newName");
137  if (name != null && name.isEmpty()) {
138  name = null;
139  }
140 
141  // process comment
142  String comment = null;
143  NodeList commentNL = changeEl.getElementsByTagName("comment");
144  if (commentNL.getLength() != 0) { // if any comment found
145  Element commentEl = (Element) commentNL.item(0);
146  int k = 1;
147  while (commentEl.getParentNode() != changeEl && k < commentNL.getLength()) {
148  // if it is node on nested level
149  commentEl = (Element) commentNL.item(k); // skip node
150  k++;
151  }
152  if (commentEl.getParentNode() == changeEl) { // if node is on right level
153  comment = MessageProcessor.getElementContent(commentEl);
154  }
155  } // if any comment found
156 
157  // find affected types
158  List<AnnotType> changedTypes = getChangedTypes(uri, userGroup);
159 
160  if (changedTypes.isEmpty()) {
161  errorMessage = errorMessage + MessageProvider.getMessage("noTypesSelectedByPattern") + ": " + uri + "<br/>";
162  continue;
163  }
164 
165  for (Iterator<AnnotType> chTIt = changedTypes.iterator(); chTIt.hasNext();) {
166  AnnotType chType = chTIt.next();
167 
168  // find annotations of this type and check whether name can be changed
169  if (name != null) {
170  params[0] = "type";
171  params[1] = chType.getId();
172  List aList = AppBean.getPersistenceManager().queryDB("Annotation.findByType", params);
173  if (aList != null && !aList.isEmpty()) { // if some annotations found
174  errorMessage = errorMessage + MessageProvider.getMessage("ifAnnotationsExistsNameCantBeChanged")
175  + " (" + chType.getUri() + ")<br/>";
176  name = null; // name can't be changed
177  }
178  }
179 
180  affectedTypes.add(chType); // type will be affected by change
181  if (name != null) { // if name will be changed
182  boolean someChange = true;
183  while (someChange) { // while some types added
184  someChange = false;
185  List<AnnotType> nowAdd = new ArrayList<AnnotType>();
186  for (Iterator<AnnotType> afIt = affectedTypes.iterator(); afIt.hasNext();) { // for all affected
187  AnnotType afT = afIt.next();
188  // query DB for types which primary ancestor is actual type
189  params[0] = "ancestor";
190  params[1] = afT.getId();
191 
192  @SuppressWarnings("unchecked")
193  List<AnnotType> tList = AppBean.getPersistenceManager().queryDB("AnnotType.findByAncestor", params);
194  if (tList != null && !tList.isEmpty()) { // if some type found
195  for (Iterator<AnnotType> tIt = tList.iterator(); tIt.hasNext();) {
196  AnnotType t = tIt.next();
197  if (!affectedTypes.contains(t) && !nowAdd.contains(t)) {
198  nowAdd.add(t); // type will be affected by change of ancestor
199  someChange = true;
200  }
201  }
202  } // if some type found
203  } // for all affected
204  affectedTypes.addAll(nowAdd);
205  } // while some types added
206  // change name
207  chType.setName(name);
208  } // if name will be changed
209 
210 
211  // change comment
212  if (comment != null) {
213  chType.setComment(comment);
214  }
215 
216  // process changes in attributes
217  NodeList attrNodes = changeEl.getElementsByTagName("attribute");
218  int attrCnt = attrNodes.getLength();
219  for (int j = 0; j < attrCnt; j++) { // for each attribute
220  Element attrEl = (Element) attrNodes.item(j);
221  String aName = attrEl.getAttribute("name");
222  if (aName == null || aName.isEmpty()) {
223  errorMessage = errorMessage + MessageProvider.getMessage("badAttrChangeDescriprionFound") + "<br/>";
224  continue;
225  }
226 
227  AnnotTypeAttr chAttr = null;
228  for (Iterator<AnnotTypeAttr> attrIt = chType.getAttributes().iterator(); attrIt.hasNext();) {
229  AnnotTypeAttr aTA = attrIt.next();
230  if (aTA.getName().equals(aName)) {
231  chAttr = aTA;
232  }
233  }
234 
235  if (chAttr == null) {
236  errorMessage = errorMessage + MessageProvider.getMessage("badAttrChangeDescriprionFound")
237  + ": " + aName + "<br/>";
238  continue;
239  }
240 
241  // process new name
242  String newAttrName = attrEl.getAttribute("newName");
243  if (newAttrName != null && newAttrName.isEmpty()) {
244  newAttrName = null;
245  }
246 
247  // update name
248  if (newAttrName != null) {
249  chAttr.setName(newAttrName);
250  }
251 
252  // process comment
253  String attrComment = null;
254  NodeList aCNL = attrEl.getElementsByTagName("comment");
255  if (aCNL.getLength() != 0) {
256  Element aCEl = (Element) aCNL.item(0);
257  attrComment = MessageProcessor.getElementContent(aCEl);
258  }
259 
260  // update comment
261  if (attrComment != null) {
262  chAttr.setComment(attrComment);
263  }
264 
265  } // for each attribute
266  } // for each changed type
267  } // for each change
268 
269  // check for duplicit attributes
270  for (Iterator<AnnotType> aTIt = affectedTypes.iterator(); aTIt.hasNext();) {
271  AnnotType aType = aTIt.next();
272  ArrayList<String> nList = new ArrayList<String>();
273  for (Iterator<AnnotTypeAttr> aTAIt = aType.getAttributes().iterator(); aTAIt.hasNext();) {
274  AnnotTypeAttr aTA = aTAIt.next();
275  if (!nList.contains(aTA.getName())) {
276  nList.add(aTA.getName());
277  } else { // if duplicit attribute found
278  errorMessage = errorMessage + MessageProvider.getMessage("changesViolateRestrictions")
279  + ": " + MessageProvider.getMessage("duplicitAttrsFound")
280  + ": " + aTA.getName() + "<br/>";
281  return null;
282  }
283  }
284  } // check for duplicit attributes
285 
286 
287  // persist changes to database
288  EntityManager em = AppBean.getPersistenceManager().getEM();
289  EntityTransaction transaction = em.getTransaction();
290  boolean errorOccurred = false;
291  try {
292  transaction.begin();
293 
294  List<AnnotType> sTypes = new ArrayList<AnnotType>(); // stored affected types
295 
296  for (Iterator<AnnotType> aTIt = affectedTypes.iterator(); aTIt.hasNext();) { // for each type
297  AnnotType aType = aTIt.next();
298  AnnotType sType = queryType(aType.getUri(), em); // get stored variant of type
299  sTypes.add(sType);
300  // update type
301  sType.setName(aType.getName());
302  sType.setComment(aType.getComment());
303  // update attributes
304  for (Iterator<AnnotTypeAttr> aTAIt = sType.getAttributes().iterator(); aTAIt.hasNext();) {
305  AnnotTypeAttr aTA = aTAIt.next();
306  // find new data and update attribute
307  for (Iterator<AnnotTypeAttr> nATAIt = aType.getAttributes().iterator(); nATAIt.hasNext();) {
308  AnnotTypeAttr nATA = nATAIt.next();
309  if (aTA.getId() == nATA.getId()) {
310  aTA.setName(nATA.getName());
311  aTA.setComment(nATA.getComment());
312  break;
313  }
314  }
315  }
316  } // for each type
317 
318  for (Iterator<AnnotType> sTIt = sTypes.iterator(); sTIt.hasNext();) {
319  AnnotType sType = sTIt.next();
320  sType.setUri(sType.getGeneratedURI()); // update URI
321  }
322 
323  // check for duplicit types
324  for (Iterator<AnnotType> sTIt = sTypes.iterator(); sTIt.hasNext();) {
325  AnnotType type = sTIt.next();
326  // query DB for types with given URI
327  params[0] = "uri";
328  params[1] = type.getUri();
329  Query q = em.createNamedQuery("AnnotType.findByUri");
330  for (int p = 0; p < params.length; p = p + 2) {
331  q.setParameter((String) params[p], params[p + 1]);
332  }
333  List tList = q.getResultList();
334  if (tList != null && !tList.isEmpty()) { // if type was found
335  if (tList.size() > 1) { // if more than one type found
336  errorMessage = errorMessage + MessageProvider.getMessage("changesViolateRestrictions")
337  + ": " + MessageProvider.getMessage("duplicitUrisFound")
338  + ": " + type.getUri() + "<br/>";
339  throw new RuntimeException("Duplicit URIs found!");
340  }
341  } else { // if type was not found
342  throw new RuntimeException("Some type was not found!");
343  }
344  } // check for duplicit types
345 
346  em.flush();
347  transaction.commit();
348  } catch (Exception e) {
349  transaction.rollback();
350  if (errorMessage.isEmpty()) {
351  errorMessage = errorMessage + MessageProvider.getMessage("typePersistingError") + "<br/>";
352  }
353  return null;
354  } finally {
355  em.close();
356  }
357 
358  // update URIs
359  for (Iterator<AnnotType> aTIt = affectedTypes.iterator(); aTIt.hasNext();) {
360  AnnotType aType = aTIt.next();
361  aType.setUri(aType.getGeneratedURI()); // update URI
362  }
363 
364  // prepare messages for connected clients
365  ResponseCreator rc = AppBean.getResponseCreator();
366  Iterator<EditorSession> sesIt = AppBean.getSessions().iterator();
367  synchronized(AppBean.getSessions()){
368  while (sesIt.hasNext()) { // for each client
369  EditorSession es = sesIt.next();
370  Flier flier = new Flier();
371  // create list of changed types
372  for (Iterator<AnnotType> atIt = affectedTypes.iterator(); atIt.hasNext();) {
373  AnnotType at = atIt.next();
374  flier.AddEditedType(at);
375  }
376  es.addMessageTS(rc.createCometResponse(flier, es)); // create message
377  }
378  }
379 
380  // display message about success
381  successMessage = MessageProvider.getMessage("uploadSuccessfull") + "<br/>"
382  +MessageProvider.getMessage("changesInTypesApplied");
383 
384  return null;
385  } // btnUploadAction()
386 
387  /**
388  * Gets changed types of annotations
389  *
390  * @param uriPattern URI pattern
391  * @param userGroup User group in which changed types are
392  * @return Returns list of changed types
393  */
394  private List<AnnotType> getChangedTypes(String uriPattern, UserGroup userGroup) {
395  if (!uriPattern.contains("*") && uriPattern.contains(AppBean.getBaseTypeUri())) {
396  // if pattern contains URI without wildcards, exact matching type will be returned
397  return getChangedTypeExact(uriPattern);
398  } else if (uriPattern.contains("*") && uriPattern.contains(AppBean.getBaseTypeUri())) {
399  // if pattern contains URI with wildcards
400  // replaces wildcards by these required for database query
401  uriPattern = uriPattern.replace("*", "%");
402  // return matching types
403  return getChangedTypesLike(uriPattern);
404  } else if (!uriPattern.contains("*")) {
405  // if pattern contains linearized name without wildcards
406  // creates list of names to URI
407  uriPattern = MessageProcessor.replaceArrows(uriPattern);
408  if (MessageProcessor.isGroupIncluded(uriPattern)) { // if group number is included
409  // create URI of type
410  uriPattern = AppBean.getBaseTypeUri() + uriPattern;
411  // return exactly matching types
412  return getChangedTypeExact(uriPattern);
413  } else { // if group number is not included
414  // create URI of type
415  String uriPatternWG = AppBean.getBaseTypeUri() + "g" + userGroup.getId() + "/" + uriPattern;
416  // return type exactly matching in this group
417  return getChangedTypeExact(uriPatternWG);
418  }
419  } else { // if pattern contains linearized name with wildcards
420  // replaces wildcards by these required for database query
421  uriPattern = uriPattern.replace("*", "%");
422  uriPattern = MessageProcessor.replaceArrows(uriPattern);
423  if (MessageProcessor.isGroupIncluded(uriPattern)) { // if group number is included
424  // create URI of type
425  uriPattern = AppBean.getBaseTypeUri() + uriPattern;
426  // return matching types
427  return getChangedTypesLike(uriPattern);
428  } else { // if group number is not included
429  // create URI of type
430  String uriPatternWG = AppBean.getBaseTypeUri() + "g" + userGroup.getId() + "/" + uriPattern;
431  // return types matching in this group
432  return getChangedTypesLike(uriPatternWG);
433  }
434  } // if filter contains linearized name with wildcards
435  } // getQueriedTypes()
436 
437  /**
438  * Gets type of annotations with given URI serialized in XML
439  *
440  * @param uri URI of requested type of annotations
441  * @return Returns list with types of annotations with given URI
442  */
443  private List<AnnotType> getChangedTypeExact(String uri) {
444  // query database for type with given URI
445  Object[] params = new Object[2];
446  params[0] = "uri";
447  params[1] = uri;
448 
449  @SuppressWarnings("unchecked")
450  List<AnnotType> tList = AppBean.getPersistenceManager().queryDB("AnnotType.findByUri", params);
451  if (tList != null && !tList.isEmpty()) { // if type was found
452  return tList;
453  }
454  return new ArrayList<AnnotType>(); // return empty list
455  } // getChangedTypeExact()
456 
457  /**
458  * Gets type of annotations with URI matching given pattern
459  * Character % is used as wildcard.
460  *
461  * @param uriPattern Pattern of URI of requested type of annotations
462  * @return Returns list with types of annotations with URI matching given pattern
463  */
464  @SuppressWarnings("unchecked")
465  private List<AnnotType> getChangedTypesLike(String uriPattern) {
466  List tList = null;
467  // query database for matching types
468  EntityManager em = AppBean.getPersistenceManager().getEM();
469  try {
470  Query query = em.createQuery("SELECT a FROM AnnotType a WHERE a.uri LIKE '" + uriPattern + "'");
471  tList = query.getResultList();
472  } catch (Exception e) {
473  tList = null;
474  } finally {
475  em.close();
476  }
477 
478  if (tList != null && !tList.isEmpty()) { // if some types was found
479  return tList;
480  }
481  return new ArrayList<AnnotType>(); // return empty list
482  } // getChangedTypesLike()
483 
484 
485  /**
486  * Query database for type of annotation
487  *
488  * @param uri URI of type of annotation
489  * @param em Entity manager
490  * @return Returns type of annotation with given URI
491  * @throws RuntimeException If type of annotation was not found, throws exception
492  */
493  private static AnnotType queryType(String uri, EntityManager em) throws RuntimeException {
494  AnnotType annotType = null;
495  Object[] params = new Object[2];
496  params[0] = "uri";
497  params[1] = uri;
498  Query q = em.createNamedQuery("AnnotType.findByUri");
499  for (int p = 0; p < params.length; p = p + 2) {
500  q.setParameter((String) params[p], params[p + 1]);
501  }
502  List aList = q.getResultList();
503  if (aList != null && !aList.isEmpty()) { // if type was found
504  annotType = (AnnotType) aList.get(0);
505  } else { // if type was not found (merge failed)
506  throw new RuntimeException("New type not found!");
507  }
508  return annotType;
509  } // queryType()
510 
511  /**
512  * Gets uploaded file
513  *
514  * @return Returns uploaded file
515  */
516  public UploadedFile getUploadedFile() {
517  return uploadedFile;
518  }
519 
520  /**
521  * Sets uploaded file
522  *
523  * @param uploadedFile Uploaded file
524  */
525  public void setUploadedFile(UploadedFile uploadedFile) {
526  this.uploadedFile = uploadedFile;
527  }
528 
529  /**
530  * Gets uploaded file name
531  *
532  * @return Returns uploaded file name
533  */
534  public String getFileName() {
535  return fileName;
536  }
537 
538  /**
539  * Gets error message displayed in form
540  *
541  * @return Returns error message displayed in form
542  */
543  public String getErrorMessage() {
544  return errorMessage;
545  }
546 
547  /**
548  * Sets error message to be displayed in form
549  *
550  * @param errorMessage Error message to be displayed in form
551  */
552  public void setErrorMessage(String errorMessage) {
553  this.errorMessage = errorMessage;
554  }
555 
556  /**
557  * Gets success message displayed in form
558  *
559  * @return Returns success message displayed in form
560  */
561  public String getSuccessMessage() {
562  return successMessage;
563  }
564 
565  /**
566  * Sets success message to be displayed in form
567  *
568  * @param successMessage Success message to be displayed in form
569  */
570  public void setSuccessMessage(String successMessage) {
571  this.successMessage = successMessage;
572  }
573 
574  /**
575  * Gets user group in which uploaded types will be shared
576  *
577  * @return Returns user group in which uploaded types will be shared
578  */
579  public String getuGroup() {
580  return uGroup;
581  }
582 
583  /**
584  * Sets user group in which uploaded types will be shared
585  *
586  * @param uGroup User group in which uploaded types will be shared
587  */
588  public void setuGroup(String uGroup) {
589  this.uGroup = uGroup;
590  }
591 
592  /**
593  * Parses XML with changes
594  *
595  * @param XMLString String with XML with changes
596  * @return Parsed XML in w3c.dom.Document
597  */
598  private static Document parseXml(String XMLString) {
599  Document dom;
600  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
601  dbf.setNamespaceAware(true);
602 
603  try {
604  DocumentBuilder db = dbf.newDocumentBuilder();
605  InputSource is = new InputSource();
606  is.setCharacterStream(new StringReader(XMLString));
607  dom = db.parse(is);
608  } catch (ParserConfigurationException pce) {
609  return null; // bad request
610  } catch (SAXException se) {
611  return null;
612  } catch (IOException ioe) {
613  return null;
614  }
615 
616  return dom;
617  } // parseXml()
618 
619 } // public class RenameTypes
Class representing attribute of type of annotation.
Singleton for storing global variables.
Definition: AppBean.java:47
Class for getting localized messages from message bundle.
void setSuccessMessage(String successMessage)
Backbean for page for batch renaming of types of annotations.
void setUploadedFile(UploadedFile uploadedFile)
Static class which parses and process XML with messages.
Class representing user group.
Definition: UserGroup.java:47
List< AnnotType > getChangedTypesLike(String uriPattern)
Class representing type of annotation.
Definition: AnnotType.java:58
Flier with informations for comet handlers.
Definition: Flier.java:31
List< AnnotType > getChangedTypeExact(String uri)
Class that creates responses and persists data.
List< AnnotType > getChangedTypes(String uriPattern, UserGroup userGroup)
Informations about client session.
static Document parseXml(String XMLString)
static AnnotType queryType(String uri, EntityManager em)