Skip to main content
summaryrefslogblamecommitdiffstats
blob: 5c943bd602a4e20fa735ffa61c816acea0ff10d7 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                                
                                                                



                                                                        

                                                                                 
                                             
 
                    
                                      
                           
                      
                      
                     
 
                                              
                                                 
                                        
                                       





                                                                           
                                                              

                                                                
                                                 
                                                            
                                                   



                                                            
                                                   
                                                                  





                                                                          
                                                                                                         
 
                                                
 
                                                                                    
 
                                                                                          
 

                                                                                                                  
                                          
                                                               
         
 
                 
                                                                    
                            


                 
                                                                        
                            

         
                                                                        












                                                                                          

                                                     

         
                 




                                    
                                          
                                                      






                                                               

                                                                    

         
                 








                                                                                                   
                                                                       


                                                                       
                 
                                                                 
                                         


                 
                                                             
                                       

         
                 
                                                                                                    
                                                                        
                                                         

                                                                                                      
                                                                                                                  
                                                                                               
                                               
                                                                                                

                         
         
 
                 
                                                                                                                       
                                                         
 

                                                                             
                                       
                     
                                                                                  
                                                                   
                                                                                                          
                         
 
                                                           
                                                                                                             

                                                                                     
                         
                                       
                                                                      
                 

                                        
         
 
                 

                                                                                                                   

                                                                                             
 



                                                                                   
 

                                                                                                    




                                                                 
 

                                                 
                                                                                                                        

                                                           
 




                                                                                                  
                                                     
                                 
 









                                                                                                                               
 
                                                                 
                                                                                   
                                                               
                                                                    

                                         


                                               
                                                                                                
                         

                                       


                 
                 

                                                                                                                        
                                                                                                






                                                                                                      
                                                                                   
                                                                                     
                                                       

                                                                                                
                         
                 
 
                            

         
                 
                                                                                         
                                                                             

                                                     

         
                 
                                                                                                  
                                                      
                                       
                                                                         

                                                                                                                   
                                                                                                               
                                                                                                                                           
                                                                                                                    
                                                                                            
                                                


                 




                                                                                                               
                                                                            


                 

                                                                  
                                              

                                                                                                                   
                         
                                                                                                        



                                     


                                                                        
                                                                                            
                                                           
                                                                      
                 
                                                                                     
                                                                                           
                                                        
                                                                                      
                                                                                                       




                                                                  
                             
                                                                
                 

         
                                                                          


                                                                              
                                                                        


                                                                              
                                                                                           


                                                 
                                                                                                  








                                                                              
                 
                                                                                                                



                                                                                          

                                                                                                                   
                 
         
 





                                                                            
 



                                         
 
                                                                                                  

                                                                              
 

                                                                                
                                                                                          

                                                             
                                                                                         

                         


















                                                                                                       
                                                                                                                       



                                                            
                 
                                                              
 


















                                                                                                      
 

                              
 










                                                                                                                                
 
/*******************************************************************************
 * Copyright (c) 2004, 2007 Mylyn project committers 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
 *******************************************************************************/

package org.eclipse.mylyn.internal.trac.core;

import java.io.File;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

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.internal.trac.core.ITracClient.Version;
import org.eclipse.mylyn.internal.trac.core.TracAttributeFactory.Attribute;
import org.eclipse.mylyn.internal.trac.core.TracTask.Kind;
import org.eclipse.mylyn.internal.trac.core.model.TracTicket;
import org.eclipse.mylyn.internal.trac.core.model.TracTicket.Key;
import org.eclipse.mylyn.internal.trac.core.util.TracUtils;
import org.eclipse.mylyn.tasks.core.AbstractAttachmentHandler;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryQuery;
import org.eclipse.mylyn.tasks.core.AbstractTask;
import org.eclipse.mylyn.tasks.core.AbstractTaskDataHandler;
import org.eclipse.mylyn.tasks.core.ITaskCollector;
import org.eclipse.mylyn.tasks.core.RepositoryOperation;
import org.eclipse.mylyn.tasks.core.RepositoryStatus;
import org.eclipse.mylyn.tasks.core.RepositoryTaskAttribute;
import org.eclipse.mylyn.tasks.core.RepositoryTaskData;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.core.TaskRepositoryLocationFactory;

/**
 * @author Steffen Pingel
 */
public class TracRepositoryConnector extends AbstractRepositoryConnector {

	private final static String CLIENT_LABEL = "Trac (supports 0.9 or 0.10 through Web and XML-RPC)";

