protected CacheBuilder<Object, Object> createCacheBuilder( Duration expireAfterWriteDuration, Duration refreshAfterWriteDuration) { return CacheBuilder.newBuilder() .expireAfterWrite(expireAfterWriteDuration.getValue(), expireAfterWriteDuration.getUnit()) .refreshAfterWrite( refreshAfterWriteDuration.getValue(), refreshAfterWriteDuration.getUnit()); }
public class BugzillaRestConnector extends AbstractRepositoryConnector { public static final Duration CLIENT_CACHE_DURATION = new Duration(24, TimeUnit.HOURS); public static final Duration CONFIGURATION_CACHE_EXPIRE_DURATION = new Duration(7, TimeUnit.DAYS); public static final Duration CONFIGURATION_CACHE_REFRESH_AFTER_WRITE_DURATION = new Duration(1, TimeUnit.DAYS); private static final ThreadLocal<IOperationMonitor> context = new ThreadLocal<IOperationMonitor>(); private boolean ignoredProperty(String propertyName) { if (propertyName.equals(RepositoryLocation.PROPERTY_LABEL) || propertyName.equals(TaskRepository.OFFLINE) || propertyName.equals(IRepositoryConstants.PROPERTY_ENCODING) || propertyName.equals(TaskRepository.PROXY_HOSTNAME) || propertyName.equals(TaskRepository.PROXY_PORT) || propertyName.equals("org.eclipse.mylyn.tasklist.repositories.savePassword") || propertyName.equals("org.eclipse.mylyn.tasklist.repositories.proxy.usedefault") || propertyName.equals("org.eclipse.mylyn.tasklist.repositories.proxy.savePassword") || propertyName.equals("org.eclipse.mylyn.tasklist.repositories.proxy.username") || propertyName.equals("org.eclipse.mylyn.tasklist.repositories.proxy.password") || propertyName.equals("org.eclipse.mylyn.tasklist.repositories.proxy.enabled")) { return true; } return false; } private final PropertyChangeListener repositoryChangeListener4ClientCache = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (ignoredProperty(evt.getPropertyName())) { return; } TaskRepository taskRepository = (TaskRepository) evt.getSource(); clientCache.invalidate(new RepositoryKey(taskRepository)); } }; private final PropertyChangeListener repositoryChangeListener4ConfigurationCache = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (ignoredProperty(evt.getPropertyName()) || evt.getPropertyName().equals("org.eclipse.mylyn.tasklist.repositories.password")) { return; } TaskRepository taskRepository = (TaskRepository) evt.getSource(); configurationCache.invalidate(new RepositoryKey(taskRepository)); } }; private final LoadingCache<RepositoryKey, BugzillaRestClient> clientCache = CacheBuilder.newBuilder() .expireAfterAccess(CLIENT_CACHE_DURATION.getValue(), CLIENT_CACHE_DURATION.getUnit()) .build( new CacheLoader<RepositoryKey, BugzillaRestClient>() { @Override public BugzillaRestClient load(RepositoryKey key) throws Exception { TaskRepository repository = key.getRepository(); repository.addChangeListener(repositoryChangeListener4ClientCache); return createClient(repository); } }); private final LoadingCache<RepositoryKey, Optional<BugzillaRestConfiguration>> configurationCache; public BugzillaRestConnector() { this(CONFIGURATION_CACHE_REFRESH_AFTER_WRITE_DURATION); } public BugzillaRestConnector(Duration refreshAfterWriteDuration) { super(); configurationCache = createCacheBuilder(CONFIGURATION_CACHE_EXPIRE_DURATION, refreshAfterWriteDuration) .build( new CacheLoader<RepositoryKey, Optional<BugzillaRestConfiguration>>() { @Override public Optional<BugzillaRestConfiguration> load(RepositoryKey key) throws Exception { BugzillaRestClient client = clientCache.get(key); TaskRepository repository = key.getRepository(); repository.addChangeListener(repositoryChangeListener4ConfigurationCache); return Optional.fromNullable( client.getConfiguration(key.getRepository(), context.get())); } @Override public ListenableFuture<Optional<BugzillaRestConfiguration>> reload( final RepositoryKey key, Optional<BugzillaRestConfiguration> oldValue) throws Exception { // asynchronous! ListenableFutureJob<Optional<BugzillaRestConfiguration>> job = new ListenableFutureJob<Optional<BugzillaRestConfiguration>>("") { @Override protected IStatus run(IProgressMonitor monitor) { BugzillaRestClient client; try { client = clientCache.get(key); set( Optional.fromNullable( client.getConfiguration(key.getRepository(), context.get()))); } catch (ExecutionException e) { e.printStackTrace(); return new Status( IStatus.ERROR, BugzillaRestCore.ID_PLUGIN, "BugzillaRestConnector reload Configuration", e); } return Status.OK_STATUS; } }; job.schedule(); return job; } }); } protected CacheBuilder<Object, Object> createCacheBuilder( Duration expireAfterWriteDuration, Duration refreshAfterWriteDuration) { return CacheBuilder.newBuilder() .expireAfterWrite(expireAfterWriteDuration.getValue(), expireAfterWriteDuration.getUnit()) .refreshAfterWrite( refreshAfterWriteDuration.getValue(), refreshAfterWriteDuration.getUnit()); } @Override public boolean canCreateNewTask(TaskRepository repository) { return true; } @Override public boolean canCreateTaskFromKey(TaskRepository repository) { // ignore return false; } @Override public String getConnectorKind() { return BugzillaRestCore.CONNECTOR_KIND; } @Override public String getLabel() { return "Bugzilla 5.0 or later with REST"; } @Override public String getRepositoryUrlFromTaskUrl(String taskUrl) { if (taskUrl == null) { return null; } int index = taskUrl.indexOf("/rest.cgi/"); return index == -1 ? null : taskUrl.substring(0, index); } @Override public TaskData getTaskData( TaskRepository repository, String taskIdOrKey, IProgressMonitor monitor) throws CoreException { return ((BugzillaRestTaskDataHandler) getTaskDataHandler()) .getTaskData(repository, taskIdOrKey, monitor); } @Override public String getTaskIdFromTaskUrl(String taskUrl) { // ignore return null; } @Override public String getTaskUrl(String repositoryUrl, String taskIdOrKey) { return repositoryUrl + "/rest.cgi/bug/" + taskIdOrKey; } @Override public boolean hasTaskChanged(TaskRepository taskRepository, ITask task, TaskData taskData) { // ignore return false; } @Override public IStatus performQuery( TaskRepository repository, IRepositoryQuery query, TaskDataCollector collector, ISynchronizationSession session, IProgressMonitor monitor) { // ignore return null; } @Override public void updateRepositoryConfiguration(TaskRepository taskRepository, IProgressMonitor monitor) throws CoreException { context.set(monitor != null ? OperationUtil.convert(monitor) : new NullOperationMonitor()); configurationCache.refresh(new RepositoryKey(taskRepository)); context.remove(); } @Override public void updateTaskFromTaskData(TaskRepository taskRepository, ITask task, TaskData taskData) { task.setUrl(taskData.getRepositoryUrl() + "/rest.cgi/bug/" + taskData.getTaskId()); } @Override public AbstractTaskDataHandler getTaskDataHandler() { return new BugzillaRestTaskDataHandler(this); } private BugzillaRestClient createClient(TaskRepository repository) { RepositoryLocation location = new RepositoryLocation(repository.getProperties()); AuthenticationCredentials credentials1 = repository.getCredentials(org.eclipse.mylyn.commons.net.AuthenticationType.REPOSITORY); UserCredentials credentials = new UserCredentials(credentials1.getUserName(), credentials1.getPassword(), null, true); location.setCredentials(AuthenticationType.REPOSITORY, credentials); BugzillaRestClient client = new BugzillaRestClient(location, this); return client; } /** * Returns the Client for the {@link TaskRepository}. * * @param repository the {@link TaskRepository} object * @return the client Object * @throws CoreException */ public BugzillaRestClient getClient(TaskRepository repository) throws CoreException { try { return clientCache.get(new RepositoryKey(repository)); } catch (ExecutionException e) { throw new CoreException( new Status(IStatus.ERROR, BugzillaRestCore.ID_PLUGIN, "TaskRepositoryManager is null")); } } @Override public RepositoryInfo validateRepository(TaskRepository repository, IProgressMonitor monitor) throws CoreException { try { BugzillaRestClient client = createClient(repository); if (!client.validate(OperationUtil.convert(monitor))) { throw new CoreException( new Status(IStatus.ERROR, BugzillaRestCore.ID_PLUGIN, "repository is invalide")); } BugzillaRestVersion version = client.getVersion(OperationUtil.convert(monitor)); return new RepositoryInfo(new RepositoryVersion(version.toString())); } catch (Exception e) { throw new CoreException( new Status(IStatus.ERROR, BugzillaRestCore.ID_PLUGIN, e.getMessage(), e)); } } public BugzillaRestConfiguration getRepositoryConfiguration(TaskRepository repository) throws CoreException { if (clientCache.getIfPresent(new RepositoryKey(repository)) == null) { getClient(repository); } try { Optional<BugzillaRestConfiguration> configurationOptional = configurationCache.get(new RepositoryKey(repository)); return configurationOptional.isPresent() ? configurationOptional.get() : null; } catch (UncheckedExecutionException e) { throw new CoreException( new Status(IStatus.ERROR, BugzillaRestCore.ID_PLUGIN, e.getMessage(), e)); } catch (ExecutionException e) { throw new CoreException( new Status(IStatus.ERROR, BugzillaRestCore.ID_PLUGIN, e.getMessage(), e)); } } public void clearClientCache() { clientCache.invalidateAll(); } public void clearConfigurationCache() { configurationCache.invalidateAll(); } public void clearAllCaches() { clearClientCache(); clearConfigurationCache(); } @Override public boolean isRepositoryConfigurationStale(TaskRepository repository, IProgressMonitor monitor) throws CoreException { return false; } @Override public ITaskMapping getTaskMapping(final TaskData taskData) { return new TaskMapper(taskData) { @Override public String getTaskKey() { TaskAttribute attribute = getTaskData() .getRoot() .getAttribute(BugzillaRestTaskSchema.getDefault().BUG_ID.getKey()); if (attribute != null) { return attribute.getValue(); } return super.getTaskKey(); } @Override public String getTaskKind() { return taskData.getConnectorKind(); } @Override public String getTaskUrl() { return taskData.getRepositoryUrl(); } }; } }