001    package org.hackystat.dailyprojectdata.resource.issue;
002    
003    import java.util.Arrays;
004    import java.util.List;
005    import java.util.logging.Logger;
006    import javax.xml.datatype.XMLGregorianCalendar;
007    import org.hackystat.dailyprojectdata.resource.issue.jaxb.IssueData;
008    import org.hackystat.sensorbase.resource.sensordata.jaxb.Property;
009    import org.hackystat.sensorbase.resource.sensordata.jaxb.SensorData;
010    import org.hackystat.utilities.tstamp.Tstamp;
011    
012    /**
013     * Parser for the issue sensordata to IssueData.
014     * @author Shaoxuan Zhang
015     *
016     */
017    public class IssueDataParser {
018    
019      //static String copied from org.hackystat.sensor.ant.issue.IssueEntry
020      /** property key of ID. */
021      protected static final String ID_PROPERTY_KEY = "Id";
022      /** property key of TYPE. */
023      protected static final String TYPE_PROPERTY_KEY = "Type";
024      /** property key of STATUS. */
025      protected static final String STATUS_PROPERTY_KEY = "Status";
026      /** property key of PRIORITY. */
027      protected static final String PRIORITY_PROPERTY_KEY = "Priority";
028      /** property key of MILESTONE. */
029      protected static final String MILESTONE_PROPERTY_KEY = "Milestone";
030      /** property key of OWNER. */
031      protected static final String OWNER_PROPERTY_KEY = "Owner";
032    
033      /** timestamp separator in property value. */
034      protected static final String TIMESTAMP_SEPARATOR = "--";
035      
036      private Logger logger;
037      private List<String> openIssueStatus = Arrays.asList(new String[]{"New", "Accepted", "Started"});
038      
039      /**
040       * @param logger the logger.
041       */
042      public IssueDataParser(final Logger logger) {
043        this.logger = logger;
044      }
045      
046      /**
047       * Determine if the status value means open.
048       * @param statusValue the status value.
049       * @return true if it is open.
050       */
051      public boolean isOpenStatus(String statusValue) {
052        return statusValue != null && openIssueStatus.contains(statusValue);
053      }
054      
055      /**
056       * Get the state of the issue on the given time.
057       * @param issueSensorData the given sensordata.
058       * @param timestamp the time.
059       * @return the IssueData.
060       */
061      public IssueData getIssueDpd(SensorData issueSensorData, final XMLGregorianCalendar timestamp) {
062        IssueData issueDpd = new IssueData();
063    
064        //get id
065        for (Property property : issueSensorData.getProperties().getProperty()) {
066          if (ID_PROPERTY_KEY.equals(property.getKey())) {
067            issueDpd.setId(Integer.valueOf(property.getValue()));
068            break;
069          }
070        }
071        
072        //get latest type
073        issueDpd.setType(this.getValueWithKeyWhen(issueSensorData, TYPE_PROPERTY_KEY, timestamp));
074        
075        //get latest status
076        issueDpd.setStatus(this.getValueWithKeyWhen(issueSensorData, STATUS_PROPERTY_KEY, timestamp));
077        
078        //get latest priority
079        issueDpd.setPriority(
080            this.getValueWithKeyWhen(issueSensorData, PRIORITY_PROPERTY_KEY, timestamp));
081        
082        //get latest milestone
083        issueDpd.setMilestone(
084            this.getValueWithKeyWhen(issueSensorData, MILESTONE_PROPERTY_KEY, timestamp));
085        
086        //get latest owner
087        issueDpd.setOwner(this.getValueWithKeyWhen(issueSensorData, OWNER_PROPERTY_KEY, timestamp));
088        
089        return issueDpd;
090      }
091    
092      /**
093       * Return the value with the given key in the given time within the given sensordata.
094       * @param issueSensorData the sensordata.
095       * @param key the property key
096       * @param timestamp the time.
097       * @return the latest value, null if not found.
098       */
099      public String getValueWithKeyWhen(SensorData issueSensorData, String key, 
100          XMLGregorianCalendar timestamp) {
101        XMLGregorianCalendar latestTime = null;
102        String value = null;
103        for (Property property : issueSensorData.getProperties().getProperty()) {
104          if (key.equals(property.getKey())) {
105            XMLGregorianCalendar newTimestamp = null;
106            try {
107              newTimestamp = extractTimestamp(property.getValue());
108            }
109            catch (Exception e) {
110              logger.warning("Error when extracting timestamp from [" + property.getValue() + "]");
111            }
112            if (newTimestamp != null && !Tstamp.greaterThan(newTimestamp, timestamp) && 
113                (latestTime == null || Tstamp.lessThan(latestTime, newTimestamp))) {
114              latestTime = newTimestamp;
115              value = extractValue(property.getValue());
116            }
117          }
118        }
119        return value;
120      }
121    
122      /**
123       * Extract timestamp from formatted string.
124       * @param value the string.
125       * @return the timestamp.
126       * @throws Exception if the string is not formatted.
127       */
128      private static XMLGregorianCalendar extractTimestamp(String value) throws Exception {
129        int startIndex = value.indexOf(TIMESTAMP_SEPARATOR) + TIMESTAMP_SEPARATOR.length();
130        return Tstamp.makeTimestamp(value.substring(startIndex));
131      }
132    
133      /**
134       * Extract value from formatted string.
135       * @param string the string.
136       * @return the value.
137       */
138      private static String extractValue(String string) {
139        return string.substring(0, string.indexOf(TIMESTAMP_SEPARATOR));
140      }
141    }