View Javadoc
1   /*
2    * This software was designed and created by Jason Carroll.
3    * Copyright (c) 2002, 2003, 2004 Jason Carroll.
4    * The author can be reached at jcarroll@cowsultants.com
5    * ITracker website: http://www.cowsultants.com
6    * ITracker forums: http://www.cowsultants.com/phpBB/index.php
7    *
8    * This program is free software; you can redistribute it and/or modify
9    * it only under the terms of the GNU General Public License as published by
10   * the Free Software Foundation; either version 2 of the License, or
11   * (at your option) any later version.
12   *
13   * This program is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   * GNU General Public License for more details.
17   */
18  
19  package org.itracker.web.util;
20  
21  import org.apache.log4j.Logger;
22  import org.itracker.core.resources.ITrackerResources;
23  import org.itracker.model.*;
24  import org.itracker.model.util.IssueUtilities;
25  import org.itracker.model.util.UserUtilities;
26  import org.xml.sax.Attributes;
27  import org.xml.sax.SAXException;
28  import org.xml.sax.helpers.DefaultHandler;
29  
30  import java.util.*;
31  
32  
33  /**
34   * This class provides functionality needed to parse an XML document to be imported into
35   * an ITracker instance, into a set of data models.
36   */
37  public class ImportHandler extends DefaultHandler implements ImportExportTags {
38  
39      private final Logger logger;
40      private List<AbstractEntity> items;
41      private StringBuffer tagBuffer;
42      private SAXException endException;
43  
44      private AbstractEntity parentModel;
45      private AbstractEntity childModel;
46      private List<Object> itemList;
47      private String tempStorage;
48  
49      public ImportHandler() {
50          this.logger = Logger.getLogger(getClass());
51          this.items = new ArrayList<>();
52          this.endException = null;
53      }
54  
55      public AbstractEntity[] getModels() {
56          return items.toArray(new AbstractEntity[items.size()]);
57      }
58  
59      @Override
60      public void startDocument() {
61          logger.debug("Started import xml parsing.");
62      }
63  
64      @Override
65      public void endDocument() {
66          logger.debug("Completed import xml parsing.");
67      }
68  
69      @Override
70      public void startElement(String uri, String name, String qName, Attributes atts) throws SAXException {
71          logger.debug("Parsing import tag " + qName);
72  
73          if (endException != null) {
74              throw endException;
75          }
76  
77  
78          tempStorage = "";
79          try {
80              if (TAG_COMPONENT.equals(qName)) {
81                  String id = atts.getValue(ATTR_SYSTEMID);
82                  if (id == null) {
83                      throw new SAXException("Attribute " + ATTR_SYSTEMID + " was null for component.");
84                  }
85  
86                  // FIXME: pass component name instead of import/export ID. 
87                  childModel = new Component((Project) parentModel, atts.getValue(ATTR_ID));
88                  childModel.setId(new Integer(id));
89              } else if (TAG_COMPONENTS.equals(qName)) {
90                  itemList = new ArrayList<>();
91              } else if (TAG_CONFIGURATION.equals(qName)) {
92                  parentModel = new SystemConfiguration();
93              } else if (TAG_CUSTOM_FIELD.equals(qName)) {
94                  String id = atts.getValue(ATTR_SYSTEMID);
95                  if (id == null) {
96                      throw new SAXException("Attribute " + ATTR_SYSTEMID + " was null for issue.");
97                  }
98  
99                  childModel = new CustomField();
100                 childModel.setId(new Integer(id));
101             } else if (TAG_CUSTOM_FIELD_OPTION.equals(qName)) {
102                 tempStorage = ITrackerResources.unescapeUnicodeString(atts.getValue(ATTR_VALUE));
103             } else if (TAG_CUSTOM_FIELDS.equals(qName)) {
104                 itemList = new ArrayList<>();
105             } else if (TAG_HISTORY_ENTRY.equals(qName)) {
106                 String creatorId = atts.getValue(ATTR_CREATOR_ID);
107                 String date = atts.getValue(ATTR_DATE);
108                 String status = atts.getValue(ATTR_STATUS);
109                 if (creatorId == null) {
110                     throw new SAXException("Attribute " + ATTR_CREATOR_ID + " was null for issue history.");
111                 } else if (date == null) {
112                     throw new SAXException("Attribute date was null for issue history.");
113                 }
114 
115                 childModel = new IssueHistory();
116                 ((IssueHistory) childModel).setUser((User) findModel(creatorId));
117                 ((IssueHistory) childModel).setStatus(status != null && !status.equals("") ? Integer.parseInt(status) : IssueUtilities.HISTORY_STATUS_AVAILABLE);
118                 childModel.setCreateDate(getDateValue(date, qName));
119                 tagBuffer = new StringBuffer();
120             } else if (TAG_ISSUE.equals(qName)) {
121                 String id = atts.getValue(ATTR_SYSTEMID);
122                 if (id == null) {
123                     throw new SAXException("Attribute " + ATTR_SYSTEMID + " was null for issue.");
124                 }
125 
126                 parentModel = new Issue();
127                 parentModel.setId(new Integer(id));
128             } else if (TAG_ISSUE_ATTACHMENT.equals(qName)) {
129                 childModel = new IssueAttachment();
130             } else if (TAG_ISSUE_ATTACHMENTS.equals(qName)) {
131                 itemList = new ArrayList<Object>();
132             } else if (TAG_ISSUE_COMPONENTS.equals(qName)) {
133                 itemList = new ArrayList<Object>();
134             } else if (TAG_ISSUE_FIELD.equals(qName)) {
135                 String id = atts.getValue(ATTR_ID);
136                 if (id == null) {
137                     throw new SAXException("Attribute " + ATTR_SYSTEMID + " was null for issue field.");
138                 }
139                 childModel = new IssueField((Issue) parentModel, (CustomField) findModel(id));
140             } else if (TAG_ISSUE_FIELDS.equals(qName)) {
141                 itemList = new ArrayList<>();
142             } else if (TAG_ISSUE_HISTORY.equals(qName)) {
143                 itemList = new ArrayList<>();
144             } else if (TAG_ISSUE_VERSIONS.equals(qName)) {
145                 itemList = new ArrayList<>();
146             } else if (TAG_PROJECT.equals(qName)) {
147                 String id = atts.getValue(ATTR_SYSTEMID);
148                 if (id == null) {
149                     throw new SAXException("Attribute " + ATTR_SYSTEMID + " was null for project.");
150                 }
151 
152                 parentModel = new Project();
153                 parentModel.setId(new Integer(id));
154             } else if (TAG_PROJECT_FIELDS.equals(qName)) {
155                 itemList = new ArrayList<>();
156             } else if (TAG_PROJECT_OWNERS.equals(qName)) {
157                 itemList = new ArrayList<>();
158             } else if (TAG_RESOLUTION.equals(qName)) {
159                 String value = atts.getValue(ATTR_VALUE);
160                 String order = atts.getValue(ATTR_ORDER);
161 
162                 childModel = new Configuration(Configuration.Type.resolution, value, Integer.parseInt(order));
163                 tagBuffer = new StringBuffer();
164             } else if (TAG_SEVERITY.equals(qName)) {
165                 String value = atts.getValue(ATTR_VALUE);
166                 String order = atts.getValue(ATTR_ORDER);
167 
168                 childModel = new Configuration(Configuration.Type.severity, value, Integer.parseInt(order));
169                 tagBuffer = new StringBuffer();
170             } else if (TAG_STATUS.equals(qName)) {
171                 String value = atts.getValue(ATTR_VALUE);
172                 String order = atts.getValue(ATTR_ORDER);
173 
174                 childModel = new Configuration(Configuration.Type.status, value, Integer.parseInt(order));
175                 tagBuffer = new StringBuffer();
176             } else if (TAG_USER.equals(qName)) {
177                 String id = atts.getValue(ATTR_SYSTEMID);
178                 if (id == null) {
179                     throw new SAXException("Attribute " + ATTR_SYSTEMID + " was null for user.");
180                 }
181 
182                 parentModel = new User();
183                 parentModel.setId(new Integer(id));
184             } else if (TAG_VERSION.equals(qName)) {
185                 String id = atts.getValue(ATTR_SYSTEMID);
186                 if (id == null) {
187                     throw new SAXException("Attribute " + ATTR_SYSTEMID + " was null for version.");
188                 }
189 
190                 // FIXME: pass version number instead of import/export ID. 
191                 childModel = new Version((Project) parentModel, atts.getValue(ATTR_ID));
192                 childModel.setId(new Integer(id));
193             } else if (TAG_VERSIONS.equals(qName)) {
194                 itemList = new ArrayList<>();
195             } else {
196                 tagBuffer = new StringBuffer();
197             }
198         } catch (NumberFormatException nfe) {
199             throw new SAXException("Attribute in " + qName + " did not contain a numeric value.");
200         }
201     }
202 
203     @Override
204     public void endElement(String uri, String name, String qName) throws SAXException {
205         logger.debug("Completing import tag " + qName);
206 
207         try {
208             if (TAG_ISSUE.equals(qName) || TAG_PROJECT.equals(qName) || TAG_USER.equals(qName) || TAG_CONFIGURATION.equals(qName)) {
209                 items.add((AbstractEntity) parentModel.clone());
210                 parentModel = null;
211                 childModel = null;
212                 itemList = null;
213             } else if (TAG_RESOLUTION.equals(qName) || TAG_SEVERITY.equals(qName) || TAG_STATUS.equals(qName)) {
214                 ((Configuration) childModel).setName(getBuffer());
215                 items.add((AbstractEntity) childModel.clone());
216                 ((SystemConfiguration) parentModel).addConfiguration((Configuration) childModel);
217                 childModel = null;
218             } else if (TAG_COMPONENT.equals(qName) || TAG_VERSION.equals(qName) || TAG_CUSTOM_FIELD.equals(qName)) {
219                 // Add to both so we can search the the models for components, customfields, and versions later
220                 // Make sure they are double added when processed
221                 items.add((AbstractEntity) childModel.clone());
222                 itemList.add(childModel.clone());
223                 childModel = null;
224             } else if (TAG_HISTORY_ENTRY.equals(qName)) {
225                 ((IssueHistory) childModel).setDescription(getBuffer());
226                 itemList.add(childModel.clone());
227                 childModel = null;
228             } else if (TAG_ISSUE_ATTACHMENT.equals(qName)) {
229                 itemList.add(childModel.clone());
230                 childModel = null;
231             } else if (TAG_ISSUE_FIELD.equals(qName)) {
232                 itemList.add(childModel.clone());
233                 childModel = null;
234             } else if (TAG_COMPONENTS.equals(qName)) {
235                 List<Component> itemListArray = new ArrayList<>();
236                 for (Object anItemList : itemList) {
237                     itemListArray.add((Component) anItemList);
238                 }
239                 ((Project) parentModel).setComponents(itemListArray);
240             } else if (TAG_COMPONENT_DESCRIPTION.equals(qName)) {
241                 ((Component) childModel).setDescription(getBuffer());
242             } else if (TAG_COMPONENT_ID.equals(qName)) {
243                 if (itemList == null) {
244                     itemList = new ArrayList<>();
245                 }
246                 itemList.add(findModel(getBuffer()));
247             } else if (TAG_COMPONENT_NAME.equals(qName)) {
248                 ((Component) childModel).setName(getBuffer());
249             } else if (TAG_CONFIGURATION_VERSION.equals(qName)) {
250                 ((SystemConfiguration) parentModel).setVersion(getBuffer());
251             } else if (TAG_CREATE_DATE.equals(qName)) {
252                 parentModel.setCreateDate(getDateValue(getBuffer(), qName));
253             } else if (TAG_CREATOR.equals(qName)) {
254                 ((Issue) parentModel).setCreator((User) findModel(getBuffer()));
255             } else if (TAG_CUSTOM_FIELDS.equals(qName)) {
256                 List<CustomField> itemListArray = new ArrayList<>();
257                 for (Object anItemList : itemList) {
258                     itemListArray.add((CustomField) anItemList);
259                 }
260                 ((SystemConfiguration) parentModel).setCustomFields(itemListArray);
261             } else if (TAG_CUSTOM_FIELD_DATEFORMAT.equals(qName)) {
262                 ((CustomField) childModel).setDateFormat(getBuffer());
263             } else if (TAG_CUSTOM_FIELD_LABEL.equals(qName)) {
264 //                ((CustomField) childModel).setName(getBuffer());
265 //            	TODO handle configuration for setting the BASE label
266             } else if (TAG_CUSTOM_FIELD_OPTION.equals(qName)) {
267                 ((CustomField) childModel).addOption(tempStorage, getBuffer());
268             } else if (TAG_CUSTOM_FIELD_REQUIRED.equals(qName)) {
269                 ((CustomField) childModel).setRequired(("true".equalsIgnoreCase(getBuffer())));
270             } else if (TAG_CUSTOM_FIELD_SORTOPTIONS.equals(qName)) {
271                 ((CustomField) childModel).setSortOptionsByName(("true".equalsIgnoreCase(getBuffer())));
272             } else if (TAG_CUSTOM_FIELD_TYPE.equals(qName)) {
273                 final String s = getBuffer();
274                 try {
275                     // fallback for old export type as int-code
276                     int i = Integer.valueOf(s);
277                     ((CustomField) childModel).setFieldType(CustomField.Type.valueOf(i));
278                 } catch (RuntimeException e) {
279                     try {
280                         ((CustomField) childModel).setFieldType(CustomField.Type.valueOf(s));
281                     } catch (RuntimeException re) {
282                         throw new SAXException("Could not convert string buffer to type value.");
283                     }
284                 }
285             } else if (TAG_EMAIL.equals(qName)) {
286                 ((User) parentModel).setEmail(getBuffer());
287             } else if (TAG_FIRST_NAME.equals(qName)) {
288                 ((User) parentModel).setFirstName(getBuffer());
289             } else if (TAG_ISSUE_ATTACHMENTS.equals(qName)) {
290                 List<IssueAttachment> itemListArray = new ArrayList<>();
291                 for (Object anItemList : itemList) {
292                     itemListArray.add((IssueAttachment) anItemList);
293                 }
294                 ((Issue) parentModel).setAttachments(itemListArray);
295             } else if (TAG_ISSUE_ATTACHMENT_CREATOR.equals(qName)) {
296                 ((IssueAttachment) childModel).setUser((User) findModel(getBuffer()));
297             } else if (TAG_ISSUE_ATTACHMENT_DESCRIPTION.equals(qName)) {
298                 ((IssueAttachment) childModel).setDescription(getBuffer());
299             } else if (TAG_ISSUE_ATTACHMENT_FILENAME.equals(qName)) {
300                 ((IssueAttachment) childModel).setFileName(getBuffer());
301             } else if (TAG_ISSUE_ATTACHMENT_ORIGFILE.equals(qName)) {
302                 ((IssueAttachment) childModel).setOriginalFileName(getBuffer());
303             } else if (TAG_ISSUE_ATTACHMENT_SIZE.equals(qName)) {
304                 ((IssueAttachment) childModel).setSize(getBufferAsLong());
305             } else if (TAG_ISSUE_ATTACHMENT_TYPE.equals(qName)) {
306                 ((IssueAttachment) childModel).setType(getBuffer());
307             } else if (TAG_ISSUE_COMPONENTS.equals(qName)) {
308                 List<Component> itemListArray = new ArrayList<>();
309                 for (Object anItemList : itemList) {
310                     itemListArray.add((Component) anItemList);
311                 }
312                 ((Issue) parentModel).setComponents(itemListArray);
313             } else if (TAG_ISSUE_DESCRIPTION.equals(qName)) {
314                 ((Issue) parentModel).setDescription(getBuffer());
315             } else if (TAG_ISSUE_FIELDS.equals(qName)) {
316                 List<IssueField> itemListArray = new ArrayList<>();
317                 for (int i = 0; i < itemList.size(); i++) {
318                     itemListArray.add(i, (IssueField) itemList.get(i));
319                 }
320                 ((Issue) parentModel).setFields(itemListArray);
321             } else if (TAG_ISSUE_HISTORY.equals(qName)) {
322                 List<IssueHistory> itemListArray = new ArrayList<>();
323                 for (int i = 0; i < itemList.size(); i++) {
324                     itemListArray.add(i, (IssueHistory) itemList.get(i));
325                 }
326                 ((Issue) parentModel).setHistory(itemListArray);
327             } else if (TAG_ISSUE_PROJECT.equals(qName)) {
328                 ((Issue) parentModel).setProject((Project) findModel(getBuffer()));
329             } else if (TAG_ISSUE_RESOLUTION.equals(qName)) {
330                 ((Issue) parentModel).setResolution(getBuffer());
331             } else if (TAG_ISSUE_SEVERITY.equals(qName)) {
332                 ((Issue) parentModel).setSeverity(getBufferAsInt());
333             } else if (TAG_ISSUE_STATUS.equals(qName)) {
334                 ((Issue) parentModel).setStatus(getBufferAsInt());
335             } else if (TAG_ISSUE_VERSIONS.equals(qName)) {
336                 List<Version> itemListArray = new ArrayList<>();
337                 for (int i = 0; i < itemList.size(); i++) {
338                     itemListArray.add(i, (Version) itemList.get(i));
339                 }
340                 ((Issue) parentModel).setVersions(itemListArray);
341             } else if (TAG_LAST_MODIFIED.equals(qName)) {
342                 parentModel.setLastModifiedDate(getDateValue(getBuffer(), qName));
343             } else if (TAG_LAST_NAME.equals(qName)) {
344                 ((User) parentModel).setLastName(getBuffer());
345             } else if (TAG_LOGIN.equals(qName)) {
346                 ((User) parentModel).setLogin(getBuffer());
347             } else if (TAG_OWNER.equals(qName)) {
348                 ((Issue) parentModel).setOwner((User) findModel(getBuffer()));
349             } else if (TAG_PROJECT_NAME.equals(qName)) {
350                 ((Project) parentModel).setName(getBuffer());
351             } else if (TAG_PROJECT_DESCRIPTION.equals(qName)) {
352                 ((Project) parentModel).setDescription(getBuffer());
353             } else if (TAG_PROJECT_FIELDS.equals(qName)) {
354                 List<CustomField> itemListArray = new ArrayList<>();
355                 for (int i = 0; i < itemList.size(); i++) {
356                     itemListArray.add(i, (CustomField) itemList.get(i));
357                 }
358                 ((Project) parentModel).setCustomFields(itemListArray);
359             } else if (TAG_PROJECT_FIELD_ID.equals(qName)) {
360                 itemList.add(findModel(getBuffer()));
361             } else if (TAG_PROJECT_OPTIONS.equals(qName)) {
362                 ((Project) parentModel).setOptions(getBufferAsInt());
363             } else if (TAG_PROJECT_OWNERS.equals(qName)) {
364                 List<User> itemListArray = new ArrayList<>();
365                 for (int i = 0; i < itemList.size(); i++) {
366                     itemListArray.add(i, (User) itemList.get(i));
367                 }
368                 ((Project) parentModel).setOwners(itemListArray);
369             } else if (TAG_PROJECT_OWNER_ID.equals(qName)) {
370                 itemList.add(findModel(getBuffer()));
371             } else if (TAG_PROJECT_STATUS.equals(qName)) {
372                 // By default activate the project
373                 ((Project) parentModel).setStatus(Status.ACTIVE);
374                 try {
375                     ((Project) parentModel).setStatus(Status.valueOf(getBuffer().toUpperCase()));
376                 } catch (RuntimeException re) {
377                     // ok, it is active.
378                 }
379             } else if (TAG_SUPER_USER.equals(qName)) {
380                 ((User) parentModel).setSuperUser(("true".equalsIgnoreCase(getBuffer())));
381             } else if (TAG_TARGET_VERSION_ID.equals(qName)) {
382                 ((Issue) parentModel).setTargetVersion((Version) findModel(getBuffer()));
383             } else if (TAG_USER_STATUS.equals(qName)) {
384                 // By default lock the user
385                 ((User) parentModel).setStatus(UserUtilities.STATUS_LOCKED);
386                 // TODO: Make status Enum
387                 String currBuffer = getBuffer();
388                 try {
389                     ((User)parentModel).setStatus(Integer.parseInt(currBuffer));
390                 } catch (RuntimeException re) {
391                     HashMap<String, String> userStatuses = UserUtilities.getStatusNames(EXPORT_LOCALE);
392                     for (String key : userStatuses.keySet()) {
393                         String keyValue = userStatuses.get(key);
394                         if (keyValue != null && keyValue.equalsIgnoreCase(currBuffer)) {
395                             ((User) parentModel).setStatus(Integer.parseInt(key));
396                             break;
397                         }
398                     }
399                 }
400             } else if (TAG_VERSIONS.equals(qName)) {
401                 List<Version> itemListArray = new ArrayList<>();
402                 for (int i = 0; i < itemList.size(); i++) {
403                     itemListArray.add(i, (Version) itemList.get(i));
404                 }
405                 ((Project) parentModel).setVersions(itemListArray);
406             } else if (TAG_VERSION_DESCRIPTION.equals(qName)) {
407                 ((Version) childModel).setDescription(getBuffer());
408             } else if (TAG_VERSION_ID.equals(qName)) {
409                 if (itemList == null) {
410                     itemList = new ArrayList<>();
411                 }
412                 itemList.add(findModel(getBuffer()));
413             } else if (TAG_VERSION_NUMBER.equals(qName)) {
414                 ((Version) childModel).setVersionInfo(getBuffer());
415             }
416         } catch (RuntimeException e) {
417             logger.debug("endElement: RuntimeException importing data.", e);
418             endException = new SAXException("Error processing tag " + qName + ": " + e.getMessage());
419             throw endException;
420         } catch (SAXException e) {
421             logger.debug("endElement: SAXException importing data.", e);
422             throw e;
423         } catch (CloneNotSupportedException e) {
424             logger.debug("endElement: CloneNotSupportedException importing data.", e);
425             endException = new SAXException("Error processing tag " + qName + ": " + e.getMessage());
426             throw endException;
427         }
428         tagBuffer = null;
429     }
430 
431     @Override
432     public void characters(char[] ch, int start, int length) {
433         logger.debug("Read " + ch.length + " Start: " + start + " Length: " + length);
434         logger.debug("String: " + new String(ch, start, length));
435         if (tagBuffer != null) {
436             tagBuffer.append(ITrackerResources.unescapeUnicodeString(new String(ch, start, length)));
437         }
438     }
439 
440     private String getBuffer() {
441         if (tagBuffer == null) {
442             return "";
443         } else {
444             return tagBuffer.toString();
445         }
446     }
447 
448     private int getBufferAsInt() throws SAXException {
449         if (tagBuffer == null) {
450             return -1;
451         } else {
452             try {
453                 return Integer.parseInt(tagBuffer.toString());
454             } catch (NumberFormatException nfe) {
455                 throw new SAXException("Could not convert string buffer to int value.");
456             }
457         }
458     }
459 
460     private long getBufferAsLong() throws SAXException {
461         if (tagBuffer == null) {
462             return -1;
463         } else {
464             try {
465                 return Long.parseLong(tagBuffer.toString());
466             } catch (NumberFormatException nfe) {
467                 throw new SAXException("Could not convert string buffer to long value.");
468             }
469         }
470     }
471 
472     private AbstractEntity findModel(String itemTypeId) {
473         if (itemTypeId != null && !itemTypeId.equals("")) {
474             for (AbstractEntity model : items) {
475                 if (getModelTypeIdString(model).equalsIgnoreCase(itemTypeId)) {
476                     return model;
477                 }
478             }
479         }
480         logger.debug("Unable to find model id " + itemTypeId + " during import.");
481         return null;
482     }
483 
484     private String getModelTypeIdString(AbstractEntity model) {
485         String idString = "UNKNOWN";
486 
487         if (model != null && model.getId() != null) {
488             String type = "";
489             if (model instanceof Component) {
490                 type = TAG_COMPONENT;
491             } else if (model instanceof CustomField) {
492                 type = TAG_CUSTOM_FIELD;
493             } else if (model instanceof Issue) {
494                 type = TAG_ISSUE;
495             } else if (model instanceof Project) {
496                 type = TAG_PROJECT;
497             } else if (model instanceof User) {
498                 type = TAG_USER;
499             } else if (model instanceof Version) {
500                 type = TAG_VERSION;
501             }
502 
503             idString = type + model.getId();
504         }
505 
506         return idString;
507     }
508 
509     private Date getDateValue(String dateString, String qName) throws SAXException {
510         if (dateString == null || "".equals(dateString)) {
511             return new Date();
512         }
513 
514         try {
515             return DATE_FORMATTER.parse(dateString);
516         } catch (Exception e) {
517             throw new SAXException("Value in " + qName + " did not contain a valid date value.");
518         }
519     }
520 }