/******************************************************************************* * Copyright (c) 2013 BREDEX GmbH. * 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: * BREDEX GmbH - initial API and implementation and/or initial documentation *******************************************************************************/ package org.eclipse.jubula.client.alm.mylyn.core.utils; import java.lang.reflect.InvocationTargetException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.lang.StringUtils; 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.jubula.client.alm.mylyn.core.Activator; import org.eclipse.jubula.client.alm.mylyn.core.bp.CommentReporter; import org.eclipse.jubula.client.alm.mylyn.core.i18n.Messages; import org.eclipse.jubula.client.alm.mylyn.core.model.ALMChange; import org.eclipse.jubula.client.alm.mylyn.core.model.CommentEntry; import org.eclipse.jubula.client.alm.mylyn.core.model.FieldUpdate; import org.eclipse.jubula.client.core.utils.IParamValueToken; import org.eclipse.jubula.client.core.utils.ParamValueConverter; import org.eclipse.jubula.client.core.utils.SimpleStringConverter; import org.eclipse.jubula.client.core.utils.VariableToken; import org.eclipse.jubula.mylyn.utils.MylynAccess; import org.eclipse.jubula.mylyn.utils.MylynAccess.CONNECTOR; import org.eclipse.jubula.tools.internal.constants.StringConstants; import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector; import org.eclipse.mylyn.tasks.core.ITask; import org.eclipse.mylyn.tasks.core.RepositoryResponse; import org.eclipse.mylyn.tasks.core.TaskRepository; import org.eclipse.mylyn.tasks.core.data.AbstractTaskDataHandler; import org.eclipse.mylyn.tasks.core.data.ITaskDataManager; import org.eclipse.mylyn.tasks.core.data.ITaskDataWorkingCopy; import org.eclipse.mylyn.tasks.core.data.TaskAttribute; import org.eclipse.mylyn.tasks.core.data.TaskData; import org.eclipse.mylyn.tasks.core.data.TaskDataModel; import org.eclipse.mylyn.tasks.ui.TasksUi; import org.eclipse.osgi.util.NLS; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author BREDEX GmbH */ public final class ALMAccess { /** * Exception for Problems with resolving a variable * @author BREDEX GmbH */ public static class CouldNotResolveException extends Exception { /** Could not not resolve a variable or similar */ public CouldNotResolveException() { super(); } /** Could not not resolve a variable or similar * @param message the message or the value */ public CouldNotResolveException(String message) { super(message); } } /** the logger */ private static final Logger LOG = LoggerFactory.getLogger(ALMAccess.class); /** the postfix for a variable to generate the date in a specific format*/ private static final String VARIABLE_DATE_POSTFIX = "date"; //$NON-NLS-1$ /** the postfix for a variable to generate the url*/ private static final String VARIABLE_URL_POSTFIX = "url"; //$NON-NLS-1$ /** the prefix for the variable when to use the summary */ private static final String VARIABLE_SUMMARY_PREFIX = "summary"; //$NON-NLS-1$ /** the prefix for the variable when to use the node */ private static final String VARIABLE_NODE_PREFIX = "node"; //$NON-NLS-1$ /** Constructor */ private ALMAccess() { // hide } /** * Writes comments to ALM system * @param repoLabel * repoLabel * @param taskId * the taskId * @param comments * the comment entries * @param monitor * the monitor to use * @return true if succeeded; false otherwise */ public static boolean createComment(String repoLabel, String taskId, List<CommentEntry> comments, IProgressMonitor monitor) { boolean succeeded = false; TaskRepository repo = MylynAccess.getRepositoryByLabel(repoLabel); try { TaskData taskData = MylynAccess .getTaskDataByID(repo, taskId, monitor); if (taskData == null) { return succeeded; } String connectorKind = repo.getConnectorKind(); AbstractRepositoryConnector connector = TasksUi .getRepositoryConnector(connectorKind); ITask task = MylynAccess.getTaskByID(repo, taskData.getTaskId(), monitor); if (task != null) { ITaskDataManager taskDataManager = TasksUi.getTaskDataManager(); ITaskDataWorkingCopy taskWorkingCopy = taskDataManager .createWorkingCopy(task, taskData); TaskDataModel taskModel = new TaskDataModel(repo, task, taskWorkingCopy); TaskAttribute rootData = taskModel.getTaskData() .getRoot(); CONNECTOR handle = determineConnectorHandling(connectorKind); TaskAttribute change = null; switch (handle) { case HP_ALM: change = hpAlmCommentHandling(comments, rootData); break; case DEFAULT: default: change = defaultCommentHandling(comments, rootData); break; } if (change == null) { return succeeded; } AbstractTaskDataHandler taskDataHandler = connector .getTaskDataHandler(); RepositoryResponse response = taskDataHandler.postTaskData( taskModel.getTaskRepository(), taskModel.getTaskData(), taskModel.getChangedOldAttributes(), monitor); succeeded = RepositoryResponse.ResponseKind.TASK_UPDATED .equals(response.getReposonseKind()); } } catch (CoreException e) { LOG.error(e.getLocalizedMessage(), e); } return succeeded; } /** * Updates fields in ALM system * * @param repoLabel * name of repository * @param taskId * task id * @param fieldUpdates * list of field updates * @param monitor * monitor * @return OK if succeeded; WARNING when problems; ERROR otherwise */ public static IStatus updateFields(String repoLabel, String taskId, List<FieldUpdate> fieldUpdates, IProgressMonitor monitor) { IStatus status; try { TaskRepository repo = MylynAccess.getRepositoryByLabel(repoLabel); status = MylynAccess.updateAttributes(repo, taskId, attributeUpdateMapping(fieldUpdates), monitor); } catch (CouldNotResolveException e) { status = new Status(IStatus.CANCEL, Activator.ID, "Could not resolve variable"); //$NON-NLS-1$ } return status; } /** * Creates list of task attributes to change * * @param fieldUpdates * the field updates * @return list of task attributes to change * @throws CouldNotResolveException */ private static List<Map<String, String>> attributeUpdateMapping( List<FieldUpdate> fieldUpdates) throws CouldNotResolveException { List<Map<String, String>> attributeUpdates = new ArrayList<Map<String, String>>(fieldUpdates.size()); boolean failed = false; for (FieldUpdate u : fieldUpdates) { Map<String, String> attributesToChange = u.getAttributesToChange(); for (String key : attributesToChange.keySet()) { String value = attributesToChange.get(key); try { value = getVariableValues(value, u); attributesToChange.put(key, value); } catch (CouldNotResolveException ce) { // First validating all attributes and values before ending failed = true; } } attributeUpdates.add(attributesToChange); } if (failed) { throw new CouldNotResolveException(); } return attributeUpdates; } /** * * @param value the string value which variables of it should be resolved (using our parser) * @param fieldUpdate the {@link FieldUpdate} of the corresponding value * @return a string with all variables resolved * @throws CouldNotResolveException */ private static String getVariableValues(String value, FieldUpdate fieldUpdate) throws CouldNotResolveException { boolean isFailing = false; if (StringUtils.isNotBlank(value)) { ParamValueConverter converter = new SimpleStringConverter(value); if (converter.containsErrors()) { CommentReporter.getInstance().getConsole() .writeErrorLine(NLS.bind( Messages.ParsingReportingRuledFailed, value)); throw new CouldNotResolveException(NLS.bind( Messages.ParsingReportingRuledFailed, value)); } List<IParamValueToken> liste = converter.getTokens(); String result = StringConstants.EMPTY; for (Iterator<IParamValueToken> iter = liste.iterator(); iter.hasNext();) { IParamValueToken iParamValueToken = iter.next(); if (iParamValueToken instanceof VariableToken) { try { result += getBeanString(fieldUpdate, (VariableToken) iParamValueToken); } catch (CouldNotResolveException ce) { isFailing = true; } } else { result += iParamValueToken.getGuiString(); } } if (isFailing) { throw new CouldNotResolveException(); } return result; } return value; } /** * @param comments * the commentEntries to add * @param attr * the attribute to modify * @return a flag indicating the success of attribute handling */ private static TaskAttribute hpAlmCommentHandling( List<CommentEntry> comments, TaskAttribute attr) { Properties almProps = Activator.getDefault().getAlmAccessProperties(); String hpTaskKindKeyPrefix = CONNECTOR.HP_ALM.toString() + StringConstants.DOT + TaskAttribute.TASK_KIND; String req = hpTaskKindKeyPrefix + ".REQUIREMENT"; //$NON-NLS-1$ String hpTaskKindReq = almProps.getProperty(req); String def = hpTaskKindKeyPrefix + ".DEFECT"; //$NON-NLS-1$ String hpTaskKindDefect = almProps.getProperty(def); String taskKindValue = attr.getMappedAttribute( TaskAttribute.TASK_KIND).getValue(); String attrName = null; if (hpTaskKindReq.equals(taskKindValue)) { attrName = almProps.getProperty(req + ".comment"); //$NON-NLS-1$ } else if (hpTaskKindDefect.equals(taskKindValue)) { attrName = almProps.getProperty(def + ".comment"); //$NON-NLS-1$ } if (attrName != null) { TaskAttribute commentAttribute = attr.getMappedAttribute(attrName); String oldComment = commentAttribute.getValue(); String newComment = StringConstants.EMPTY; for (ALMChange c : comments) { newComment = c.toString() + "<br>" //$NON-NLS-1$ + c.getDashboardURL() + "<br>" //$NON-NLS-1$ + newComment; } commentAttribute.setValue(newComment + oldComment); return commentAttribute; } return null; } /** * @param comments * the commentEntries to add * @param attr * the attribute to modify * @return a flag indicating the success of attribute handling */ private static TaskAttribute defaultCommentHandling( List<CommentEntry> comments, TaskAttribute attr) { TaskAttribute newComment = attr .createMappedAttribute(TaskAttribute.COMMENT_NEW); String comment = StringConstants.EMPTY; for (CommentEntry c : comments) { comment = comment + StringConstants.NEWLINE + c.toString() + StringConstants.NEWLINE + c.getDashboardURL() + StringConstants.NEWLINE + StringConstants.NEWLINE; } newComment.setValue(comment); return newComment; } /** * @param connectorKind * the connector kind * @return the connector handling type */ private static CONNECTOR determineConnectorHandling( String connectorKind) { String hpAlmConnectorKind = Activator.getDefault() .getAlmAccessProperties() .getProperty(CONNECTOR.HP_ALM.toString()); if (hpAlmConnectorKind.equals(connectorKind)) { return CONNECTOR.HP_ALM; } return CONNECTOR.DEFAULT; } /** * gets the variable out of the {@link TestResultNode} or {@link ITestResultSummaryPO} * @param fieldUpdate the FieldUpdate which has all necessary information * @param variable the variable which should be parsed. * <code>node.</code> and <code>summary.</code> are allowed with all public * getters given. Also <code>node.url</code> and <code>summary.date</code> * could be used. * @return the String representation the resolved variable */ private static String getBeanString(FieldUpdate fieldUpdate, VariableToken variable) throws CouldNotResolveException { String returnValue = variable.getVariableString(); if (StringUtils.contains(returnValue, '_')) { String[] strings = StringUtils.split(returnValue, "_", 2); //$NON-NLS-1$ try { if (strings[0].equalsIgnoreCase(VARIABLE_NODE_PREFIX)) { if (strings[1].equalsIgnoreCase(VARIABLE_URL_POSTFIX)) { returnValue = fieldUpdate.getDashboardURL(); } else if (strings[1].equalsIgnoreCase( VARIABLE_DATE_POSTFIX)) { returnValue = formatDate(fieldUpdate.getNode() .getTimeStamp()); } else { returnValue = BeanUtils.getProperty( fieldUpdate.getNode(), strings[1]); } } if (strings[0].equalsIgnoreCase(VARIABLE_SUMMARY_PREFIX)) { if (strings[1].equalsIgnoreCase(VARIABLE_DATE_POSTFIX)) { returnValue = formatDate(fieldUpdate.getSummary() .getTestsuiteDate()); } else { returnValue = BeanUtils.getProperty( fieldUpdate.getSummary(), strings[1]); } } } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { CommentReporter.getInstance().getConsole() .writeErrorLine(NLS.bind(Messages.UnresolvableVariable, variable.getGuiString())); throw new CouldNotResolveException(variable.getGuiString()); } } else { returnValue = variable.getGuiString(); CommentReporter.getInstance().getConsole() .writeErrorLine(NLS.bind(Messages.UnresolvableVariable, variable.getGuiString())); throw new CouldNotResolveException(variable.getGuiString()); } return returnValue; } /** * * @param date the date do Format * @return <code>dd.MM.yyyy</code> representation of a {@link Date} */ private static String formatDate(Date date) { return new SimpleDateFormat("dd.MM.yyyy") //$NON-NLS-1$ .format(date); } }