001: package org.tigris.scarab.xmlrpc;
002:
003: import java.util.*;
004: import java.io.*;
005:
006: import org.tigris.scarab.om.ActivitySet;
007: import org.tigris.scarab.om.Attachment;
008: import org.tigris.scarab.om.Attribute;
009: import org.tigris.scarab.om.AttributeOption;
010: import org.tigris.scarab.om.AttributeOptionManager;
011: import org.tigris.scarab.om.AttributeValue;
012: import org.tigris.scarab.om.GlobalParameter;
013: import org.tigris.scarab.om.GlobalParameterManager;
014: import org.tigris.scarab.om.Issue;
015: import org.tigris.scarab.om.IssueManager;
016: import org.tigris.scarab.om.MITListManager;
017: import org.tigris.scarab.om.Module;
018: import org.tigris.scarab.om.ModuleManager;
019: import org.tigris.scarab.om.ScarabUser;
020: import org.tigris.scarab.om.ScarabUserManager;
021:
022: import org.tigris.scarab.services.cache.ScarabCache;
023: import org.tigris.scarab.util.IssueIdParser;
024: import org.tigris.scarab.util.ScarabUtil;
025: import org.tigris.scarab.util.word.IssueSearch;
026: import org.tigris.scarab.util.word.IssueSearchFactory;
027: import org.tigris.scarab.util.word.QueryResult;
028:
029: import org.apache.log4j.Category;
030: import org.apache.turbine.Turbine;
031:
032: /**
033: * Provides a basic API for XML-RPC requests to the Scarab server.
034: * It makes the server side for scarab-post-commit.py script (in the
035: * extensions/script directory).
036: *
037: * @author Mick
038: * @version $Id$
039: * @see org.tigris.scarab.util.SimpleHandlerClient
040: */
041: public class SimpleHandler {
042: private static final Category category = Category
043: .getInstance(SimpleHandler.class);
044:
045: /**
046: * Maximum number of characters to put into one comment, add multiple
047: * comments if neccessary. Really only applies to oracle databases where
048: * varchar2 has a limit of 4000, and has to be used because oracle's clob/blob
049: * doesn't work w/ torque. <br/>
050: * <b>
051: * A value of zero means no limit of comment size.
052: * </b>
053: */
054: private static final int MAX_COMMENT_SIZE;
055:
056: protected static void log(String str) {
057: category.info("SimpleHandler: " + str);
058: }
059:
060: static {
061: log("loading");
062: final String db = Turbine.getConfiguration().getString(
063: "scarab.database.type");
064: MAX_COMMENT_SIZE = (db.equalsIgnoreCase("oracle")) ? 4000 : 0;
065: }
066:
067: /**
068: * Append a comment to the specified issue. Wrapper method with string
069: * parameters.
070: *
071: * @return Vector with first item a boolean indicating success.
072: * @param issues
073: * string with the ids of the issue to add the comment to
074: * (can contain other words which will simply be ignored)
075: * @param user
076: * the username of the user who is adding the comment
077: * @param comment
078: * the comment to append to the issue
079: * @param disableEmailsInt
080: * do we want this change to trigger an email to every person assigned a role.
081: */
082: public Vector addComment(final String issues, final String user,
083: final String comment, final int disableEmailsInt) {
084:
085: final Vector retValue = new Vector();
086: boolean success = false;
087: final String c = ScarabUtil.fixEOLs(comment);
088: final boolean disableEmails = (disableEmailsInt != 0);
089: log("addComment: issues=" + issues + ", user=" + user
090: + ", comment=\"" + c + ", disableEmails="
091: + disableEmailsInt);
092:
093: try {
094:
095: // issues to add comment to
096: final Set issueSet = new HashSet();
097:
098: // find user
099: final ScarabUser u = ScarabUserManager.getInstance(user);
100:
101: // find modules in moduleDomain
102: List modules = MITListManager
103: .getAllModulesAllIssueTypesList(u).getModules();
104:
105: for (Iterator it = modules.iterator(); it.hasNext();) {
106: final Module m = (Module) it.next();
107: // Parse issues from issues string
108: final List issueTokens = IssueIdParser.tokenizeText(m,
109: issues);
110:
111: for (Iterator it2 = issueTokens.iterator(); it2
112: .hasNext();) {
113: final Object o = it2.next();
114: // find issue
115: if (o instanceof List && ((List) o).get(1) != null
116: && ((List) o).get(1) instanceof String) {
117: final Issue i = IssueManager
118: .getIssueById((String) ((List) o)
119: .get(1));
120: issueSet.add(i);
121: }
122: }
123: }
124: // now add the comments to each issue found
125: for (Iterator it = issueSet.iterator(); it.hasNext();) {
126: final Issue i = (Issue) it.next();
127: success |= addComment(i, u, c, disableEmails);
128: }
129: retValue.add(new Boolean(success));
130: } catch (RuntimeException e) {
131: retValue.add(Boolean.FALSE);
132: retValue.add(e);
133: e.printStackTrace();
134: throw e;
135: } catch (Exception e) {
136: retValue.add(Boolean.FALSE);
137: retValue.add(e);
138: e.printStackTrace();
139: }
140: return retValue;
141: }
142:
143: /**
144: * Append a comment to the specified issue.
145: *
146: * @return success.
147: * @param issueId
148: * the id of the issue to add the comment to
149: * @param username
150: * the username of the user who is adding the comment
151: * @param comment
152: * the comment to append to the issue
153: */
154: protected boolean addComment(final Issue issue,
155: final ScarabUser user, final String comment,
156: final boolean disableEmails) throws Exception {
157:
158: log("adding comment to " + issue.getIssueId());
159:
160: // buffer the comment so we can break it down if MAX_COMMENT_SIZE != 0
161: final BufferedReader reader = new BufferedReader(
162: new StringReader(comment));
163: // The comment Attachments that will be added to the issue.
164: // This will only contain one Attachment when MAX_COMMENT_SIZE == 0
165: final List comments = new LinkedList();
166: final StringBuffer nextComment = new StringBuffer();
167: String nextLine = "";
168: do {
169: nextLine = reader.readLine();
170:
171: if (nextLine == null
172: || (MAX_COMMENT_SIZE > 0 && nextComment.length()
173: + nextLine.length() > MAX_COMMENT_SIZE)) {
174: final Attachment attachment = new Attachment();
175: attachment.setData(nextComment.toString());
176: comments.add(0, attachment); // reverse order the list, it looks better on issue page.
177: nextComment.setLength(0);
178: }
179: if (nextLine != null) {
180: nextComment.append(nextLine + '\n');
181: }
182:
183: } while (nextLine != null);
184:
185: // actually add the comment Attachments to issue
186: synchronized (GlobalParameter.EMAIL_ENABLED) {
187: // turn off emailing? we need to remember original state anyway...
188: final boolean originalEmailState = GlobalParameterManager
189: .getBoolean(GlobalParameter.EMAIL_ENABLED);
190:
191: if (disableEmails && originalEmailState) {
192: GlobalParameterManager.setBoolean(
193: GlobalParameter.EMAIL_ENABLED, false);
194: }
195: for (Iterator it = comments.iterator(); it.hasNext();) {
196: Attachment attachment = (Attachment) it.next();
197: if (attachment.getData() != null
198: && attachment.getData().length() > 0) {
199: issue.addComment(attachment, user);
200: }
201: }
202: if (disableEmails && originalEmailState) {
203: GlobalParameterManager.setBoolean(
204: GlobalParameter.EMAIL_ENABLED,
205: originalEmailState);
206: }
207: }
208:
209: // [TODO] It isn't neccessary to do all of these, which one is the correct one?!?
210: ScarabCache.clear();
211: IssueManager.getMethodResult().clear();
212: ModuleManager.getMethodResult().clear();
213:
214: return true;
215: }
216:
217: /**
218: * Update Issue's attribute option with a given user and description.
219: * Wrapper method with string parameters.
220: *
221: * @return Vector with first item a boolean indicating success.
222: */
223: public Vector changeIssueAttributeOption(final String issue,
224: final String user, final String attribute,
225: final String option, final String description) {
226:
227: log("changeIssueAttributeOption: issue=" + issue + ", user="
228: + user + ", attribute=\"" + attribute + "\""
229: + ", option=\"" + option + "\"" + ", description=\""
230: + description + "\"");
231:
232: final Vector retValue = new Vector();
233: try {
234: // find issue
235: final Issue i = IssueManager.getIssueById(issue);
236: // find user
237: final ScarabUser u = ScarabUserManager.getInstance(user);
238: // find attribute
239: final Attribute a = Attribute.getInstance(attribute);
240: // find attributeOption
241: final AttributeOption o = AttributeOptionManager
242: .getInstance(a, option);
243: // proper method call
244: if (i == null || u == null || a == null || o == null) {
245: throw new IllegalArgumentException(
246: "Encountered an invalid parameter: " + i
247: + " , " + u + " , " + a + " , " + o);
248: }
249: retValue.add(new Boolean(changeIssueAttributeOption(i, u,
250: a, o, description)));
251: } catch (RuntimeException e) {
252: retValue.add(Boolean.FALSE);
253: retValue.add(e);
254: e.printStackTrace();
255: throw e;
256: } catch (Exception e) {
257: retValue.add(Boolean.FALSE);
258: retValue.add(e);
259: e.printStackTrace();
260: }
261: return retValue;
262: }
263:
264: /**
265: * Update Issue's attribute option with a given user and description
266: *
267: * @return success.
268: */
269: protected boolean changeIssueAttributeOption(final Issue issue,
270: final ScarabUser user, final Attribute attribute,
271: final AttributeOption option, final String description)
272: throws Exception {
273:
274: final AttributeValue status = issue
275: .getAttributeValue(attribute);
276: final AttributeValue nyStatus = AttributeValue.getNewInstance(
277: attribute, issue);
278: nyStatus.setOptionId(option.getOptionId());
279: //nyStatus.setActivityDescription(description);
280: final Attachment attachment = new Attachment();
281: attachment.setData(description);
282: attachment.setName("comment");
283: final HashMap newAttVals = new HashMap();
284: newAttVals.put(status.getAttributeId(), nyStatus);
285: final ActivitySet activitySet = issue.setAttributeValues(null,
286: newAttVals, attachment, user);
287: return true;
288: }
289:
290: /** returns a vector of federatedIds (prefix+count) for issues with the given attribute value.
291: **/
292: public Vector findIssuesWithAttributeValue(final String user,
293: final String attribute, final String value) {
294:
295: log("findIssuesWithAttributeValue: user=" + user
296: + ", attribute=\"" + attribute + "\"" + ", value=\""
297: + value + "\"");
298:
299: final Vector retValue = new Vector();
300: try {
301:
302: // find user
303: final ScarabUser u = ScarabUserManager.getInstance(user);
304: // find attribute
305: final Attribute a = Attribute.getInstance(attribute);
306: // proper method call
307: retValue.addAll(findIssuesWithAttributeValue(u, a, value));
308: } catch (RuntimeException e) {
309: retValue.add(null);
310: retValue.add(e);
311: e.printStackTrace();
312: throw e;
313: } catch (Exception e) {
314: retValue.add(null);
315: retValue.add(e);
316: e.printStackTrace();
317: }
318: return retValue;
319: }
320:
321: protected Vector findIssuesWithAttributeValue(
322: final ScarabUser user, final Attribute attribute,
323: final String value) throws Exception {
324: IssueSearch search = null;
325: final Vector retValue = new Vector();
326: try {
327: search = IssueSearchFactory.INSTANCE
328: .getInstance(MITListManager
329: .getAllModulesAllIssueTypesList(user), user);
330: final AttributeValue av = AttributeValue.getNewInstance(
331: attribute, search);
332: av.setValue(value);
333: search.addAttributeValue(av);
334: final Iterator queryresults = search.getQueryResults();
335:
336: while (queryresults.hasNext()) {
337: final QueryResult qr = (QueryResult) queryresults
338: .next();
339: retValue.add(qr.getUniqueId());
340: //log(" Adding to results "+qr.getUniqueId());
341: }
342: } finally {
343: if (search != null) {
344: search.close();
345: IssueSearchFactory.INSTANCE.notifyDone();
346: }
347: }
348: return retValue; // return matching issues
349: }
350:
351: }
|