	private TracClientManager clientManager;

	private TracTaskDataHandler taskDataHandler = new TracTaskDataHandler(this);

	private TracAttachmentHandler attachmentHandler = new TracAttachmentHandler(this);

	private TaskRepositoryLocationFactory taskRepositoryLocationFactory = new TaskRepositoryLocationFactory();
	
	public TracRepositoryConnector() {
		TracCorePlugin.getDefault().setConnector(this);
	}

	@Override
	public boolean canCreateNewTask(TaskRepository repository) {
		return true;
	}

	@Override
	public boolean canCreateTaskFromKey(TaskRepository repository) {
		return true;
	}

	private TracWikiHandler wikiHandler = new TracWikiHandler(this);

	public boolean hasWiki(TaskRepository repository) {
		// check the access mode to validate Wiki support
		try {
			ITracClient client = getClientManager().getRepository(repository);
			if (client instanceof ITracWikiClient) {
				return true;
			}
		} catch (MalformedURLException e) {
		}
		return false;
	}

	public AbstractWikiHandler getWikiHandler() {
		return wikiHandler;
	}

	@Override
	public String getLabel() {
		return CLIENT_LABEL;
	}

	@Override
	public String getConnectorKind() {
		return TracCorePlugin.REPOSITORY_KIND;
	}

	@Override
	public String getRepositoryUrlFromTaskUrl(String url) {
		if (url == null) {
			return null;
		}
		int index = url.lastIndexOf(ITracClient.TICKET_URL);
		return index == -1 ? null : url.substring(0, index);
	}

	@Override
	public String getTaskIdFromTaskUrl(String url) {
		if (url == null) {
			return null;
		}
		int index = url.lastIndexOf(ITracClient.TICKET_URL);
		return index == -1 ? null : url.substring(index + ITracClient.TICKET_URL.length());
	}

	@Override
	public String getTaskUrl(String repositoryUrl, String taskId) {
		return repositoryUrl + ITracClient.TICKET_URL + taskId;
	}

	@Override
	public AbstractAttachmentHandler getAttachmentHandler() {
		return attachmentHandler;
	}

	@Override
	public AbstractTaskDataHandler getTaskDataHandler() {
		return taskDataHandler;
	}

	@Override
	public void updateTaskFromRepository(TaskRepository repository, AbstractTask repositoryTask,
			IProgressMonitor monitor) throws CoreException {
		if (repositoryTask instanceof TracTask) {
			try {
				ITracClient connection = getClientManager().getRepository(repository);
				TracTicket ticket = connection.getTicket(getTicketId(repositoryTask.getTaskId()));
				updateTaskFromTicket((TracTask) repositoryTask, ticket, false);
			} catch (Exception e) {
				throw new CoreException(TracCorePlugin.toStatus(e, repository));
			}
		}
	}

	@Override
	public IStatus performQuery(AbstractRepositoryQuery query, TaskRepository repository, IProgressMonitor monitor,
			ITaskCollector resultCollector) {

		final List<TracTicket> tickets = new ArrayList<TracTicket>();

		ITracClient tracClient;
		try {
			tracClient = getClientManager().getRepository(repository);
			if (query instanceof TracRepositoryQuery) {
				tracClient.search(((TracRepositoryQuery) query).getTracSearch(), tickets);
			}

			for (TracTicket ticket : tickets) {
				AbstractTask task = createTask(repository.getUrl(), ticket.getId() + "", "");
				updateTaskFromTicket((TracTask) task, ticket, false);
				resultCollector.accept(task);
			}
		} catch (Throwable e) {
			return TracCorePlugin.toStatus(e, repository);
		}

		return Status.OK_STATUS;
	}

