blob: 0394cc57094ee71f3a96de7ccdb5745cdde96a0f [file] [log] [blame]
package com.intellij.tasks.generic;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.tasks.Task;
import com.intellij.tasks.impl.TaskUtil;
import com.intellij.ui.components.JBScrollPane;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.annotations.AbstractCollection;
import com.intellij.util.xmlb.annotations.Property;
import com.intellij.util.xmlb.annotations.Tag;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
/**
* @author Mikhail Golubev
*/
public abstract class SelectorBasedResponseHandler extends ResponseHandler {
private static final Logger LOG = Logger.getInstance(SelectorBasedResponseHandler.class);
// Supported selector names
@NonNls protected static final String TASKS = "tasks";
@NonNls protected static final String SUMMARY = "summary";
@NonNls protected static final String DESCRIPTION = "description";
@NonNls protected static final String ISSUE_URL = "issueUrl";
@NonNls protected static final String CLOSED = "closed";
@NonNls protected static final String UPDATED = "updated";
@NonNls protected static final String CREATED = "created";
@NonNls protected static final String SINGLE_TASK_ID = "singleTask-id";
@NonNls protected static final String SINGLE_TASK_SUMMARY = "singleTask-summary";
@NonNls protected static final String SINGLE_TASK_DESCRIPTION = "singleTask-description";
@NonNls protected static final String SINGLE_TASK_ISSUE_URL = "singleTask-issueUrl";
@NonNls protected static final String SINGLE_TASK_CLOSED = "singleTask-closed";
@NonNls protected static final String SINGLE_TASK_UPDATED = "singleTask-updated";
@NonNls protected static final String SINGLE_TASK_CREATED = "singleTask-created";
@NonNls protected static final String ID = "id";
protected LinkedHashMap<String, Selector> mySelectors = new LinkedHashMap<String, Selector>();
/**
* Serialization constructor
*/
@SuppressWarnings("UnusedDeclaration")
protected SelectorBasedResponseHandler() {
// empty
}
protected SelectorBasedResponseHandler(GenericRepository repository) {
super(repository);
// standard selectors
setSelectors(ContainerUtil.newArrayList(
// matched against list of tasks at whole downloaded from "taskListUrl"
new Selector(TASKS),
// matched against single tasks extracted from the list downloaded from "taskListUrl"
new Selector(ID),
new Selector(SUMMARY),
new Selector(DESCRIPTION),
new Selector(UPDATED),
new Selector(CREATED),
new Selector(CLOSED),
new Selector(ISSUE_URL),
// matched against single task downloaded from "singleTaskUrl"
new Selector(SINGLE_TASK_ID),
new Selector(SINGLE_TASK_SUMMARY),
new Selector(SINGLE_TASK_DESCRIPTION),
new Selector(SINGLE_TASK_UPDATED),
new Selector(SINGLE_TASK_CREATED),
new Selector(SINGLE_TASK_CLOSED),
new Selector(SINGLE_TASK_ISSUE_URL)
));
}
@Tag("selectors")
@Property(surroundWithTag = false)
@AbstractCollection(surroundWithTag = false)
@NotNull
public List<Selector> getSelectors() {
return new ArrayList<Selector>(mySelectors.values());
}
public void setSelectors(@NotNull List<Selector> selectors) {
mySelectors.clear();
for (Selector selector : selectors) {
mySelectors.put(selector.getName(), selector);
}
}
/**
* Only predefined selectors should be accessed.
*/
@NotNull
protected Selector getSelector(@NotNull String name) {
return mySelectors.get(name);
}
@NotNull
protected String getSelectorPath(@NotNull String name) {
Selector s = getSelector(name);
return s.getPath();
}
@NotNull
@Override
public JComponent getConfigurationComponent(@NotNull Project project) {
FileType fileType = getResponseType().getSelectorFileType();
HighlightedSelectorsTable table = new HighlightedSelectorsTable(fileType, project, getSelectors());
return new JBScrollPane(table);
}
@Override
public SelectorBasedResponseHandler clone() {
SelectorBasedResponseHandler clone = (SelectorBasedResponseHandler)super.clone();
clone.mySelectors = new LinkedHashMap<String, Selector>(mySelectors.size());
for (Selector selector : mySelectors.values()) {
clone.mySelectors.put(selector.getName(), selector.clone());
}
return clone;
}
@Override
public boolean isConfigured() {
Selector idSelector = getSelector(ID);
if (StringUtil.isEmpty(idSelector.getPath())) return false;
Selector summarySelector = getSelector(SUMMARY);
if (StringUtil.isEmpty(summarySelector.getPath())) return false;
return true;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SelectorBasedResponseHandler)) return false;
SelectorBasedResponseHandler handler = (SelectorBasedResponseHandler)o;
if (!mySelectors.equals(handler.mySelectors)) return false;
return true;
}
@Override
public int hashCode() {
return mySelectors.hashCode();
}
@NotNull
@Override
public final Task[] parseIssues(@NotNull String response, int max) throws Exception {
if (StringUtil.isEmpty(getSelectorPath(TASKS)) ||
StringUtil.isEmpty(getSelectorPath(ID)) ||
StringUtil.isEmpty(getSelectorPath(SUMMARY))) {
throw new Exception("Selectors 'tasks', 'id' and 'summary' are mandatory");
}
List<Object> tasks = selectTasksList(response, max);
LOG.debug(String.format("Total %d tasks extracted from response", tasks.size()));
List<Task> result = new ArrayList<Task>(tasks.size());
for (Object context : tasks) {
String id = selectString(getSelector(ID), context);
String summary = selectString(getSelector(SUMMARY), context);
assert id != null && summary != null;
GenericTask task = new GenericTask(id, summary, myRepository);
if (!myRepository.getDownloadTasksInSeparateRequests()) {
String description = selectString(getSelector(DESCRIPTION), context);
if (description != null) {
task.setDescription(description);
}
String issueUrl = selectString(getSelector(ISSUE_URL), context);
if (issueUrl != null) {
task.setIssueUrl(issueUrl);
}
Boolean closed = selectBoolean(getSelector(CLOSED), context);
if (closed != null) {
task.setClosed(closed);
}
Date updated = selectDate(getSelector(UPDATED), context);
if (updated != null) {
task.setUpdated(updated);
}
Date created = selectDate(getSelector(CREATED), context);
if (created != null) {
task.setCreated(created);
}
}
result.add(task);
}
return result.toArray(new Task[result.size()]);
}
@Nullable
private Date selectDate(@NotNull Selector selector, @NotNull Object context) throws Exception {
String s = selectString(selector, context);
if (s == null) {
return null;
}
return TaskUtil.parseDate(s);
}
@Nullable
protected Boolean selectBoolean(@NotNull Selector selector, @NotNull Object context) throws Exception {
String s = selectString(selector, context);
if (s == null) {
return null;
}
s = s.trim().toLowerCase();
if (s.equals("true")) {
return true;
}
else if (s.equals("false")) {
return false;
}
throw new Exception(
String.format("Expression '%s' should match boolean value. Got '%s' instead", selector.getName(), s));
}
@NotNull
protected abstract List<Object> selectTasksList(@NotNull String response, int max) throws Exception;
@Nullable
protected abstract String selectString(@NotNull Selector selector, @NotNull Object context) throws Exception;
@Nullable
@Override
public final Task parseIssue(@NotNull String response) throws Exception {
if (StringUtil.isEmpty(getSelectorPath(SINGLE_TASK_ID)) ||
StringUtil.isEmpty(getSelectorPath(SINGLE_TASK_SUMMARY))) {
throw new Exception("Selectors 'singleTask-id' and 'singleTask-summary' are mandatory");
}
String id = selectString(getSelector(SINGLE_TASK_ID), response);
String summary = selectString(getSelector(SINGLE_TASK_SUMMARY), response);
assert id != null && summary != null;
GenericTask task = new GenericTask(id, summary, myRepository);
String description = selectString(getSelector(SINGLE_TASK_DESCRIPTION), response);
if (description != null) {
task.setDescription(description);
}
String issueUrl = selectString(getSelector(SINGLE_TASK_ISSUE_URL), response);
if (issueUrl != null) {
task.setIssueUrl(issueUrl);
}
Boolean closed = selectBoolean(getSelector(SINGLE_TASK_CLOSED), response);
if (closed != null) {
task.setClosed(closed);
}
Date updated = selectDate(getSelector(SINGLE_TASK_UPDATED), response);
if (updated != null) {
task.setUpdated(updated);
}
Date created = selectDate(getSelector(SINGLE_TASK_CREATED), response);
if (created != null) {
task.setCreated(created);
}
return task;
}
}