package com.gratex.perconik.activity.ide.listeners; import java.io.File; import java.util.Map; import javax.annotation.concurrent.GuardedBy; import org.eclipse.jgit.events.RefsChangedEvent; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import com.gratex.perconik.activity.ide.IdeData; import com.gratex.perconik.activity.uaca.IdeUacaProxy; import com.gratex.perconik.services.uaca.ide.IdeCheckinEventRequest; import sk.stuba.fiit.perconik.core.listeners.GitReferenceListener; import sk.stuba.fiit.perconik.eclipse.jgit.lib.GitRepositories; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.collect.Maps.newHashMap; import static com.gratex.perconik.activity.ide.IdeData.setApplicationData; import static com.gratex.perconik.activity.ide.IdeData.setEventData; import static com.gratex.perconik.activity.ide.listeners.Utilities.currentTime; /** * A listener of IDE commit events. This listener handles desired * events and eventually builds corresponding data transfer objects * of type {@link IdeCheckinEventRequest} and passes them to the * {@link IdeUacaProxy} to be transferred into the <i>User Activity Central * Application</i> for further processing. * * <p>Commit listener listens to Git commit events only. * * <p>Data available in an {@code IdeCheckinEventRequest}: * * <ul> * <li>{@code changesetIdInRcs} - current Git commit * identifier (40 hexadecimal characters), * for example {@code "ffba951d35f710abee873db3f5547043aeb3fde9"}. * <li>{@code rcsServer} - see {@code RcsServerDto} below. * <li>See {@link IdeListener} for documentation of inherited data. * </ul> * * <p>Data available in an {@code RcsServerDto}: * * <ul> * <li>{@code url} - remote origin URL from the nearest Git repository, * for example {@code https://github.com/perconik/perconik.git}. The nearest * Git repository is the first one found on path starting in project root, * going through workspace root down to the file system root. * <li>{@code typeUri} - always {@code "git"}. * </ul> * * @author Pavol Zbell * @since 1.0 */ public final class IdeCommitListener extends IdeListener implements GitReferenceListener { // TODO initialize cache in postRegister with Repository repository: fromWorkspace(getWorkspace()).values() private final Object lock = new Object(); @GuardedBy("lock") private final Map<File, Map<String, String>> cache; public IdeCommitListener() { this.cache = newHashMap(); } private boolean updateLastCommit(final File directory, final String branch, final String id) { Map<String, String> cache; synchronized (this.lock) { cache = this.cache.get(directory); if (cache == null) { this.cache.put(directory, cache = newHashMap()); } } synchronized (cache) { String last = cache.get(branch); if (!id.equals(last)) { cache.put(branch, id); return last != null; } } return false; } static IdeCheckinEventRequest build(final long time, final String url, final String id) { final IdeCheckinEventRequest data = new IdeCheckinEventRequest(); data.setChangesetIdInRcs(id); data.setRcsServer(IdeData.newGitServerData(url)); setApplicationData(data); setEventData(data, time); return data; } void process(final long time, final RefsChangedEvent event) { Repository repository = event.getRepository(); File directory = repository.getDirectory(); String url = GitRepositories.getRemoteOriginUrl(repository); checkArgument(url != null, "Unable to get remote origin url from %s", directory); String branch = GitRepositories.getShortBranch(repository); RevCommit commit = GitRepositories.getMostRecentCommit(repository); String id = commit.getName(); if (this.updateLastCommit(directory, branch, id)) { this.proxy.sendCheckinEvent(build(time, url, id)); } } public void onRefsChanged(final RefsChangedEvent event) { final long time = currentTime(); execute(new Runnable() { public void run() { process(time, event); } }); } }