blob: 16f0b49d0361a6a8b91ffbda535710d357a62a70 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2009 Eugene Kuleshov and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Eugene Kuleshov - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.web.tasks;
import static org.eclipse.mylyn.internal.web.tasks.Util.isPresent;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.codec.EncoderException;
import org.apache.commons.codec.net.URLCodec;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.lang.StringEscapeUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.commons.net.AbstractWebLocation;
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
import org.eclipse.mylyn.commons.net.AuthenticationType;
import org.eclipse.mylyn.commons.net.WebLocation;
import org.eclipse.mylyn.commons.net.WebUtil;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
import org.eclipse.mylyn.tasks.core.IRepositoryManager;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.ITask;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
import org.eclipse.mylyn.tasks.core.data.TaskData;
import org.eclipse.mylyn.tasks.core.data.TaskDataCollector;
import org.eclipse.mylyn.tasks.core.data.TaskMapper;
import org.eclipse.mylyn.tasks.core.sync.ISynchronizationSession;
import org.eclipse.mylyn.tasks.ui.TaskRepositoryLocationUiFactory;
import org.eclipse.mylyn.tasks.ui.TasksUi;
import com.sun.syndication.feed.module.DCModule;
import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.SyndFeedInput;
import com.sun.syndication.io.XmlReader;
/**
* Generic connector for web based issue tracking systems
*
* @author Eugene Kuleshov
*/
public class WebRepositoryConnector extends AbstractRepositoryConnector {
public static final String REPOSITORY_TYPE = "web"; //$NON-NLS-1$
public static final String PROPERTY_TASK_CREATION_URL = "taskCreationUrl"; //$NON-NLS-1$
public static final String PROPERTY_TASK_URL = "taskUrl"; //$NON-NLS-1$
public static final String PROPERTY_QUERY_URL = "queryUrl"; //$NON-NLS-1$
public static final String PROPERTY_QUERY_METHOD = "queryMethod"; //$NON-NLS-1$
public static final String PROPERTY_QUERY_REGEXP = "queryPattern"; //$NON-NLS-1$
public static final String PROPERTY_LOGIN_FORM_URL = "loginFormUrl"; //$NON-NLS-1$
public static final String PROPERTY_LOGIN_TOKEN_REGEXP = "loginTokenPattern"; //$NON-NLS-1$
public static final String PROPERTY_LOGIN_REQUEST_METHOD = "loginRequestMethod"; //$NON-NLS-1$
public static final String PROPERTY_LOGIN_REQUEST_URL = "loginRequestUrl"; //$NON-NLS-1$
public static final String PARAM_PREFIX = "param_"; //$NON-NLS-1$
public static final String PARAM_SERVER_URL = "serverUrl"; //$NON-NLS-1$
public static final String PARAM_USER_ID = "userId"; //$NON-NLS-1$
public static final String PARAM_PASSWORD = "password"; //$NON-NLS-1$
public static final String PARAM_LOGIN_TOKEN = "loginToken"; //$NON-NLS-1$
public static final String REQUEST_POST = "POST"; //$NON-NLS-1$
public static final String REQUEST_GET = "GET"; //$NON-NLS-1$
private static final String COMPLETED_STATUSES = "completed|fixed|resolved|invalid|verified|deleted|closed|done"; //$NON-NLS-1$
public static final String KEY_TASK_PREFIX = "taskPrefix"; //$NON-NLS-1$
public static final String KEY_QUERY_TEMPLATE = "UrlTemplate"; //$NON-NLS-1$
public static final String KEY_QUERY_PATTERN = "Regexp"; //$NON-NLS-1$
private static final String USER_AGENT = "WebTemplatesConnector"; //$NON-NLS-1$
private final static Date DEFAULT_DATE = new Date(0);
@Override
public String getConnectorKind() {
return REPOSITORY_TYPE;
}
@Override
public String getLabel() {
return Messages.WebRepositoryConnector_Web_Template_Advanced_;
}
@Override
public boolean canCreateNewTask(TaskRepository repository) {
return repository.hasProperty(PROPERTY_TASK_CREATION_URL);
}
@Override
public boolean canCreateTaskFromKey(TaskRepository repository) {
return repository.hasProperty(PROPERTY_TASK_URL);
}
@Override
public boolean canSynchronizeTask(TaskRepository taskRepository, ITask task) {
return false;
}
// @Override
// public AbstractTask createTaskFromExistingId(TaskRepository repository, final String id, IProgressMonitor monitor)
// throws CoreException {
// if (REPOSITORY_TYPE.equals(repository.getConnectorKind())) {
// String taskPrefix = evaluateParams(repository.getProperty(PROPERTY_TASK_URL), repository);
//
// final WebTask task = new WebTask(id, id, taskPrefix, repository.getRepositoryUrl(), REPOSITORY_TYPE);
//
// RetrieveTitleFromUrlJob job = new RetrieveTitleFromUrlJob(taskPrefix + id) {
// @Override
// protected void setTitle(String pageTitle) {
// task.setSummary(pageTitle);
// TasksUiPlugin.getTaskList().notifyTaskChanged(task, false);
// }
// };
// job.schedule();
//
// return task;
// }
//
// return null;
// }
@Override
public TaskData getTaskData(TaskRepository repository, String taskId, IProgressMonitor monitor)
throws CoreException {
String taskPrefix = evaluateParams(repository.getProperty(PROPERTY_TASK_URL), repository);
TaskData taskData = createTaskData(repository, taskId);
TaskMapper mapper = new TaskMapper(taskData, true);
mapper.setCreationDate(DEFAULT_DATE);
mapper.setTaskUrl(taskPrefix + taskId);
mapper.setValue(KEY_TASK_PREFIX, taskPrefix);
// bug 300310: only update the summary on forced refreshes
mapper.setSummary(taskId);
try {
String pageTitle = WebUtil.getTitleFromUrl(new WebLocation(taskPrefix + taskId), monitor);
if (pageTitle != null) {
mapper.setSummary(pageTitle);
}
} catch (IOException e) {
// log to error log?
}
taskData.getRoot()
.getMappedAttribute(TaskAttribute.SUMMARY)
.getMetaData()
.putValue("forced", Boolean.TRUE.toString());
return taskData;
}
@SuppressWarnings("restriction")
@Override
public String getRepositoryUrlFromTaskUrl(String url) {
if (url == null) {
return null;
}
// lookup repository using task prefix url
IRepositoryManager repositoryManager = TasksUi.getRepositoryManager();
for (TaskRepository repository : repositoryManager.getRepositories(getConnectorKind())) {
String taskUrl = evaluateParams(repository.getProperty(PROPERTY_TASK_URL), repository);
if (taskUrl != null && !taskUrl.equals("") && url.startsWith(taskUrl)) { //$NON-NLS-1$
return repository.getRepositoryUrl();
}
}
for (IRepositoryQuery query : org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal.getTaskList()
.getQueries()) {
TaskRepository repository = repositoryManager.getRepository(query.getConnectorKind(),
query.getRepositoryUrl());
if (repository != null) {
String queryUrl = evaluateParams(query.getAttribute(KEY_TASK_PREFIX), //
getQueryParams(query), repository);
if (queryUrl != null && !queryUrl.equals("") && url.startsWith(queryUrl)) { //$NON-NLS-1$
return query.getRepositoryUrl();
}
}
}
return null;
}
public static Map<String, String> getQueryParams(IRepositoryQuery query) {
Map<String, String> params = new LinkedHashMap<String, String>();
Map<String, String> attributes = query.getAttributes();
for (String name : attributes.keySet()) {
if (name.startsWith(WebRepositoryConnector.PARAM_PREFIX)) {
params.put(name, attributes.get(name));
}
}
return params;
}
@Override
public String getTaskIdFromTaskUrl(String url) {
if (url == null) {
return null;
}
IRepositoryManager repositoryManager = TasksUi.getRepositoryManager();
for (TaskRepository repository : repositoryManager.getRepositories(getConnectorKind())) {
String start = evaluateParams(repository.getProperty(PROPERTY_TASK_URL), repository);
if (start != null && url.startsWith(start)) {
return url.substring(start.length());
}
}
return null;
}
@Override
public String getTaskUrl(String repositoryUrl, String taskId) {
IRepositoryManager repositoryManager = TasksUi.getRepositoryManager();
TaskRepository repository = repositoryManager.getRepository(getConnectorKind(), repositoryUrl);
if (repository != null) {
String prefix = evaluateParams(repository.getProperty(PROPERTY_TASK_URL), repository);
return prefix + taskId;
}
return null;
}
@Override
public IStatus performQuery(TaskRepository repository, IRepositoryQuery query, TaskDataCollector resultCollector,
ISynchronizationSession session, IProgressMonitor monitor) {
Map<String, String> queryParameters = getQueryParams(query);
String queryUrl = evaluateParams(query.getUrl(), queryParameters, repository);
try {
String content = fetchResource(queryUrl, queryParameters, repository);
String taskPrefixAttribute = query.getAttribute(KEY_TASK_PREFIX);
if (!Util.isPresent(taskPrefixAttribute)) {
return performRssQuery(content, monitor, resultCollector, repository);
} else {
String taskPrefix = evaluateParams(taskPrefixAttribute, queryParameters, repository);
String queryPattern = evaluateParams(query.getAttribute(KEY_QUERY_PATTERN), queryParameters, repository);
return performQuery(content, queryPattern, taskPrefix, monitor, resultCollector, repository);
}
} catch (IOException e) {
String msg = e.getMessage() == null ? e.toString() : e.getMessage();
return new Status(IStatus.ERROR, TasksWebPlugin.ID_PLUGIN, IStatus.ERROR, //
Messages.WebRepositoryConnector_Could_not_fetch_resource + queryUrl + "\n" + msg, e); //$NON-NLS-1$
}
}
@Override
public boolean isRepositoryConfigurationStale(TaskRepository repository, IProgressMonitor monitor)
throws CoreException {
return false;
}
@Override
public void updateRepositoryConfiguration(TaskRepository repository, IProgressMonitor monitor) throws CoreException {
// ignore
}
@Override
public void updateTaskFromTaskData(TaskRepository repository, ITask task, TaskData taskData) {
preProcessTaskData(task, taskData);
TaskMapper mapper = new TaskMapper(taskData);
if (Util.isPresent(mapper.getValue(KEY_TASK_PREFIX))) {
task.setAttribute(KEY_TASK_PREFIX, mapper.getValue(KEY_TASK_PREFIX));
task.setTaskKey(task.getTaskId());
} else {
// do not show task id for RSS items
task.setTaskKey(null);
}
mapper.applyTo(task);
}
private void preProcessTaskData(ITask task, TaskData taskData) {
if (task.getSummary() != null && task.getSummary().length() > 0) {
// bug 300310: if task already has a summary, keep it
TaskAttribute summaryAttribute = taskData.getRoot().getMappedAttribute(TaskAttribute.SUMMARY);
if (summaryAttribute != null && Boolean.parseBoolean(summaryAttribute.getMetaData().getValue("forced"))) {
summaryAttribute.setValue(task.getSummary());
}
}
}
public static IStatus performQuery(String resource, String regexp, String taskPrefix, IProgressMonitor monitor,
TaskDataCollector resultCollector, TaskRepository repository) {
NamedPattern p = new NamedPattern(regexp, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL
| Pattern.UNICODE_CASE | Pattern.CANON_EQ);
Matcher matcher = p.matcher(resource);
if (!matcher.find()) {
return Status.OK_STATUS;
} else {
boolean isCorrect = true;
do {
if (p.getGroups().isEmpty()) {
// "classic" mode, no named patterns
if (matcher.groupCount() < 2) {
isCorrect = false;
}
if (matcher.groupCount() >= 1) {
String id = matcher.group(1);
String description = matcher.groupCount() > 1 ? cleanup(matcher.group(2), repository) : null;
description = unescapeHtml(description);
TaskData data = createTaskData(repository, id);
TaskMapper mapper = new TaskMapper(data, true);
mapper.setCreationDate(DEFAULT_DATE);
mapper.setTaskUrl(taskPrefix + id);
mapper.setSummary(description);
mapper.setValue(KEY_TASK_PREFIX, taskPrefix);
resultCollector.accept(data);
}
} else {
String id = p.group("Id", matcher); //$NON-NLS-1$
String description = p.group("Description", matcher); //$NON-NLS-1$
if (id == null || description == null) {
isCorrect = false;
}
if (id != null) {
description = unescapeHtml(description);
String owner = unescapeHtml(cleanup(p.group("Owner", matcher), repository)); //$NON-NLS-1$
String type = unescapeHtml(cleanup(p.group("Type", matcher), repository)); //$NON-NLS-1$
TaskData data = createTaskData(repository, id);
TaskMapper mapper = new TaskMapper(data, true);
mapper.setCreationDate(DEFAULT_DATE);
mapper.setTaskUrl(taskPrefix + id);
mapper.setSummary(description);
mapper.setValue(KEY_TASK_PREFIX, taskPrefix);
mapper.setOwner(owner);
mapper.setTaskKind(type);
String status = p.group("Status", matcher); //$NON-NLS-1$
if (status != null) {
if (COMPLETED_STATUSES.contains(status.toLowerCase())) {
// TODO set actual completion date here
mapper.setCompletionDate(DEFAULT_DATE);
}
}
resultCollector.accept(data);
}
}
} while (matcher.find() && !monitor.isCanceled());
if (isCorrect) {
return Status.OK_STATUS;
} else {
return new Status(IStatus.ERROR, TasksWebPlugin.ID_PLUGIN, IStatus.ERROR,
Messages.WebRepositoryConnector_Require_two_matching_groups, null);
}
}
}
private static TaskData createTaskData(TaskRepository taskRepository, String id) {
TaskData data = new TaskData(new TaskAttributeMapper(taskRepository), WebRepositoryConnector.REPOSITORY_TYPE,
taskRepository.getRepositoryUrl(), id);
data.setPartial(true);
return data;
}
private static String unescapeHtml(String text) {
if (text == null) {
return ""; //$NON-NLS-1$
}
return StringEscapeUtils.unescapeHtml(text);
}
private static String cleanup(String text, TaskRepository repository) {
if (text == null) {
return null;
}
// Has to disable this for now. See bug 166737 and bug 166936
// try {
// text = URLDecoder.decode(text, repository.getCharacterEncoding());
// } catch (UnsupportedEncodingException ex) {
// // ignore
// }
text = text.replaceAll("<!--.+?-->", ""); //$NON-NLS-1$ //$NON-NLS-2$
String[] tokens = text.split(" |\\t|\\n|\\r"); //$NON-NLS-1$
StringBuilder sb = new StringBuilder();
String sep = ""; //$NON-NLS-1$
for (String token : tokens) {
if (token.length() > 0) {
sb.append(sep).append(token);
sep = " "; //$NON-NLS-1$
}
}
return sb.toString();
}
public static IStatus performRssQuery(String content, IProgressMonitor monitor, TaskDataCollector resultCollector,
TaskRepository repository) {
SyndFeedInput input = new SyndFeedInput();
try {
SyndFeed feed = input.build(new XmlReader(new ByteArrayInputStream(content.getBytes())));
SimpleDateFormat df = new SimpleDateFormat("yy-MM-dd HH:mm"); //$NON-NLS-1$
Iterator<?> it;
for (it = feed.getEntries().iterator(); it.hasNext();) {
SyndEntry entry = (SyndEntry) it.next();
String author = entry.getAuthor();
if (author == null) {
DCModule module = (DCModule) entry.getModule("http://purl.org/dc/elements/1.1/"); //$NON-NLS-1$
author = module.getCreator();
}
Date date = entry.getUpdatedDate();
if (date == null) {
date = entry.getPublishedDate();
}
if (date == null) {
DCModule module = (DCModule) entry.getModule("http://purl.org/dc/elements/1.1/"); //$NON-NLS-1$
date = module.getDate();
}
String entryUri = entry.getLink();
if (entryUri == null) {
entryUri = entry.getUri();
}
String entrTitle = entry.getTitle();
TaskData data = createTaskData(repository, entryUri.replaceAll("-", "%2D")); //$NON-NLS-1$ //$NON-NLS-2$
TaskMapper schema = new TaskMapper(data, true);
schema.setSummary(((date == null ? "" : df.format(date) + " - ") + entrTitle)); //$NON-NLS-1$ //$NON-NLS-2$
schema.setCreationDate(date);
schema.setOwner(author);
schema.setTaskUrl(entryUri);
resultCollector.accept(data);
}
return Status.OK_STATUS;
} catch (Exception e) {
String msg = e.getMessage() == null ? e.toString() : e.getMessage();
return new Status(IStatus.ERROR, TasksWebPlugin.ID_PLUGIN, IStatus.ERROR, //
Messages.WebRepositoryConnector_Failed_to_parse_RSS_feed + "\"" + msg + "\"", e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
public static String fetchResource(String url, Map<String, String> params, TaskRepository repository)
throws IOException {
HttpClient client = new HttpClient();
WebUtil.configureHttpClient(client, USER_AGENT);
AbstractWebLocation location = new TaskRepositoryLocationUiFactory().createWebLocation(repository);
HostConfiguration hostConfiguration = WebUtil.createHostConfiguration(client, location, null);
loginRequestIfNeeded(client, hostConfiguration, params, repository);
GetMethod method = new GetMethod(url);
// method.setFollowRedirects(false);
return requestResource(url, client, hostConfiguration, method);
}
private static void loginRequestIfNeeded(HttpClient client, HostConfiguration hostConfiguration,
Map<String, String> params, TaskRepository repository) throws HttpException, IOException {
if (repository.getCredentials(AuthenticationType.REPOSITORY) == null
|| !isPresent(repository.getProperty(PROPERTY_LOGIN_REQUEST_URL))) {
return;
}
String loginFormUrl = evaluateParams(repository.getProperty(PROPERTY_LOGIN_FORM_URL), params, repository);
String loginToken = evaluateParams(repository.getProperty(PROPERTY_LOGIN_TOKEN_REGEXP), params, repository);
if (isPresent(loginFormUrl) || isPresent(loginToken)) {
GetMethod method = new GetMethod(loginFormUrl);
// method.setFollowRedirects(false);
String loginFormPage = requestResource(loginFormUrl, client, hostConfiguration, method);
if (loginFormPage != null) {
Pattern p = Pattern.compile(loginToken);
Matcher m = p.matcher(loginFormPage);
if (m.find()) {
params.put(PARAM_PREFIX + PARAM_LOGIN_TOKEN, m.group(1));
}
}
}
String loginRequestUrl = evaluateParams(repository.getProperty(PROPERTY_LOGIN_REQUEST_URL), params, repository);
requestResource(loginRequestUrl, client, hostConfiguration, getLoginMethod(params, repository));
}
public static HttpMethod getLoginMethod(Map<String, String> params, TaskRepository repository) {
String requestMethod = repository.getProperty(PROPERTY_LOGIN_REQUEST_METHOD);
String requestTemplate = repository.getProperty(PROPERTY_LOGIN_REQUEST_URL);
String requestUrl = evaluateParams(requestTemplate, params, repository);
if (REQUEST_GET.equals(requestMethod)) {
return new GetMethod(requestUrl);
// method.setFollowRedirects(false);
}
int n = requestUrl.indexOf('?');
if (n == -1) {
return new PostMethod(requestUrl);
}
PostMethod postMethod = new PostMethod(requestUrl.substring(0, n));
// TODO this does not take into account escaped values
n = requestTemplate.indexOf('?');
String[] requestParams = requestTemplate.substring(n + 1).split("&"); //$NON-NLS-1$
for (String requestParam : requestParams) {
String[] nv = requestParam.split("="); //$NON-NLS-1$
if (nv.length == 1) {
postMethod.addParameter(nv[0], ""); //$NON-NLS-1$
} else {
String value = evaluateParams(nv[1], getParams(repository, params), false);
postMethod.addParameter(nv[0], value);
}
}
return postMethod;
}
private static String requestResource(String url, HttpClient client, HostConfiguration hostConfiguration,
HttpMethod method) throws IOException, HttpException {
String refreshUrl = null;
try {
client.executeMethod(hostConfiguration, method);
// int statusCode = client.executeMethod(method);
// if (statusCode == 300 || statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 307) {
// Header location = method.getResponseHeader("Location");
// if (location != null) {
// refreshUrl = location.getValue();
// if (!refreshUrl.startsWith("/")) {
// refreshUrl = "/" + refreshUrl;
// }
// }
// }
refreshUrl = getRefreshUrl(url, method);
if (refreshUrl == null) {
return method.getResponseBodyAsString();
}
} finally {
method.releaseConnection();
}
method = new GetMethod(refreshUrl);
try {
client.executeMethod(hostConfiguration, method);
return method.getResponseBodyAsString();
} finally {
method.releaseConnection();
}
}
private static String getRefreshUrl(String url, HttpMethod method) {
Header refreshHeader = method.getResponseHeader("Refresh"); //$NON-NLS-1$
if (refreshHeader == null) {
return null;
}
String value = refreshHeader.getValue();
int n = value.indexOf(";url="); //$NON-NLS-1$
if (n == -1) {
return null;
}
value = value.substring(n + 5);
int requestPath;
if (value.charAt(0) == '/') {
int colonSlashSlash = url.indexOf("://"); //$NON-NLS-1$
requestPath = url.indexOf('/', colonSlashSlash + 3);
} else {
requestPath = url.lastIndexOf('/');
}
String refreshUrl;
if (requestPath == -1) {
refreshUrl = url + "/" + value; //$NON-NLS-1$
} else {
refreshUrl = url.substring(0, requestPath + 1) + value;
}
return refreshUrl;
}
public static String evaluateParams(String value, Map<String, String> params, TaskRepository repository) {
return evaluateParams(value, getParams(repository, params), true);
}
public static String evaluateParams(String value, TaskRepository repository) {
return evaluateParams(value, getParams(repository, null), true);
}
private static String evaluateParams(String value, Map<String, String> params, boolean encode) {
if (value == null || value.indexOf("${") == -1) { //$NON-NLS-1$
return value;
}
int n = 0;
int n1 = value.indexOf("${"); //$NON-NLS-1$
StringBuilder evaluatedValue = new StringBuilder(value.length());
while (n1 > -1) {
evaluatedValue.append(value.substring(n, n1));
int n2 = value.indexOf("}", n1); //$NON-NLS-1$
if (n2 > -1) {
String key = value.substring(n1 + 2, n2);
if (PARAM_SERVER_URL.equals(key) || PARAM_USER_ID.equals(key) || PARAM_PASSWORD.equals(key)) {
evaluatedValue.append(evaluateParams(params.get(key), params, false));
} else {
String val = evaluateParams(params.get(PARAM_PREFIX + key), params, false);
evaluatedValue.append(encode ? encode(val) : val);
}
}
n = n2 + 1;
n1 = value.indexOf("${", n2); //$NON-NLS-1$
}
if (n > -1) {
evaluatedValue.append(value.substring(n));
}
return evaluatedValue.toString();
}
private static Map<String, String> getParams(TaskRepository repository, Map<String, String> params) {
Map<String, String> mergedParams = new LinkedHashMap<String, String>(repository.getProperties());
mergedParams.put(PARAM_SERVER_URL, repository.getRepositoryUrl());
AuthenticationCredentials credentials = repository.getCredentials(AuthenticationType.REPOSITORY);
if (credentials != null) {
mergedParams.put(PARAM_USER_ID, credentials.getUserName());
mergedParams.put(PARAM_PASSWORD, credentials.getPassword());
}
if (params != null) {
mergedParams.putAll(params);
}
return mergedParams;
}
private static String encode(String value) {
try {
return new URLCodec().encode(value);
} catch (EncoderException ex) {
return value;
}
}
public static List<String> getTemplateVariables(String value) {
if (value == null) {
return Collections.emptyList();
}
List<String> vars = new ArrayList<String>();
Matcher m = Pattern.compile("\\$\\{(.+?)\\}").matcher(value); //$NON-NLS-1$
while (m.find()) {
vars.add(m.group(1));
}
return vars;
}
@Override
public boolean hasLocalCompletionState(TaskRepository taskRepository, ITask task) {
return true;
}
@Override
public boolean hasTaskChanged(TaskRepository taskRepository, ITask task, TaskData taskData) {
preProcessTaskData(task, taskData);
return new TaskMapper(taskData).hasChanges(task);
}
}