	@Override
	public boolean markStaleTasks(TaskRepository repository, Set<AbstractTask> tasks, IProgressMonitor monitor)
			throws CoreException {
		try {
			monitor.beginTask("Getting changed tasks", IProgressMonitor.UNKNOWN);

			if (!TracRepositoryConnector.hasChangedSince(repository)) {
				// always run the queries for web mode
				return true;
			}

			if (repository.getSynchronizationTimeStamp() == null
					|| repository.getSynchronizationTimeStamp().length() == 0) {
				for (AbstractTask task : tasks) {
					task.setStale(true);
				}
				return true;
			}

			Date since = new Date(0);
			try {
				since = TracUtils.parseDate(Integer.parseInt(repository.getSynchronizationTimeStamp()));
			} catch (NumberFormatException e) {
			}

			try {
				ITracClient client = getClientManager().getRepository(repository);
				Set<Integer> ids = client.getChangedTickets(since);
				if (ids.isEmpty()) {
					// repository is unchanged
					return false;
				}

				if (ids.size() == 1) {
					// getChangedTickets() is expected to always return at least one ticket because
					// the repository synchronization timestamp is set to the most recent modification date
					Integer id = ids.iterator().next();
					Date lastChanged = client.getTicketLastChanged(id);
					if (since.equals(lastChanged)) {
						// repository didn't actually change
						return false;
					}
				}

				for (AbstractTask task : tasks) {
					Integer id = getTicketId(task.getTaskId());
					if (ids.contains(id)) {
						task.setStale(true);
					}
				}

				return true;
			} catch (Exception e) {
				throw new CoreException(TracCorePlugin.toStatus(e, repository));
			}
		} finally {
			monitor.done();
		}
	}

	@Override
	public AbstractTask createTaskFromExistingId(TaskRepository repository, String taskId, IProgressMonitor monitor)
			throws CoreException {
		AbstractTask task = super.createTaskFromExistingId(repository, taskId, monitor);
		if (task == null) {
			// repository does not support XML-RPC, fall back to web access
			try {
				int taskIdInt = getTicketId(taskId);
				ITracClient connection = getClientManager().getRepository(repository);
				TracTicket ticket = connection.getTicket(taskIdInt);

				task = createTask(repository.getUrl(), taskId, "");
				updateTaskFromTicket((TracTask) task, ticket, false);
				taskList.addTask(task);
			} catch (Exception e) {
				throw new CoreException(TracCorePlugin.toStatus(e, repository));
			}
		}

		return task;
	}

	@Override
	public AbstractTask createTask(String repositoryUrl, String id, String summary) {
		TracTask tracTask = new TracTask(repositoryUrl, id, summary);
		tracTask.setCreationDate(new Date());
		return tracTask;
	}

	@Override
	public void updateTaskFromTaskData(TaskRepository repository, AbstractTask repositoryTask,
			RepositoryTaskData taskData) {
		if (taskData != null) {
			repositoryTask.setSummary(taskData.getSummary());
			repositoryTask.setOwner(taskData.getAttributeValue(RepositoryTaskAttribute.USER_ASSIGNED));
			repositoryTask.setCompleted(TracTask.isCompleted(taskData.getStatus()));
			repositoryTask.setUrl(repository.getUrl() + ITracClient.TICKET_URL + taskData.getId());
			repositoryTask.setPriority(TracTask.getMylynPriority(taskData.getAttributeValue(Attribute.PRIORITY.getTracKey())));
			Kind kind = TracTask.Kind.fromType(taskData.getAttributeValue(Attribute.TYPE.getTracKey()));
			repositoryTask.setTaskKind((kind != null) ? kind.toString() : null);
			// TODO: Completion Date
		}
	}

	public static int getTicketId(String taskId) throws CoreException {
		try {
			return Integer.parseInt(taskId);
		} catch (NumberFormatException e) {
			throw new CoreException(new Status(IStatus.ERROR, TracCorePlugin.PLUGIN_ID, IStatus.OK,
					"Invalid ticket id: " + taskId, e));
		}
	}

	public synchronized TracClientManager getClientManager() {
		if (clientManager == null) {
			File cacheFile = null;
			if (TracCorePlugin.getDefault().getRepostioryAttributeCachePath() != null) {
				cacheFile = TracCorePlugin.getDefault().getRepostioryAttributeCachePath().toFile();
			}
			clientManager = new TracClientManager(cacheFile, taskRepositoryLocationFactory);
		}
		return clientManager;
	}

	/**
	 * Updates fields of <code>task</code> from <code>ticket</code>.
	 */
	public void updateTaskFromTicket(TracTask task, TracTicket ticket, boolean notify) {
		if (ticket.getValue(Key.SUMMARY) != null) {
			task.setSummary(ticket.getValue(Key.SUMMARY));
		}
		task.setCompleted(TracTask.isCompleted(ticket.getValue(Key.STATUS)));
		task.setPriority(TracTask.getMylynPriority(ticket.getValue(Key.PRIORITY)));
		if (ticket.getValue(Key.TYPE) != null) {
			Kind kind = TracTask.Kind.fromType(ticket.getValue(Key.TYPE));
			task.setTaskKind((kind != null) ? kind.toString() : ticket.getValue(Key.TYPE));
		}
		if (ticket.getCreated() != null) {
			task.setCreationDate(ticket.getCreated());
		}

		if (notify) {
			taskList.notifyTaskChanged(task, false);
		}
	}

