/******************************************************************************* * Copyright (c) 2006, 2016 Mountainminds GmbH & Co. KG and Contributors * 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: * Marc R. Hoffmann - initial API and implementation * ******************************************************************************/ package com.mountainminds.eclemma.internal.core; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.jdt.core.IPackageFragmentRoot; import com.mountainminds.eclemma.core.ICoverageSession; import com.mountainminds.eclemma.core.IExecutionDataSource; import com.mountainminds.eclemma.core.ISessionListener; import com.mountainminds.eclemma.core.ISessionManager; /** * ISessionManager implementation. */ public class SessionManager implements ISessionManager { private final ExecutionDataFiles executiondatafiles; private final Object lock; private final List<ISessionListener> listeners; private final List<ICoverageSession> sessions; private final Map<Object, List<ICoverageSession>> launchmap; private ICoverageSession activeSession; public SessionManager(ExecutionDataFiles executiondatafiles) { this.executiondatafiles = executiondatafiles; this.lock = new Object(); this.listeners = new ArrayList<ISessionListener>(); this.sessions = new ArrayList<ICoverageSession>(); this.launchmap = new HashMap<Object, List<ICoverageSession>>(); this.activeSession = null; } public void addSession(ICoverageSession session, boolean activate, ILaunch launch) { synchronized (lock) { if (session == null) { throw new IllegalArgumentException(); } if (!sessions.contains(session)) { sessions.add(session); if (launch != null) { List<ICoverageSession> l = launchmap.get(launch); if (l == null) { l = new ArrayList<ICoverageSession>(); launchmap.put(launch, l); } l.add(session); } fireSessionAdded(session); } if (activate) { activeSession = session; fireSessionActivated(session); } } } public void removeSession(ICoverageSession session) { synchronized (lock) { removeSessions(Collections.singleton(session)); } } public void removeSessionsFor(ILaunch launch) { synchronized (lock) { final List<ICoverageSession> sessionsToRemove = launchmap.get(launch); if (sessionsToRemove != null) { removeSessions(sessionsToRemove); } } } public void removeAllSessions() { synchronized (lock) { removeSessions(sessions); } } private void removeSessions(Collection<ICoverageSession> sessionsToRemove) { // Clone as in some scenarios we're modifying the caller's instance sessionsToRemove = new ArrayList<ICoverageSession>(sessionsToRemove); // Remove Sessions List<ICoverageSession> removedSessions = new ArrayList<ICoverageSession>(); for (final ICoverageSession s : sessionsToRemove) { if (sessions.remove(s)) { removedSessions.add(s); for (final List<ICoverageSession> mappedSessions : launchmap.values()) { mappedSessions.remove(s); } } } // Activate other session if active session was removed: final boolean actived = sessionsToRemove.contains(activeSession); if (actived) { final int size = sessions.size(); activeSession = size == 0 ? null : sessions.get(size - 1); } // Fire events: for (ICoverageSession s : removedSessions) { fireSessionRemoved(s); } if (actived) { fireSessionActivated(activeSession); } } public List<ICoverageSession> getSessions() { synchronized (lock) { return new ArrayList<ICoverageSession>(sessions); } } public void activateSession(ICoverageSession session) { synchronized (lock) { if (sessions.contains(session) && !session.equals(activeSession)) { activeSession = session; fireSessionActivated(session); } } } public ICoverageSession getActiveSession() { synchronized (lock) { return activeSession; } } public void refreshActiveSession() { synchronized (lock) { if (activeSession != null) { fireSessionActivated(activeSession); } } } public ICoverageSession mergeSessions(Collection<ICoverageSession> sessions, String description, IProgressMonitor monitor) throws CoreException { monitor.beginTask(CoreMessages.MergingCoverageSessions_task, sessions.size()); // Merge all sessions final Set<IPackageFragmentRoot> scope = new HashSet<IPackageFragmentRoot>(); final Set<ILaunchConfiguration> launches = new HashSet<ILaunchConfiguration>(); final MemoryExecutionDataSource memory = new MemoryExecutionDataSource(); for (ICoverageSession session : sessions) { scope.addAll(session.getScope()); if (session.getLaunchConfiguration() != null) { launches.add(session.getLaunchConfiguration()); } session.accept(memory, memory); monitor.worked(1); } final IExecutionDataSource executionDataSource = executiondatafiles .newFile(memory); // Adopt launch configuration only if there is exactly one final ILaunchConfiguration launchconfiguration = launches.size() == 1 ? launches .iterator().next() : null; final ICoverageSession merged = new CoverageSession(description, scope, executionDataSource, launchconfiguration); // Update session list synchronized (lock) { addSession(merged, true, null); for (ICoverageSession session : sessions) { removeSession(session); } } monitor.done(); return merged; } public void addSessionListener(ISessionListener listener) { if (listener == null) { throw new IllegalArgumentException(); } synchronized (lock) { if (!listeners.contains(listener)) { listeners.add(listener); } } } public void removeSessionListener(ISessionListener listener) { synchronized (lock) { listeners.remove(listener); } } private void fireSessionAdded(ICoverageSession session) { // copy to avoid concurrent modification issues for (ISessionListener l : new ArrayList<ISessionListener>(listeners)) { l.sessionAdded(session); } } private void fireSessionRemoved(ICoverageSession session) { // copy to avoid concurrent modification issues for (ISessionListener l : new ArrayList<ISessionListener>(listeners)) { l.sessionRemoved(session); } } private void fireSessionActivated(ICoverageSession session) { // copy to avoid concurrent modification issues for (ISessionListener l : new ArrayList<ISessionListener>(listeners)) { l.sessionActivated(session); } } }