Java tutorial
/* * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.tasks.fogbugz; import java.util.Date; import java.util.List; import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.methods.PostMethod; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.xpath.XPath; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.tasks.Comment; import com.intellij.tasks.Task; import com.intellij.tasks.TaskRepository; import com.intellij.tasks.TaskRepositoryType; import com.intellij.tasks.TaskType; import com.intellij.tasks.impl.BaseRepository; import com.intellij.tasks.impl.BaseRepositoryImpl; import com.intellij.util.NotNullFunction; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xmlb.annotations.Tag; import consulo.ui.image.Image; import icons.TasksIcons; /** * @author mkennedy */ @Tag("FogBugz") public class FogBugzRepository extends BaseRepositoryImpl { private static final Logger LOG = Logger.getInstance("#com.intellij.tasks.fogbugz.FogBugzRepository"); private transient String token; public FogBugzRepository(TaskRepositoryType type) { super(type); setUrl("https://example.fogbugz.com"); } private FogBugzRepository(FogBugzRepository other) { super(other); } @SuppressWarnings({ "UnusedDeclaration" }) public FogBugzRepository() { } @Override public Task[] getIssues(@Nullable String query, int max, final long since) throws Exception { return getCases(StringUtil.notNullize(query)); } private Task[] getCases(String q) throws Exception { HttpClient client = login(getLoginMethod()); PostMethod method = new PostMethod(getUrl() + "/api.asp"); method.addParameter("token", token); method.addParameter("cmd", "search"); method.addParameter("q", q); method.addParameter("cols", "sTitle,fOpen,dtOpened,dtLastUpdated,ixCategory"); int status = client.executeMethod(method); if (status != 200) { throw new Exception("Error listing cases: " + method.getStatusLine()); } Document document = new SAXBuilder(false).build(method.getResponseBodyAsStream()).getDocument(); XPath path = XPath.newInstance("/response/cases/case"); final XPath commentPath = XPath.newInstance("events/event"); @SuppressWarnings("unchecked") final List<Element> nodes = (List<Element>) path.selectNodes(document); final List<Task> tasks = ContainerUtil.mapNotNull(nodes, new NotNullFunction<Element, Task>() { @Nonnull @Override public Task fun(Element element) { return createCase(element, commentPath); } }); return tasks.toArray(new Task[tasks.size()]); } private static TaskType getType(Element element) { String category = element.getChildText("ixCategory"); if ("1".equals(category)) { return TaskType.BUG; } else if ("2".equals(category)) { return TaskType.FEATURE; } return TaskType.OTHER; } @Nonnull private Task createCase(final Element element, final XPath commentPath) { final String id = element.getAttributeValue("ixBug"); final String title = element.getChildTextTrim("sTitle"); final TaskType type = getType(element); return new Task() { @Nonnull @Override public String getId() { return id; } @Nonnull @Override public String getSummary() { return title; } @Nullable @Override public String getDescription() { return null; } @Nonnull @Override @SuppressWarnings("unchecked") public Comment[] getComments() { List<Element> nodes; try { nodes = commentPath.selectNodes(element); } catch (Exception e) { throw new RuntimeException("Error selecting comment nodes", e); } List<Comment> comments = ContainerUtil.mapNotNull(nodes, new NotNullFunction<Element, Comment>() { @Nonnull @Override public Comment fun(Element element) { return createComment(element); } private Comment createComment(final Element element) { return new Comment() { @Override public String getText() { return element.getChildTextTrim("s"); } @Nullable @Override public String getAuthor() { return element.getChildTextTrim("sPerson"); } @Nullable @Override public Date getDate() { return parseDate(element.getChildTextTrim("dt")); } }; } }); return comments.toArray(new Comment[comments.size()]); } @Nonnull @Override public Image getIcon() { return TasksIcons.Fogbugz; } @Nonnull @Override public TaskType getType() { return type; } @Nullable @Override public Date getUpdated() { return parseDate(element.getChildText("dtLastUpdated")); } @Nullable @Override public Date getCreated() { return parseDate(element.getChildTextTrim("dtOpened")); } @Override public boolean isClosed() { return !Boolean.valueOf(element.getChildTextTrim("fOpen")); } @Override public boolean isIssue() { return true; } @Nullable @Override public String getIssueUrl() { return getUrl() + "/default.asp?" + getId(); } @Nullable @Override public TaskRepository getRepository() { return FogBugzRepository.this; } }; } @Nullable @Override public Task findTask(String id) throws Exception { Task[] tasks = getCases(id); switch (tasks.length) { case 0: return null; case 1: return tasks[0]; default: LOG.warn("Expected unique case for case id: " + id + ", got " + tasks.length + " instead. Using the first one."); return tasks[0]; } } @Override public BaseRepository clone() { return new FogBugzRepository(this); } private HttpClient login(PostMethod method) throws Exception { HttpClient client = getHttpClient(); int status = client.executeMethod(method); if (status != 200) { throw new Exception("Error logging in: " + method.getStatusLine()); } Document document = new SAXBuilder(false).build(method.getResponseBodyAsStream()).getDocument(); XPath path = XPath.newInstance("/response/token"); Element result = (Element) path.selectSingleNode(document); if (result == null) { Element error = (Element) XPath.newInstance("/response/error").selectSingleNode(document); throw new Exception(error == null ? "Error logging in" : error.getText()); } token = result.getTextTrim(); return client; } private PostMethod getLoginMethod() { PostMethod method = new PostMethod(getUrl() + "/api.asp"); method.addParameter("cmd", "logon"); method.addParameter("email", getUsername()); method.addParameter("password", getPassword()); return method; } @Nullable @Override public CancellableConnection createCancellableConnection() { return new HttpTestConnection<PostMethod>(getLoginMethod()) { @Override protected void doTest(PostMethod method) throws Exception { login(method); } }; } @Nonnull private static Date parseDate(@Nonnull String string) { try { return DatatypeFactory.newInstance().newXMLGregorianCalendar(string).toGregorianCalendar().getTime(); } catch (DatatypeConfigurationException e) { throw new RuntimeException("Error configuring datatype factory", e); } } @Override public String getComment() { return "{id} (e.g. 2344245), {summary}"; } }