	public static boolean hasChangedSince(TaskRepository repository) {
		return Version.XML_RPC.name().equals(repository.getVersion());
	}

	public static boolean hasRichEditor(TaskRepository repository) {
		return Version.XML_RPC.name().equals(repository.getVersion());
	}

	public static boolean hasRichEditor(TaskRepository repository, AbstractTask task) {
		return hasRichEditor(repository);
	}

	public static boolean hasAttachmentSupport(TaskRepository repository, AbstractTask task) {
		return Version.XML_RPC.name().equals(repository.getVersion());
	}

	public void stop() {
		if (clientManager != null) {
			clientManager.writeCache();
		}
	}

	@Override
	public void updateAttributes(TaskRepository repository, IProgressMonitor monitor) throws CoreException {
		try {
			ITracClient client = getClientManager().getRepository(repository);
			client.updateAttributes(monitor, true);
		} catch (Exception e) {
			throw new CoreException(RepositoryStatus.createStatus(repository.getUrl(), IStatus.WARNING,
					TracCorePlugin.PLUGIN_ID, "Could not update attributes"));
		}
	}

	public static String getDisplayUsername(TaskRepository repository) {
		if (!repository.hasCredentials()) {
			return ITracClient.DEFAULT_USERNAME;
		}
		return repository.getUserName();
	}

	@Override
	public String getTaskIdPrefix() {
		return "#";
	}

	public static TracTicket getTracTicket(TaskRepository repository, RepositoryTaskData data)
			throws InvalidTicketException, CoreException {
		TracTicket ticket = new TracTicket(getTicketId(data.getId()));

		List<RepositoryTaskAttribute> attributes = data.getAttributes();
		for (RepositoryTaskAttribute attribute : attributes) {
			if (TracAttributeFactory.isInternalAttribute(attribute.getId())) {
				// ignore
			} else if (!attribute.isReadOnly()) {
				ticket.putValue(attribute.getId(), attribute.getValue());
			}
		}

		// set cc value
		StringBuilder sb = new StringBuilder();
		List<String> removeValues = data.getAttributeValues(RepositoryTaskAttribute.REMOVE_CC);
		List<String> values = data.getAttributeValues(RepositoryTaskAttribute.USER_CC);
		for (String user : values) {
			if (!removeValues.contains(user)) {
				if (sb.length() > 0) {
					sb.append(",");
				}
				sb.append(user);
			}
		}
		if (data.getAttributeValue(RepositoryTaskAttribute.NEW_CC).length() > 0) {
			if (sb.length() > 0) {
				sb.append(",");
			}
			sb.append(data.getAttributeValue(RepositoryTaskAttribute.NEW_CC));
		}
		if (RepositoryTaskAttribute.TRUE.equals(data.getAttributeValue(RepositoryTaskAttribute.ADD_SELF_CC))) {
			if (sb.length() > 0) {
				sb.append(",");
			}
			sb.append(repository.getUserName());
		}
		ticket.putBuiltinValue(Key.CC, sb.toString());

		RepositoryOperation operation = data.getSelectedOperation();
		if (operation != null) {
			String action = operation.getKnobName();
			if (!"leave".equals(action)) {
				if ("accept".equals(action)) {
					ticket.putValue("status", "assigned");
					ticket.putValue("owner", getDisplayUsername(repository));
				} else if ("resolve".equals(action)) {
					ticket.putValue("status", "closed");
					ticket.putValue("resolution", operation.getOptionSelection());
				} else if ("reopen".equals(action)) {
					ticket.putValue("status", "reopened");
					ticket.putValue("resolution", "");
				} else if ("reassign".equals(operation.getKnobName())) {
					ticket.putValue("status", "new");
					ticket.putValue("owner", operation.getInputValue());
				}
			}
		}

		return ticket;
	}

	public TaskRepositoryLocationFactory getTaskRepositoryLocationFactory() {
		return taskRepositoryLocationFactory;
	}
	
	public synchronized void setTaskRepositoryLocationFactory(TaskRepositoryLocationFactory taskRepositoryLocationFactory) {
		this.taskRepositoryLocationFactory = taskRepositoryLocationFactory;
		if (this.clientManager != null) {
			clientManager.setTaskRepositoryLocationFactory(taskRepositoryLocationFactory);
		}
	}
	
}

Back to the top