/******************************************************************************* * Copyright (c) 2013, 2016 Wind River Systems, Inc. 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 * * Contributors: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.te.tcf.launch.core.internal.services; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.eclipse.cdt.debug.core.sourcelookup.MappingSourceContainer; import org.eclipse.cdt.debug.internal.core.sourcelookup.MapEntrySourceContainer; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.model.ISourceLocator; import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector; import org.eclipse.debug.core.sourcelookup.ISourceContainer; import org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate; import org.eclipse.tcf.protocol.IChannel; import org.eclipse.tcf.protocol.IPeer; import org.eclipse.tcf.protocol.IToken; import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.services.IPathMap; import org.eclipse.tcf.services.IPathMap.PathMapRule; import org.eclipse.tcf.te.runtime.callback.AsyncCallbackCollector; import org.eclipse.tcf.te.runtime.callback.Callback; import org.eclipse.tcf.te.runtime.interfaces.callback.ICallback; import org.eclipse.tcf.te.runtime.services.AbstractService; import org.eclipse.tcf.te.runtime.services.ServiceManager; import org.eclipse.tcf.te.runtime.utils.StatusHelper; import org.eclipse.tcf.te.tcf.core.Tcf; import org.eclipse.tcf.te.tcf.core.async.CallbackInvocationDelegate; import org.eclipse.tcf.te.tcf.core.interfaces.IPathMapGeneratorService; import org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService; import org.eclipse.tcf.te.tcf.launch.core.activator.CoreBundleActivator; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerNode; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerNodeProvider; /** * Path map service implementation. */ @SuppressWarnings("restriction") public class PathMapService extends AbstractService implements IPathMapService { private final static String PATH_MAP_PROP_SHARED = "Shared"; //$NON-NLS-1$ // Lock to handle multi thread access private final Lock lock = new ReentrantLock(); // Contains a list of the shared Path Map rules for each context private final Map<String, List<IPathMap.PathMapRule>> sharedPathMapRules = new HashMap<String, List<IPathMap.PathMapRule>>(); /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#generateSourcePathMappings(java.lang.Object) */ @Override public void generateSourcePathMappings(Object context) { Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ Assert.isNotNull(context); // Get the launch configuration for that peer model ILaunchConfiguration config = (ILaunchConfiguration) Platform.getAdapterManager().getAdapter(context, ILaunchConfiguration.class); if (config == null) { config = (ILaunchConfiguration) Platform.getAdapterManager().loadAdapter(context, "org.eclipse.debug.core.ILaunchConfiguration"); //$NON-NLS-1$ } IPathMapGeneratorService generator = ServiceManager.getInstance().getService(context, IPathMapGeneratorService.class); if (config != null) { if (generator != null) { PathMapRule[] generatedRules = generator.getSourcePathMap(context); if (generatedRules != null) { MapEntrySourceContainer[] mappings = new MapEntrySourceContainer[generatedRules.length]; int i = 0; for (PathMapRule pathMapRule : generatedRules) { // CDT 9.0 changes constructor of MapEntrySourceCounter MapEntrySourceContainer mapping = null; Class<MapEntrySourceContainer> clazz = MapEntrySourceContainer.class; try { Constructor<MapEntrySourceContainer> c = clazz.getConstructor(IPath.class, IPath.class); c.setAccessible(true); mapping = c.newInstance(new Path(pathMapRule.getSource()), new Path(pathMapRule.getDestination())); } catch (NoSuchMethodException e) { try { Constructor<MapEntrySourceContainer> c = clazz.getConstructor(String.class, IPath.class); c.setAccessible(true); mapping = c.newInstance(pathMapRule.getSource(), new Path(pathMapRule.getDestination())); } catch (Exception e2) { /* ignored on purpose */ } } catch (Exception e) { /* ignored on purpose */ } if (mapping != null) { mappings[i++] = mapping; } } try { config = addSourceMappingToLaunchConfig(config, mappings); } catch (Exception e) { } } } } } private ILaunchConfiguration addSourceMappingToLaunchConfig(ILaunchConfiguration config, MapEntrySourceContainer[] mappings) throws CoreException { String memento = null; String type = null; ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy(); memento = wc.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, (String) null); type = wc.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, (String) null); if (type == null) { type = wc.getType().getSourceLocatorId(); } ISourceLocator locator = DebugPlugin.getDefault().getLaunchManager().newSourceLocator(type); if (locator instanceof AbstractSourceLookupDirector) { AbstractSourceLookupDirector director = (AbstractSourceLookupDirector) locator; if (memento == null) { director.initializeDefaults(wc); } else { director.initializeFromMemento(memento, wc); } ArrayList<ISourceContainer> containerList = new ArrayList<ISourceContainer>(Arrays.asList(director.getSourceContainers())); MappingSourceContainer generatedMappings = null; for (ISourceContainer container : containerList) { if (container instanceof MappingSourceContainer) { if (container.getName().equals(SOURCE_PATH_MAPPING_CONTAINER_NAME)) { generatedMappings = (MappingSourceContainer) container; break; } } } if (generatedMappings != null) { containerList.remove(generatedMappings); } generatedMappings = new MappingSourceContainer(SOURCE_PATH_MAPPING_CONTAINER_NAME); generatedMappings.init(director); containerList.add(generatedMappings); for (MapEntrySourceContainer mapping : mappings) { generatedMappings.addMapEntry(mapping); } director.setSourceContainers(containerList.toArray(new ISourceContainer[containerList.size()])); wc.setAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, director.getMemento()); wc.setAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_ID, director.getId()); return wc.doSave(); } return config; } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#getPathMap(java.lang.Object) */ @Override public PathMapRule[] getPathMap(Object context) { Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ Assert.isNotNull(context); PathMapRule[] rules = null; try { // Acquire the lock before accessing the path mappings lock.lock(); generateSourcePathMappings(context); List<PathMapRule> rulesList = new ArrayList<PathMapRule>(); // Get the launch configuration for that peer model ILaunchConfiguration config = (ILaunchConfiguration) Platform.getAdapterManager().getAdapter(context, ILaunchConfiguration.class); if (config == null) { config = (ILaunchConfiguration) Platform.getAdapterManager().loadAdapter(context, "org.eclipse.debug.core.ILaunchConfiguration"); //$NON-NLS-1$ } if (config != null) { try { String path_map_cfg = config.getAttribute(org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.ATTR_PATH_MAP, ""); //$NON-NLS-1$ rulesList.addAll(org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.parsePathMapAttribute(path_map_cfg)); path_map_cfg = config.getAttribute(ILaunchConfiguration.ATTR_SOURCE_LOCATOR_MEMENTO, ""); //$NON-NLS-1$ rulesList.addAll(org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.parseSourceLocatorMemento(path_map_cfg)); } catch (CoreException e) { /* ignored on purpose */ } } IPathMapGeneratorService generator = ServiceManager.getInstance().getService(context, IPathMapGeneratorService.class); if (generator != null) { PathMapRule[] generatedRules = generator.getPathMap(context); if (generatedRules != null && generatedRules.length > 0) { rulesList.addAll(Arrays.asList(generatedRules)); } } if (!rulesList.isEmpty()) { int cnt = 0; String id = getClientID(); for (PathMapRule r : rulesList) { if (r.getProperties().get(IPathMap.PROP_ID) == null) { r.getProperties().put(IPathMap.PROP_ID, id + "/" + cnt++); //$NON-NLS-1$ } } rules = rulesList.toArray(new PathMapRule[rulesList.size()]); } } finally { // Release the lock lock.unlock(); } return rules; } /* * (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#addSharedPathMapRules(java.lang.Object, org.eclipse.tcf.services.IPathMap.PathMapRule[]) */ @Override public void addSharedPathMapRules(Object context, PathMapRule[] rules) { Assert.isNotNull(context); Assert.isNotNull(rules); if (context instanceof IPeer) { List<IPathMap.PathMapRule> rulesToAdd = new ArrayList<IPathMap.PathMapRule>(); for (PathMapRule rule:rules) { Map<String, Object> props = new LinkedHashMap<String, Object>(); props.put(IPathMap.PROP_SOURCE, rule.getSource()); props.put(IPathMap.PROP_DESTINATION, rule.getDestination()); props.put(PATH_MAP_PROP_SHARED, rule.getProperties().get(PATH_MAP_PROP_SHARED)); rulesToAdd.add(new org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.PathMapRule(props)); } // Store new shared path map rules List<PathMapRule> currentSharedPMRules = sharedPathMapRules.get(((IPeer)context).getID()); if (currentSharedPMRules == null) { currentSharedPMRules = new ArrayList<IPathMap.PathMapRule>(); } currentSharedPMRules.addAll(rulesToAdd); sharedPathMapRules.put(((IPeer)context).getID(), currentSharedPMRules); addPathMap(context, rules); } } /* * (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#addPathMap(java.lang.Object, org.eclipse.tcf.services.IPathMap.PathMapRule[]) */ @Override public void addPathMap(Object context, IPathMap.PathMapRule[] rules) { Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ Assert.isNotNull(context); Assert.isNotNull(rules); List<PathMapRule> rulesWithoutMatching = new ArrayList<PathMapRule>(); try { // Acquire the lock before accessing the path mappings lock.lock(); List<PathMapRule> rulesList = new ArrayList<PathMapRule>(); // Get the launch configuration for that peer model ILaunchConfigurationWorkingCopy config = (ILaunchConfigurationWorkingCopy) Platform.getAdapterManager().getAdapter(context, ILaunchConfigurationWorkingCopy.class); if (config == null) { config = (ILaunchConfigurationWorkingCopy) Platform.getAdapterManager().loadAdapter(context, "org.eclipse.debug.core.ILaunchConfigurationWorkingCopy"); //$NON-NLS-1$ } if (config != null) { populatePathMapRulesList(config, rulesList); // Find an existing path map rule for the given source and destination for (PathMapRule r:rules) { PathMapRule matchingRule = null; for (PathMapRule candidate : rulesList) { if (r.getSource().equals(candidate.getSource()) && r.getDestination().equals(candidate.getDestination())) { matchingRule = candidate; break; } } if (matchingRule == null) { rulesWithoutMatching.add(r); } } // Add new path map rules if (rulesWithoutMatching.size() > 0) { for (PathMapRule rule:rulesWithoutMatching) { Map<String, Object> props = new LinkedHashMap<String, Object>(); props.put(IPathMap.PROP_SOURCE, rule.getSource()); props.put(IPathMap.PROP_DESTINATION, rule.getDestination()); props.put(PATH_MAP_PROP_SHARED, rule.getProperties().get(PATH_MAP_PROP_SHARED)); rulesList.add(new org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.PathMapRule(props)); } // Update the launch configuration updateLaunchConfiguration(config, rulesList); // Apply the path map applyPathMap(context, false, false, new Callback() { @Override protected void internalDone(Object caller, IStatus status) { if (status != null && !status.isOK() && Platform.inDebugMode()) { Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); } } }); } } } finally { // Release the lock lock.unlock(); } } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#addPathMap(java.lang.Object, java.lang.String, java.lang.String) */ @Override public PathMapRule addPathMap(Object context, String source, String destination) { Map<String, Object> props = new LinkedHashMap<String, Object>(); props.put(IPathMap.PROP_SOURCE, source); props.put(IPathMap.PROP_DESTINATION, destination); org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.PathMapRule rule = new org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.PathMapRule(props); addPathMap(context, new PathMapRule[] {rule}); return rule; } /* * (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#removePathMap(java.lang.Object, org.eclipse.tcf.services.IPathMap.PathMapRule[]) */ @Override public void removePathMap(Object context, IPathMap.PathMapRule[] rules) { Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ Assert.isNotNull(context); Assert.isNotNull(rules); try { // Acquire the lock before accessing the path mappings lock.lock(); List<PathMapRule> rulesList = new ArrayList<PathMapRule>(); // Get the launch configuration for that peer model ILaunchConfigurationWorkingCopy config = (ILaunchConfigurationWorkingCopy) Platform.getAdapterManager().getAdapter(context, ILaunchConfigurationWorkingCopy.class); if (config == null) { config = (ILaunchConfigurationWorkingCopy) Platform.getAdapterManager().loadAdapter(context, "org.eclipse.debug.core.ILaunchConfigurationWorkingCopy"); //$NON-NLS-1$ } if (config != null) { populatePathMapRulesList(config, rulesList); // If the original rule has an ID set, create a copy of the rule // but without the ID property List<PathMapRule> rulesToRemove = new ArrayList<PathMapRule>(); for (PathMapRule rule:rules) { if (rule.getID() != null) { Map<String, Object> props = new HashMap<String, Object>(rule.getProperties()); props.remove(IPathMap.PROP_ID); rule = new org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.PathMapRule(props); } rulesToRemove.add(rule); } // Remove the given rule from the list of present if (rulesList.removeAll(rulesToRemove)) { // Update the launch configuration updateLaunchConfiguration(config, rulesList); // Apply the path map applyPathMap(context, true, true, new Callback() { @Override protected void internalDone(Object caller, IStatus status) { if (status != null && !status.isOK() && Platform.inDebugMode()) { Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); } } }); } } } finally { // Release the lock lock.unlock(); } } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#removePathMap(java.lang.Object, org.eclipse.tcf.services.IPathMap.PathMapRule) */ @Override public void removePathMap(final Object context, final PathMapRule rule) { removePathMap(context, new PathMapRule[]{rule}); } /* * (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#cleanSharedPathMapRules() */ @Override public void cleanSharedPathMapRules(Object context) { Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ Assert.isNotNull(context); if (context instanceof IPeer) { List<PathMapRule> pathMapRulesToRemove = sharedPathMapRules.get(((IPeer)context).getID()); if (pathMapRulesToRemove != null) { removePathMap(context, pathMapRulesToRemove.toArray(new IPathMap.PathMapRule[0])); } sharedPathMapRules.remove(((IPeer)context).getID()); } } /** * Populate the given path map rules list from the given launch configuration. * * @param config The launch configuration. Must not be <code>null</code>. * @param rulesList The path map rules list. Must not be <code>null</code>. */ private void populatePathMapRulesList(ILaunchConfiguration config, List<PathMapRule> rulesList) { Assert.isNotNull(config); Assert.isNotNull(rulesList); try { String path_map_cfg = config.getAttribute(org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.ATTR_PATH_MAP, ""); //$NON-NLS-1$ String path_map_cfgV1 = config.getAttribute(org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.ATTR_PATH_MAP + "V1", ""); //$NON-NLS-1$ //$NON-NLS-2$ rulesList.addAll(org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.parsePathMapAttribute(path_map_cfgV1)); int i = -1; for (PathMapRule candidate : org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.parsePathMapAttribute(path_map_cfg)) { if (rulesList.contains(candidate)) { i = rulesList.indexOf(candidate); } else { rulesList.add(++i, candidate); } } } catch (CoreException e) { /* ignored on purpose */ } } /** * Write back the given path map rules list to the given launch configuration. * * @param config The launch configuration. Must not be <code>null</code>. * @param rulesList The path map rules list. Must not be <code>null</code>. */ private void updateLaunchConfiguration(ILaunchConfigurationWorkingCopy config, List<PathMapRule> rulesList) { Assert.isNotNull(config); Assert.isNotNull(rulesList); // Update the launch configuration for (PathMapRule candidate : rulesList) { candidate.getProperties().remove(IPathMap.PROP_ID); } StringBuilder bf = new StringBuilder(); StringBuilder bf1 = new StringBuilder(); for (PathMapRule candidate : rulesList) { if (!(candidate instanceof org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.PathMapRule)) continue; boolean enabled = true; if (candidate.getProperties().containsKey("Enabled")) { //$NON-NLS-1$ enabled = Boolean.parseBoolean(candidate.getProperties().get("Enabled").toString()); //$NON-NLS-1$ } if (enabled) { candidate.getProperties().remove("Enabled"); //$NON-NLS-1$ bf.append(candidate.toString()); } bf1.append(candidate.toString()); } if (bf.length() == 0) { config.removeAttribute(TCFLaunchDelegate.ATTR_PATH_MAP); } else { config.setAttribute(TCFLaunchDelegate.ATTR_PATH_MAP, bf.toString()); } if (bf1.length() == 0) { config.removeAttribute(org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.ATTR_PATH_MAP + "V1"); //$NON-NLS-1$ } else { config.setAttribute(org.eclipse.tcf.internal.debug.launch.TCFLaunchDelegate.ATTR_PATH_MAP + "V1", bf1.toString()); //$NON-NLS-1$ } try { config.doSave(); } catch (CoreException e) { if (Platform.inDebugMode()) { Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(e.getStatus()); } } } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#applyPathMap(java.lang.Object, boolean, boolean, org.eclipse.tcf.te.runtime.interfaces.callback.ICallback) */ @Override public void applyPathMap(final Object context, final boolean force, final boolean forceEmpty, final ICallback callback) { Assert.isTrue(!Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ Assert.isNotNull(context); Assert.isNotNull(callback); IPeer peer = context instanceof IPeer ? (IPeer)context : null; if (peer == null && context instanceof IPeerNode) peer = ((IPeerNode)context).getPeer(); if (peer == null && context instanceof IPeerNodeProvider && ((IPeerNodeProvider)context).getPeerNode() != null) peer = ((IPeerNodeProvider)context).getPeerNode().getPeer(); // If called as part of the "open channel" step group, IChannelManager.getChannel(peer) // will return null. For this case, the channel to use is passed as context directly. final IChannel channel = context instanceof IChannel ? (IChannel)context : null; // The peer in that case is the remote peer of the channel if (peer == null && channel != null) { final AtomicReference<IPeer> remotePeer = new AtomicReference<IPeer>(); Protocol.invokeAndWait(new Runnable() { @Override public void run() { remotePeer.set(channel.getRemotePeer()); } }); peer = remotePeer.get(); } // Make sure that the callback is invoked in the TCF dispatch thread final AsyncCallbackCollector collector = new AsyncCallbackCollector(callback, new CallbackInvocationDelegate()); final ICallback innerCallback = new AsyncCallbackCollector.SimpleCollectorCallback(collector); collector.initDone(); if (peer != null) { final IChannel c = channel != null ? channel : Tcf.getChannelManager().getChannel(peer); if (c != null && IChannel.STATE_OPEN == c.getState()) { // Channel is open -> Have to update the path maps // Get the configured path mappings. This must be called from // outside the runnable as getPathMap(...) must be called from // outside of the TCF dispatch thread. final PathMapRule[] configuredMap = getPathMap(context instanceof IChannel ? peer : context); if (configuredMap != null && configuredMap.length > 0) { // Create the runnable which set the path map Runnable runnable = new Runnable() { @Override public void run() { final IPathMap svc = c.getRemoteService(IPathMap.class); if (svc != null) { // Get the old path maps first. Keep path map rules not coming from us svc.get(new IPathMap.DoneGet() { @Override public void doneGet(IToken token, Exception error, PathMapRule[] map) { // Merge the path maps List<PathMapRule> rules = mergePathMaps(getClientID(), map, configuredMap); // If the merged path map differs from the agent side path map, apply the map if (force || isDifferent(rules, map)) { // Apply the path map set(rules, svc, forceEmpty, new IPathMap.DoneSet() { @Override public void doneSet(IToken token, Exception error) { innerCallback.done(PathMapService.this, StatusHelper.getStatus(error)); } }); } else { innerCallback.done(PathMapService.this, Status.OK_STATUS); } } }); } else { innerCallback.done(PathMapService.this, Status.OK_STATUS); } } }; Protocol.invokeLater(runnable); } else { innerCallback.done(PathMapService.this, Status.OK_STATUS); } } else { innerCallback.done(PathMapService.this, Status.OK_STATUS); } } else { innerCallback.done(PathMapService.this, Status.OK_STATUS); } } /** * Merge the given agent and client side path maps. * * @param clientID The current client ID. Must not be <code>null</code>. * @param agentSidePathMap The agent side path map or <code>null</code>. * @param clientSidePathMap The client side path map. Must not be <code>null</code>. * * @return The merged path map. */ public static List<PathMapRule> mergePathMaps(String clientID, PathMapRule[] agentSidePathMap, PathMapRule[] clientSidePathMap) { Assert.isNotNull(clientID); Assert.isNotNull(clientSidePathMap); // Merge the maps to a new list List<PathMapRule> rules = new ArrayList<PathMapRule>(); // The map of agent side path map rules List<PathMapRule> agentSideRules = new ArrayList<PathMapRule>(); if (agentSidePathMap != null && agentSidePathMap.length > 0) { for (PathMapRule rule : agentSidePathMap) { if (rule.getID() == null || (!rule.getID().startsWith(clientID) && !"agent".equalsIgnoreCase(rule.getID()))) { //$NON-NLS-1$ rules.add(rule); } else if ("agent".equalsIgnoreCase(rule.getID())) { //$NON-NLS-1$ agentSideRules.add(rule); } } } for (PathMapRule rule : clientSidePathMap) { if (IPathMapService.PATHMAP_PROTOCOL_HOST_TO_TARGET.equals(rule.getProtocol())) continue; // If the configured rule matches an agent side path map rule, ignore the configured rule // and add the agent side rule boolean addRule = true; Map<String, Object> m1 = new HashMap<String, Object>(rule.getProperties()); m1.remove(IPathMap.PROP_ID); for (PathMapRule agentSideRule : agentSideRules) { Map<String, Object> m2 = new HashMap<String, Object>(agentSideRule.getProperties()); m2.remove(IPathMap.PROP_ID); if (m1.equals(m2)) { rules.add(agentSideRule); addRule = false; break; } } // Add the configured rule if (addRule) rules.add(rule); } return rules; } /** * Returns if or if not the given merged path map is different from the given agent * side path map. * * @param mergedPathMap The merged path map. Must not be <code>null</code>. * @param agentSidePathMap The agent side path map or <code>null</code>. * * @return <code>True</code> if the merged path map is different, <code>false</code> if not. */ public static boolean isDifferent(List<PathMapRule> mergedPathMap, PathMapRule[] agentSidePathMap) { Assert.isNotNull(mergedPathMap); boolean changed = agentSidePathMap != null ? agentSidePathMap.length != mergedPathMap.size() : !mergedPathMap.isEmpty(); if (!changed && !mergedPathMap.isEmpty()) { // Make a copy of new map and remove all rules listed // by the old map. If not empty at the end, the new map // is different from the old map. List<PathMapRule> copy = new ArrayList<PathMapRule>(mergedPathMap); for (PathMapRule rule : agentSidePathMap) { Iterator<PathMapRule> iter = copy.iterator(); while (iter.hasNext()) { PathMapRule r = iter.next(); if (r.equals(rule)) { iter.remove(); break; } } } changed = !copy.isEmpty(); } return changed; } /** * Set the given path map. * <p> * <b>Note:</b> This method must be called from within the TCF dispatch thread. * * @param map The path map. Must not be <code>null</code>. * @param svc The path map service. Must not be <code>null</code>. * @param forceEmpty If <code>true</code>, the path map will be set even if empty. * @param done The callback to invoke. Must not be <code>null</code>. */ public static void set(List<PathMapRule> map, IPathMap svc, boolean forceEmpty, IPathMap.DoneSet done) { Assert.isTrue(Protocol.isDispatchThread(), "Illegal Thread Access"); //$NON-NLS-1$ Assert.isNotNull(map); Assert.isNotNull(svc); Assert.isNotNull(done); // Get rid of the agent side rules before applying the rules for real Iterator<PathMapRule> iter = map.iterator(); while (iter.hasNext()) { PathMapRule rule = iter.next(); if ("agent".equalsIgnoreCase(rule.getID()) || Boolean.parseBoolean((String) rule.getProperties().get(PATH_MAP_PROP_SHARED))) { //$NON-NLS-1$ iter.remove(); } } // Apply the path map rules if not empty or forced if (!map.isEmpty() || forceEmpty) { svc.set(map.toArray(new PathMapRule[map.size()]), done); } else { done.doneSet(null, null); } } /* (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#getClientID() */ @Override public String getClientID() { return org.eclipse.tcf.internal.debug.Activator.getClientID(); } /* * (non-Javadoc) * @see org.eclipse.tcf.te.tcf.core.interfaces.IPathMapService#getSharedPathMapRules(java.lang.Object) */ @Override public PathMapRule[] getSharedPathMapRules(Object context) { Assert.isNotNull(context); PathMapRule[] rules = null; try { // Acquire the lock before accessing the shared path mappings lock.lock(); if (sharedPathMapRules != null ) { List<PathMapRule> sharedRules = sharedPathMapRules.get(((IPeer)context).getID()); if (sharedRules != null && sharedRules.size() > 0) { rules = sharedRules.toArray(new IPathMap.PathMapRule[sharedRules.size()]); } } } finally { // Release the lock lock.unlock(); } return rules; } }