001: package com.technoetic.xplanner.metrics;
002:
003: import com.technoetic.xplanner.db.hibernate.ThreadSession;
004: import com.technoetic.xplanner.domain.Iteration;
005: import com.technoetic.xplanner.domain.Task;
006: import com.technoetic.xplanner.domain.UserStory;
007: import com.technoetic.xplanner.domain.repository.ObjectRepository;
008: import com.technoetic.xplanner.domain.repository.RepositoryException;
009: import com.technoetic.xplanner.security.AuthenticationException;
010: import net.sf.hibernate.HibernateException;
011: import net.sf.hibernate.Session;
012: import org.apache.log4j.Logger;
013:
014: import java.util.ArrayList;
015: import java.util.Collection;
016: import java.util.Collections;
017: import java.util.Comparator;
018: import java.util.Date;
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: public class IterationMetrics {
024: private Logger log = Logger.getLogger(getClass());
025: protected HashMap developerMetrics = new HashMap();
026: private double totalHours;
027: private double totalPairedHours;
028: private int iterationId;
029: private String iterationName = null;
030: private double maxDeveloperHours;
031: protected HashMap names = new HashMap();
032: public static final int UNASSIGNED_ID = 0;
033: public static final String UNASSIGNED_NAME = "Unassigned";
034: private Session session;
035: private ObjectRepository iterationRepository;
036:
037: public void setIterationId(int iterationId) {
038: this .iterationId = iterationId;
039: }
040:
041: public void analyze() {
042: //DEBT Spring load
043: session = ThreadSession.get();
044: try {
045: try {
046: names.clear();
047: developerMetrics.clear();
048: getNamesMap(session);
049: calculateDeveloperMetrics();
050: getHoursWorked(session, "iterationHoursWorkedQuery",
051: names);
052: } catch (Exception ex) {
053: if (session.isConnected()) {
054: session.connection().rollback();
055: }
056: log.error("error", ex);
057: }
058: } catch (Exception ex) {
059: log.error("error", ex);
060: }
061: }
062:
063: public void calculateDeveloperMetrics() throws HibernateException,
064: AuthenticationException, RepositoryException {
065: Iteration iteration = getIterationObject();
066: Collection stories = iteration.getUserStories();
067: getMetricsData(stories);
068: }
069:
070: protected Iteration getIterationObject() throws HibernateException,
071: AuthenticationException, RepositoryException {
072: ObjectRepository repository = getIterationRepository();
073: return (Iteration) repository.load(getIterationId());
074: }
075:
076: protected HashMap getMetricsData(Collection stories) {
077: for (Iterator iterator = stories.iterator(); iterator.hasNext();) {
078: UserStory story = (UserStory) iterator.next();
079: Collection tasks = story.getTasks();
080: if (tasks.isEmpty()) {
081: assignHoursToUser(story.getTrackerId(), story
082: .getEstimatedHours(), true);
083: } else {
084: for (Iterator iterator1 = tasks.iterator(); iterator1
085: .hasNext();) {
086: Task task = (Task) iterator1.next();
087: assignHoursToUser(task.getAcceptorId(), task
088: .getEstimatedHours(), false);
089: }
090: }
091: }
092: return developerMetrics;
093: }
094:
095: protected void assignHoursToUser(int personId,
096: double estimatedHours, boolean isStoryHour) {
097: if (estimatedHours == 0) {
098: return;
099: }
100: DeveloperMetrics developerMetrics = getDeveloperMetrics(
101: getName(personId), personId, iterationId);
102: if (isStoryHour) {
103: double prevAcceptedStoryHours = developerMetrics
104: .getAcceptedStoryHours();
105: developerMetrics
106: .setAcceptedStoryHours(prevAcceptedStoryHours
107: + estimatedHours);
108: } else {
109: double prevAcceptedTaskHours = developerMetrics
110: .getAcceptedTaskHours();
111: developerMetrics.setAcceptedTaskHours(prevAcceptedTaskHours
112: + estimatedHours);
113: }
114: }
115:
116: protected void getNamesMap(Session session)
117: throws HibernateException {
118: List nameResults = session.getNamedQuery("namesQuery").list();
119: Iterator iter = nameResults.iterator();
120: while (iter.hasNext()) {
121: Object[] result = (Object[]) iter.next();
122: names.put(result[1], result[0]);
123: }
124: addUnassignedName();
125: }
126:
127: protected void addUnassignedName() {
128: names.put(new Integer(UNASSIGNED_ID), UNASSIGNED_NAME);
129: }
130:
131: protected String getName(int personId) {
132: return (String) names.get(new Integer(personId));
133: }
134:
135: void getHoursWorked(Session session, String hoursQuery,
136: HashMap names) throws HibernateException {
137: totalHours = 0.0;
138: totalPairedHours = 0.0;
139: maxDeveloperHours = 0.0;
140: List hoursResults = session.getNamedQuery(hoursQuery)
141: .setInteger("iterationId", iterationId).list();
142: Iterator hoursIterator = hoursResults.iterator();
143: while (hoursIterator.hasNext()) {
144: Object[] result = (Object[]) hoursIterator.next();
145: int person1Id = toInt(result[0]);
146: int person2Id = toInt(result[1]);
147: Date startTime = (Date) result[2];
148: Date endTime = (Date) result[3];
149: double duration = toDouble(result[4]);
150: int trackerId = toInt(result[5]);
151: if ((endTime != null && startTime != null) || duration != 0) {
152: double hours = duration == 0 ? (endTime.getTime() - startTime
153: .getTime()) / 3600000.0
154: : duration;
155: boolean isPaired = person1Id != 0 && person2Id != 0;
156: if (person1Id != 0) {
157: boolean isOwnTask = person1Id == trackerId;
158: updateWorkedHours(iterationId, (String) names
159: .get(result[0]), person1Id, hours,
160: isPaired, isOwnTask);
161: totalHours += hours;
162: }
163: if (person2Id != 0) {
164: boolean isOwnTask = person2Id == trackerId;
165: updateWorkedHours(iterationId, (String) names
166: .get(result[1]), person2Id, hours,
167: isPaired, isOwnTask);
168: totalHours += hours;
169: }
170: if (isPaired) {
171: totalPairedHours += hours;
172: }
173: }
174: }
175: }
176:
177: private int toInt(Object object) {
178: return ((Integer) object).intValue();
179: }
180:
181: private double toDouble(Object object) {
182: return object != null ? ((Double) object).doubleValue() : 0;
183: }
184:
185: protected DeveloperMetrics getDeveloperMetrics(String name, int id,
186: int iterationId) {
187: DeveloperMetrics dm = (DeveloperMetrics) developerMetrics
188: .get(name);
189: if (dm == null) {
190: dm = new DeveloperMetrics();
191: dm.setId(id);
192: dm.setName(name);
193: dm.setIterationId(iterationId);
194: developerMetrics.put(name, dm);
195: }
196: return dm;
197: }
198:
199: private void updateWorkedHours(int iterationId, String name,
200: int id, double hours, boolean isPaired, boolean isOwnTask) {
201: DeveloperMetrics dm = getDeveloperMetrics(name, id, iterationId);
202: dm.setHours(dm.getHours() + hours);
203: if (isOwnTask)
204: dm.setOwnTasksWorkedHours(dm.getOwnTaskHours() + hours);
205: if (dm.getHours() > maxDeveloperHours) {
206: maxDeveloperHours = dm.getHours();
207: }
208: if (isPaired) {
209: dm.setPairedHours(dm.getPairedHours() + hours);
210: }
211: }
212:
213: public double getTotalHours() {
214: return totalHours;
215: }
216:
217: public double getTotalPairedHours() {
218: return totalPairedHours;
219: }
220:
221: public double getTotalPairedPercentage() {
222: double result = (totalPairedHours * 100)
223: / (totalHours - totalPairedHours);
224: if (Double.isNaN(result))
225: result = 0.0;
226: return result;
227: }
228:
229: public void setTotalHours(double totalHours) {
230: this .totalHours = totalHours;
231: }
232:
233: public void setTotalPairedHours(double totalPairedHours) {
234: this .totalPairedHours = totalPairedHours;
235: }
236:
237: public Collection getDeveloperTotalTime() {
238: ArrayList metrics = new ArrayList(developerMetrics.values());
239: Collections.sort(metrics, new Comparator() {
240: public int compare(Object object1, Object object2) {
241: DeveloperMetrics dm1 = (DeveloperMetrics) object1;
242: DeveloperMetrics dm2 = (DeveloperMetrics) object2;
243: return (dm1.getHours() < dm2.getHours()) ? 1 : (dm1
244: .getHours() == dm2.getHours() ? 0 : -1);
245: }
246: });
247: return metrics;
248: }
249:
250: public Collection getDeveloperOwnTasksWorkedTime() {
251: ArrayList metrics = new ArrayList(developerMetrics.values());
252: Collections.sort(metrics, new Comparator() {
253: public int compare(Object object1, Object object2) {
254: DeveloperMetrics dm1 = (DeveloperMetrics) object1;
255: DeveloperMetrics dm2 = (DeveloperMetrics) object2;
256: return (dm1.getOwnTaskHours() < dm2.getOwnTaskHours()) ? 1
257: : (dm1.getOwnTaskHours() == dm2
258: .getOwnTaskHours() ? 0 : -1);
259: }
260: });
261: return metrics;
262: }
263:
264: public double getMaxTotalTime() {
265: double maxTotalTime = 0;
266: Iterator itr = developerMetrics.values().iterator();
267: while (itr.hasNext()) {
268: double hours = ((DeveloperMetrics) itr.next()).getHours();
269: if (hours > maxTotalTime) {
270: maxTotalTime = hours;
271: }
272: }
273: return maxTotalTime;
274: }
275:
276: public Collection getDeveloperAcceptedTime() {
277: ArrayList metrics = new ArrayList(developerMetrics.values());
278: Collections.sort(metrics, new Comparator() {
279: public int compare(Object object1, Object object2) {
280: DeveloperMetrics dm1 = (DeveloperMetrics) object1;
281: DeveloperMetrics dm2 = (DeveloperMetrics) object2;
282: return (dm1.getAcceptedHours() < dm2.getAcceptedHours()) ? 1
283: : (dm1.getAcceptedHours() == dm2
284: .getAcceptedHours() ? 0 : -1);
285: }
286: });
287: return metrics;
288: }
289:
290: public double getMaxAcceptedTime() {
291: double maxAcceptedTime = 0;
292: Iterator itr = developerMetrics.values().iterator();
293: while (itr.hasNext()) {
294: double hours = ((DeveloperMetrics) itr.next())
295: .getAcceptedHours();
296: if (hours > maxAcceptedTime) {
297: maxAcceptedTime = hours;
298: }
299: }
300: return maxAcceptedTime;
301: }
302:
303: public int getIterationId() {
304: return iterationId;
305: }
306:
307: public String getIterationName() {
308: return iterationName;
309: }
310:
311: public void analyze(int iterationId) {
312: setIterationId(iterationId);
313: analyze();
314: }
315:
316: private ObjectRepository getIterationRepository() {
317: return iterationRepository;
318: }
319:
320: public void setIterationRepository(
321: ObjectRepository iterationRepository) {
322: this.iterationRepository = iterationRepository;
323: }
324: }
|