public bool Contains(GroupCompositionId id) { lock (m_Lock) { return((id != null) && m_Groups.ContainsKey(id)); } }
/// <summary> /// Adds a new <see cref="GroupDefinition"/> to the graph and returns the ID for that group. /// </summary> /// <param name="id">The ID of the group that is being added.</param> /// <param name="group">The group that should be added to the graph.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="id"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="group"/> is <see langword="null" />. /// </exception> public void Add(GroupCompositionId id, GroupDefinition group) { { Lokad.Enforce.Argument(() => id); Lokad.Enforce.Argument(() => group); } if (!m_Definitions.ContainsKey(group.Id)) { m_Definitions.Add(group.Id, group); } m_Groups.Add(id, group.Id); m_GroupConnections.AddVertex(id); foreach (var part in group.Parts) { var partId = new PartCompositionId(id, part.Id); m_Parts.Add(partId, new PartCompositionInfo(part)); m_PartConnections.AddVertex(partId); } var parts = PartsForGroup(id); ConnectParts(group.InternalConnections, parts, parts); }
/// <summary> /// Adds a new <see cref="GroupDefinition"/> to the graph and returns the ID for that group. /// </summary> /// <param name="group">The group that should be added to the graph.</param> /// <returns> /// A task which returns the ID for the group. /// </returns> public Task <GroupCompositionId> Add(GroupDefinition group) { { Debug.Assert(group != null, "The definition that should be added should not be a null reference."); } var id = new GroupCompositionId(); var remoteTask = m_Commands.Add(id, group); m_Diagnostics.Log( LevelToLog.Trace, HostConstants.LogPrefix, string.Format( CultureInfo.InvariantCulture, Resources.ProxyCompositionLayer_LogMessage_AddingGroup_WithId, id)); return(remoteTask.ContinueWith( t => { lock (m_Lock) { m_Groups.Add(id, group); m_GroupConnections.AddVertex(id); } return id; })); }
public void Add() { var lockKey = new DatasetLockKey(); var datasetLock = new Mock<ITrackDatasetLocks>(); { datasetLock.Setup(d => d.LockForWriting()) .Returns(lockKey) .Verifiable(); datasetLock.Setup(d => d.RemoveWriteLock(It.IsAny<DatasetLockKey>())) .Callback<DatasetLockKey>(key => Assert.AreSame(lockKey, key)) .Verifiable(); } var originalId = new GroupCompositionId(); var originalDefinition = new GroupDefinition("a"); var storage = new Mock<IStoreGroupsAndConnections>(); { storage.Setup(s => s.Add(It.IsAny<GroupCompositionId>(), It.IsAny<GroupDefinition>())) .Callback<GroupCompositionId, GroupDefinition>( (id, def) => { Assert.AreSame(originalId, id); Assert.AreSame(originalDefinition, def); }); } var commands = new CompositionCommands(datasetLock.Object, storage.Object); var task = commands.Add(originalId, originalDefinition); task.Wait(); datasetLock.Verify(d => d.LockForWriting(), Times.Once()); datasetLock.Verify(d => d.RemoveWriteLock(It.IsAny<DatasetLockKey>()), Times.Once()); }
public void Remove() { var lockKey = new DatasetLockKey(); var datasetLock = new Mock <ITrackDatasetLocks>(); { datasetLock.Setup(d => d.LockForWriting()) .Returns(lockKey) .Verifiable(); datasetLock.Setup(d => d.RemoveWriteLock(It.IsAny <DatasetLockKey>())) .Callback <DatasetLockKey>(key => Assert.AreSame(lockKey, key)) .Verifiable(); } var originalId = new GroupCompositionId(); var storage = new Mock <IStoreGroupsAndConnections>(); { storage.Setup(s => s.Remove(It.IsAny <GroupCompositionId>())) .Callback <GroupCompositionId>( id => { Assert.AreSame(originalId, id); }); } var commands = new CompositionCommands(datasetLock.Object, storage.Object); var task = commands.Remove(originalId); task.Wait(); datasetLock.Verify(d => d.LockForWriting(), Times.Once()); datasetLock.Verify(d => d.RemoveWriteLock(It.IsAny <DatasetLockKey>()), Times.Once()); }
public bool CanConnectTo( GroupCompositionId importingGroup, GroupImportDefinition importDefinition, IDictionary <string, object> selectionCriteria, GroupCompositionId exportingGroup) { if (!m_Graph.Contains(importingGroup)) { return(false); } if (!m_Graph.Contains(exportingGroup)) { return(false); } if (m_Graph.IsConnected(importingGroup, importDefinition)) { return(false); } var group = m_Graph.Group(exportingGroup); return(m_GroupImportEngine.Accepts(importDefinition, group.GroupExport) && m_GroupImportEngine.ExportPassesSelectionCriteria(group.GroupExport, selectionCriteria)); }
/// <summary> /// Removes the group that is related to the specified ID. /// </summary> /// <param name="group">The ID of the group that should be removed.</param> /// <returns>A task that indicates when the removal has taken place.</returns> public Task Remove(GroupCompositionId group) { { Debug.Assert(group != null, "The ID that should be removed should not be a null reference."); Debug.Assert(m_Groups.ContainsKey(group), "The ID should be known."); } m_Diagnostics.Log( LevelToLog.Trace, HostConstants.LogPrefix, string.Format( CultureInfo.InvariantCulture, Resources.ProxyCompositionLayer_LogMessage_RemovingGroup_WithId, group)); var remoteTask = m_Commands.Remove(group); return(remoteTask.ContinueWith( t => { lock (m_Lock) { if (m_GroupConnections.ContainsVertex(group)) { m_GroupConnections.RemoveVertex(group); } if (m_Groups.ContainsKey(group)) { m_Groups.Remove(group); } } })); }
/// <summary> /// Disconnects the group from all imports and exports. /// </summary> /// <param name="group">The composition ID of the group.</param> public void Disconnect(GroupCompositionId group) { if ((group == null) || !m_GroupConnections.ContainsVertex(group)) { return; } var matchingExports = m_GroupConnections .InEdges(group) .Select(edge => new Tuple <GroupCompositionId, GroupImportDefinition>(edge.Source, edge.Import)); foreach (var pair in matchingExports) { DisconnectParts(group, pair.Item2, pair.Item1); } var matchingImports = m_GroupConnections .OutEdges(group) .Select(edge => new Tuple <GroupCompositionId, GroupImportDefinition>(edge.Target, edge.Import)); foreach (var pair in matchingImports) { DisconnectParts(pair.Item1, pair.Item2, group); } m_GroupConnections.RemoveInEdgeIf(group, edge => true); m_GroupConnections.RemoveOutEdgeIf(group, edge => true); }
public void Create() { var group = new GroupCompositionId(); var part = new PartRegistrationId("a", 1); var id = new PartCompositionId(group, part); Assert.AreEqual(group, id.Group); Assert.AreEqual(part, id.Part); }
/// <summary> /// Initializes a new instance of the <see cref="PartCompositionId"/> class. /// </summary> /// <param name="group">The ID of the composed group that owns the current part.</param> /// <param name="part">The ID of the part registration that determines what the current part is.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="group"/> is <see langword="null" />. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="part"/> is <see langword="null" />. /// </exception> public PartCompositionId(GroupCompositionId group, PartRegistrationId part) { { Lokad.Enforce.Argument(() => group); Lokad.Enforce.Argument(() => part); } m_Group = group; m_Part = part; }
public void ReloadFromDataset() { var importingId = new GroupCompositionId(); var exportingId = new GroupCompositionId(); var importingGroup = new GroupDefinition("Group1"); var exportingGroup = new GroupDefinition("Group2"); var importDefinition = GroupImportDefinition.CreateDefinition( "a", new GroupRegistrationId("b"), null, Enumerable.Empty <ImportRegistrationId>()); var state = new GroupCompositionState( new List <Tuple <GroupCompositionId, GroupDefinition> > { new Tuple <GroupCompositionId, GroupDefinition>(importingId, importingGroup), new Tuple <GroupCompositionId, GroupDefinition>(exportingId, exportingGroup), }, new List <Tuple <GroupCompositionId, GroupImportDefinition, GroupCompositionId> > { new Tuple <GroupCompositionId, GroupImportDefinition, GroupCompositionId>(importingId, importDefinition, exportingId) }); using (var source = new CancellationTokenSource()) { var commands = new Mock <ICompositionCommands>(); { commands.Setup(c => c.CurrentState()) .Returns( Task <GroupCompositionState> .Factory.StartNew( () => state, source.Token, TaskCreationOptions.None, new CurrentThreadTaskScheduler())); } var connector = new Mock <IConnectGroups>(); var systemDiagnostics = new SystemDiagnostics((p, s) => { }, null); var layer = new ProxyCompositionLayer(commands.Object, connector.Object, systemDiagnostics); var task = layer.ReloadFromDataset(); task.Wait(); Assert.IsTrue(layer.Contains(importingId)); Assert.AreEqual(importingGroup, layer.Group(importingId)); Assert.IsTrue(layer.Contains(exportingId)); Assert.AreEqual(exportingGroup, layer.Group(exportingId)); Assert.IsTrue(layer.IsConnected(importingId, importDefinition)); Assert.IsTrue(layer.IsConnected(importingId, importDefinition, exportingId)); Assert.AreEqual(exportingId, layer.ConnectedTo(importingId, importDefinition)); } }
public void Remove() { int index = -1; var instanceIds = new List <PartInstanceId> { new PartInstanceId(), new PartInstanceId(), new PartInstanceId(), new PartInstanceId(), new PartInstanceId(), }; var storage = new Mock <IStoreInstances>(); { storage.Setup( s => s.Construct( It.IsAny <GroupPartDefinition>(), It.IsAny <IEnumerable <Tuple <ImportRegistrationId, PartInstanceId, ExportRegistrationId> > >())) .Returns( () => { index++; return(instanceIds[index]); }); storage.Setup(s => s.Release(It.IsAny <PartInstanceId>())) .Returns <PartInstanceId>( i => { return(new List <InstanceUpdate> { new InstanceUpdate { Instance = i, Change = InstanceChange.Removed, } }); }) .Verifiable(); } var layer = CompositionLayer.CreateInstanceWithoutTimeline(storage.Object); var groupId = new GroupCompositionId(); var definition = CreateExportingDefinition(); layer.Add(groupId, definition); Assert.AreEqual(1, layer.Groups().Count()); Assert.AreSame(groupId, layer.Groups().First()); Assert.AreSame(definition, layer.Group(groupId)); layer.Remove(groupId); Assert.AreEqual(0, layer.Groups().Count()); storage.Verify(s => s.Release(It.IsAny <PartInstanceId>()), Times.Exactly(5)); }
public void Remove() { GroupCompositionId storedId = null; GroupDefinition storedDefinition = null; using (var source = new CancellationTokenSource()) { var commands = new Mock <ICompositionCommands>(); { commands.Setup(c => c.Add(It.IsAny <GroupCompositionId>(), It.IsAny <GroupDefinition>())) .Callback <GroupCompositionId, GroupDefinition>( (id, def) => { storedId = id; storedDefinition = def; }) .Returns( Task.Factory.StartNew( () => { }, source.Token, TaskCreationOptions.None, new CurrentThreadTaskScheduler())); commands.Setup(c => c.Remove(It.IsAny <GroupCompositionId>())) .Callback <GroupCompositionId>(id => storedId = id) .Returns( Task.Factory.StartNew( () => { }, source.Token, TaskCreationOptions.None, new CurrentThreadTaskScheduler())); } var connector = new Mock <IConnectGroups>(); var systemDiagnostics = new SystemDiagnostics((p, s) => { }, null); var layer = new ProxyCompositionLayer(commands.Object, connector.Object, systemDiagnostics); var definition = new GroupDefinition("Group1"); var task = layer.Add(definition); task.Wait(); Assert.AreSame(storedId, task.Result); Assert.AreSame(definition, storedDefinition); Assert.IsTrue(layer.Contains(task.Result)); var otherTask = layer.Remove(task.Result); otherTask.Wait(); Assert.AreSame(task.Result, storedId); Assert.IsFalse(layer.Contains(task.Result)); } }
private Task OnGroupConnect( GroupCompositionId importingGroup, GroupImportDefinition importDefinition, GroupCompositionId exportingGroup, GroupExportDefinition exportDefinition) { if (!m_GroupImportEngine.Accepts(importDefinition, exportDefinition)) { throw new CannotMapExportToImportException(); } return(m_Graph.Connect(importingGroup, importDefinition, exportingGroup)); }
/// <summary> /// Returns the <see cref="GroupDefinition"/> that was registered with the given ID. /// </summary> /// <param name="id">The composition ID of the group.</param> /// <returns>The definition for the group with the given ID.</returns> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="id"/> is <see langword="null" />. /// </exception> /// <exception cref="UnknownGroupCompositionIdException"> /// Thrown if <paramref name="id"/> does not belong to a known group. /// </exception> public GroupDefinition Group(GroupCompositionId id) { { Lokad.Enforce.Argument(() => id); Lokad.Enforce.With <UnknownGroupCompositionIdException>( m_Groups.ContainsKey(id), Resources.Exceptions_Messages_UnknownGroupCompositionId); } var definitionId = m_Groups[id]; Debug.Assert(m_Definitions.ContainsKey(definitionId), "There should be a definition with the given definition ID."); return(m_Definitions[definitionId]); }
/// <summary> /// Selects the current group and adds it to the composition graph. /// </summary> /// <returns>The task that will return the ID for the group in the graph.</returns> public Task <GroupCompositionId> Select() { var task = m_OnSelect(m_Group); var continuationTask = task.ContinueWith( t => { lock (m_Lock) { m_Id = t.Result; } return(t.Result); }); return(continuationTask); }
/// <summary> /// Returns the <see cref="GroupDefinition"/> which is related to the given ID. /// </summary> /// <param name="id">The ID of the requested group.</param> /// <returns>The requested group.</returns> public GroupDefinition Group(GroupCompositionId id) { { Debug.Assert(id != null, "The ID that should be removed should not be a null reference."); } lock (m_Lock) { if (!m_Groups.ContainsKey(id)) { throw new UnknownPartGroupException(); } return(m_Groups[id]); } }
public bool IsConnected(GroupCompositionId importingGroup, GroupImportDefinition importDefinition) { if ((importingGroup == null) || (importDefinition == null)) { return(false); } if (!Contains(importingGroup)) { return(false); } lock (m_Lock) { return(m_GroupConnections.InEdges(importingGroup).Any(e => e.Import.Equals(importDefinition))); } }
/// <summary> /// Initializes a new instance of the <see cref="GroupConnection"/> class. /// </summary> /// <param name="importingGroup">The ID of the group that provides the import.</param> /// <param name="exportingGroup">The ID of the group that provides the export.</param> /// <param name="import">The import definition that should be connected to.</param> /// <param name="partConnections">The collection that contains the mapping of the part imports to the part exports.</param> public GroupConnection( GroupCompositionId importingGroup, GroupCompositionId exportingGroup, GroupImportDefinition import, IEnumerable<PartImportToPartExportMap> partConnections) { { Lokad.Enforce.Argument(() => importingGroup); Lokad.Enforce.Argument(() => exportingGroup); Lokad.Enforce.Argument(() => import); Lokad.Enforce.Argument(() => partConnections); } m_ImportingGroup = importingGroup; m_ExportingGroup = exportingGroup; m_Import = import; m_PartConnections = partConnections; }
/// <summary> /// Removes the <see cref="GroupDefinition"/> related to the given <paramref name="id"/> from the graph. /// </summary> /// <param name="id">The ID of the group that should be removed.</param> /// <returns>A task that will finish when the action has completed.</returns> public Task Remove(GroupCompositionId id) { var globalTask = Task.Factory.StartNew( () => { var key = m_DatasetLock.LockForWriting(); try { m_CompositionLayer.Remove(id); } finally { m_DatasetLock.RemoveWriteLock(key); } }); return(globalTask); }
/// <summary> /// Disconnects the given groups from each other. /// </summary> /// <param name="importingGroup">The ID of the importing group.</param> /// <param name="exportingGroup">The ID of the exporting group.</param> /// <returns>A task that will finish when the disconnection action has completed.</returns> public Task Disconnect(GroupCompositionId importingGroup, GroupCompositionId exportingGroup) { var globalTask = Task.Factory.StartNew( () => { var key = m_DatasetLock.LockForWriting(); try { m_CompositionLayer.Disconnect(importingGroup, exportingGroup); } finally { m_DatasetLock.RemoveWriteLock(key); } }); return(globalTask); }
/// <summary> /// Adds a new <see cref="GroupDefinition"/> to the graph and returns the ID for that group. /// </summary> /// <param name="id">The ID of the group.</param> /// <param name="group">The group that should be added to the graph.</param> /// <returns>A task that will finish when the action has completed.</returns> public Task Add(GroupCompositionId id, GroupDefinition group) { var globalTask = Task.Factory.StartNew( () => { var key = m_DatasetLock.LockForWriting(); try { m_CompositionLayer.Add(id, group); } finally { m_DatasetLock.RemoveWriteLock(key); } }); return globalTask; }
/// <summary> /// Returns a collection of all imports owned by the specified group that have not been provided with an export. /// </summary> /// <param name="importOwner">The composition ID of the group that owns the imports.</param> /// <returns>A collection containing all imports that have not been provided with an export.</returns> public IEnumerable <GroupImportDefinition> UnsatisfiedImports(GroupCompositionId importOwner) { { Lokad.Enforce.Argument(() => importOwner); Lokad.Enforce.With <UnknownGroupCompositionIdException>( m_Groups.ContainsKey(importOwner), Resources.Exceptions_Messages_UnknownGroupCompositionId); } var definitionId = m_Groups[importOwner]; Debug.Assert(m_Definitions.ContainsKey(definitionId), "There should be a definition for the current group."); var definition = m_Definitions[definitionId]; var inEdges = m_GroupConnections.InEdges(importOwner); return(definition.GroupImports.Where(i => !inEdges.Any(e => e.Import.Equals(i)))); }
public void CanConnectToWithNonExistingExportGroup() { var importingId = new GroupCompositionId(); var exportingId = new GroupCompositionId(); var importEngine = new Mock<IConnectGroups>(); var graph = new Mock<ICompositionLayer>(); { graph.Setup(g => g.Contains(It.IsAny<GroupCompositionId>())) .Returns<GroupCompositionId>(id => !id.Equals(exportingId)); } var selector = new GroupSelector(importEngine.Object, graph.Object); Assert.IsFalse( selector.CanConnectTo( importingId, GroupImportDefinition.CreateDefinition("myContract", new GroupRegistrationId("a"), null, null), exportingId)); }
public void CanConnectToWithNonExistingExportGroup() { var importingId = new GroupCompositionId(); var exportingId = new GroupCompositionId(); var importEngine = new Mock <IConnectGroups>(); var graph = new Mock <ICompositionLayer>(); { graph.Setup(g => g.Contains(It.IsAny <GroupCompositionId>())) .Returns <GroupCompositionId>(id => !id.Equals(exportingId)); } var selector = new GroupSelector(importEngine.Object, graph.Object); Assert.IsFalse( selector.CanConnectTo( importingId, GroupImportDefinition.CreateDefinition("myContract", new GroupRegistrationId("a"), null, null), exportingId)); }
/// <summary> /// Removes the group that is related to the specified ID. /// </summary> /// <param name="group">The ID of the group that should be removed.</param> public void Remove(GroupCompositionId group) { if (group == null) { return; } if (!m_Groups.ContainsKey(group)) { return; } var definitionId = m_Groups[group]; var definition = m_Definitions[definitionId]; foreach (var part in definition.Parts) { var partId = new PartCompositionId(group, part.Id); Debug.Assert(m_Parts.ContainsKey(partId), "The part collection should have the given part ID."); Debug.Assert(m_PartConnections.ContainsVertex(partId), "The part connections graph should have the given part ID."); var info = m_Parts[partId]; if (info.Instance != null) { ReleaseInstance(partId); } m_PartConnections.RemoveVertex(partId); m_Parts.Remove(partId); } Debug.Assert(m_GroupConnections.ContainsVertex(group), "The connections graph should have the given group ID."); m_GroupConnections.RemoveVertex(group); m_Groups.Remove(group); if (!m_Groups.Any(p => p.Value.Equals(definitionId))) { m_Definitions.Remove(definitionId); } }
private void DisconnectParts(GroupCompositionId importingGroup, GroupImportDefinition importDefinition, GroupCompositionId exportingGroup) { var definitionId = m_Groups[importingGroup]; var importingGroupDefinition = m_Definitions[definitionId]; var importingParts = importDefinition .ImportsToMatch .Select(id => importingGroupDefinition.Parts.PartByImport(id)) .Join( m_Parts, partDef => new PartCompositionId(importingGroup, partDef.Id), pair => pair.Key, (partDef, pair) => pair.Key); definitionId = m_Groups[exportingGroup]; var exportingGroupDefinition = m_Definitions[definitionId]; var exportingParts = exportingGroupDefinition.GroupExport .ProvidedExports .Select(id => exportingGroupDefinition.Parts.PartByExport(id)) .Join( m_Parts, partDef => new PartCompositionId(exportingGroup, partDef.Id), pair => pair.Key, (partDef, pair) => pair.Key); foreach (var importingPart in importingParts) { var matchedExports = m_PartConnections .InEdges(importingPart) .Where(edge => exportingParts.Contains(edge.Source)) .Select(edge => new Tuple <ImportRegistrationId, PartCompositionId>(edge.ImportRegistration, edge.Source)); foreach (var pair in matchedExports) { DisconnectInstanceFromExport(importingPart, pair.Item1, pair.Item2); } m_PartConnections.RemoveInEdgeIf(importingPart, edge => exportingParts.Contains(edge.Source)); } }
/// <summary> /// Returns the group information indicating which export the given import is connected to. /// </summary> /// <param name="importingGroup">The ID of the group owning the import.</param> /// <param name="importDefinition">The import.</param> /// <returns>The ID of the group the given import is connected to, if there is a connection; otherwise, <see langword="null" />.</returns> public GroupCompositionId ConnectedTo( GroupCompositionId importingGroup, GroupImportDefinition importDefinition) { if ((importingGroup == null) || (importDefinition == null)) { return(null); } if (!Contains(importingGroup)) { return(null); } lock (m_Lock) { return(m_GroupConnections.InEdges(importingGroup) .Where(e => e.Import.Equals(importDefinition)) .Select(e => e.Source) .FirstOrDefault()); } }
/// <summary> /// Disconnects the exporting group from the importing group. /// </summary> /// <param name="importingGroup">The composition ID of the importing group.</param> /// <param name="exportingGroup">The composition ID of the exporting group.</param> public void Disconnect(GroupCompositionId importingGroup, GroupCompositionId exportingGroup) { if ((importingGroup == null) || (exportingGroup == null)) { return; } if (!m_GroupConnections.ContainsVertex(importingGroup) || (!m_GroupConnections.ContainsVertex(exportingGroup))) { return; } var importDefinition = m_GroupConnections .InEdges(importingGroup) .Where(edge => edge.Source.Equals(exportingGroup)) .Select(edge => edge.Import) .FirstOrDefault(); m_GroupConnections.RemoveInEdgeIf(importingGroup, edge => edge.Source.Equals(exportingGroup)); DisconnectParts(importingGroup, importDefinition, exportingGroup); }
/// <summary> /// Connects the given export to the given import. /// </summary> /// <param name="importingGroup">The ID of the group that owns the import.</param> /// <param name="importDefinition">The import.</param> /// <param name="exportingGroup">The ID of the group that owns the export.</param> /// <returns>A task which indicates when the connection has taken place.</returns> public Task Connect( GroupCompositionId importingGroup, GroupImportDefinition importDefinition, GroupCompositionId exportingGroup) { { Debug.Assert(importingGroup != null, "The ID of the importing group should not be a null reference."); Debug.Assert(importDefinition != null, "The import definition should not be a null reference."); Debug.Assert(exportingGroup != null, "The ID of the exporting group should not be a null reference."); } if (!Contains(importingGroup) || !Contains(exportingGroup)) { throw new UnknownPartGroupException(); } m_Diagnostics.Log( LevelToLog.Trace, HostConstants.LogPrefix, string.Format( CultureInfo.InvariantCulture, Resources.ProxyCompositionLayer_LogMessage_ConnectingGroups_WithImportAndExport, importingGroup, exportingGroup)); var parts = m_Connector.GenerateConnectionFor(m_Groups[importingGroup], importDefinition, m_Groups[exportingGroup]); var state = new GroupConnection(importingGroup, exportingGroup, importDefinition, parts); var remoteTask = m_Commands.Connect(state); return(remoteTask.ContinueWith( t => { lock (m_Lock) { m_GroupConnections.AddEdge(new CompositionLayerGroupEdge(importingGroup, importDefinition, exportingGroup)); } })); }
/// <summary> /// Disconnects all connection to and from the given group. /// </summary> /// <param name="group">The ID of the group.</param> /// <returns>A task which indicates when the disconnection has taken place.</returns> public Task Disconnect(GroupCompositionId group) { { Debug.Assert(group != null, "The ID of the group should not be a null reference."); } m_Diagnostics.Log( LevelToLog.Trace, HostConstants.LogPrefix, string.Format( CultureInfo.InvariantCulture, Resources.ProxyCompositionLayer_LogMessage_DisconnectingAllFromGroup_WithId, group)); var remoteTask = m_Commands.Disconnect(group); return(remoteTask.ContinueWith( t => { m_GroupConnections.RemoveInEdgeIf(group, edge => true); m_GroupConnections.RemoveOutEdgeIf(group, edge => true); })); }
/// <summary> /// Disconnects the two groups. /// </summary> /// <remarks> /// This method assumes that two groups will only be connected via one import - export relation. This /// method will remove all connections from the exporting group to the importing group. /// </remarks> /// <param name="importingGroup">The ID of the group that owns the import.</param> /// <param name="exportingGroup">The ID of the group that owns the export.</param> /// <returns>A task which indicates when the disconnection has taken place.</returns> public Task Disconnect(GroupCompositionId importingGroup, GroupCompositionId exportingGroup) { { Debug.Assert(importingGroup != null, "The ID of the importing group should not be a null reference."); Debug.Assert(exportingGroup != null, "The ID of the exporting group should not be a null reference."); } m_Diagnostics.Log( LevelToLog.Trace, HostConstants.LogPrefix, string.Format( CultureInfo.InvariantCulture, Resources.ProxyCompositionLayer_LogMessage_DisconnectingGroups_WithImportAndExport, importingGroup, exportingGroup)); var remoteTask = m_Commands.Disconnect(importingGroup, exportingGroup); return(remoteTask.ContinueWith( t => { m_GroupConnections.RemoveInEdgeIf(importingGroup, edge => edge.Source.Equals(exportingGroup)); })); }
/// <summary> /// Disconnects the two groups. /// </summary> /// <remarks> /// This method assumes that two groups will only be connected via one import - export relation. This /// method will remove all connections from the exporting group to the importing group. /// </remarks> /// <param name="importingGroup">The ID of the group that owns the import.</param> /// <param name="exportingGroup">The ID of the group that owns the export.</param> /// <returns>A task which indicates when the disconnection has taken place.</returns> public Task Disconnect(GroupCompositionId importingGroup, GroupCompositionId exportingGroup) { { Debug.Assert(importingGroup != null, "The ID of the importing group should not be a null reference."); Debug.Assert(exportingGroup != null, "The ID of the exporting group should not be a null reference."); } m_Diagnostics.Log( LevelToLog.Trace, HostConstants.LogPrefix, string.Format( CultureInfo.InvariantCulture, Resources.ProxyCompositionLayer_LogMessage_DisconnectingGroups_WithImportAndExport, importingGroup, exportingGroup)); var remoteTask = m_Commands.Disconnect(importingGroup, exportingGroup); return remoteTask.ContinueWith( t => { m_GroupConnections.RemoveInEdgeIf(importingGroup, edge => edge.Source.Equals(exportingGroup)); }); }
/// <summary> /// Returns the <see cref="GroupDefinition"/> which is related to the given ID. /// </summary> /// <param name="id">The ID of the requested group.</param> /// <returns>The requested group.</returns> public GroupDefinition Group(GroupCompositionId id) { { Debug.Assert(id != null, "The ID that should be removed should not be a null reference."); } lock (m_Lock) { if (!m_Groups.ContainsKey(id)) { throw new UnknownPartGroupException(); } return m_Groups[id]; } }
/// <summary> /// Disconnects all connection to and from the given group. /// </summary> /// <param name="group">The ID of the group.</param> /// <returns>A task which indicates when the disconnection has taken place.</returns> public Task Disconnect(GroupCompositionId group) { { Debug.Assert(group != null, "The ID of the group should not be a null reference."); } m_Diagnostics.Log( LevelToLog.Trace, HostConstants.LogPrefix, string.Format( CultureInfo.InvariantCulture, Resources.ProxyCompositionLayer_LogMessage_DisconnectingAllFromGroup_WithId, group)); var remoteTask = m_Commands.Disconnect(group); return remoteTask.ContinueWith( t => { m_GroupConnections.RemoveInEdgeIf(group, edge => true); m_GroupConnections.RemoveOutEdgeIf(group, edge => true); }); }
public bool IsConnected( GroupCompositionId importingGroup, GroupImportDefinition importDefinition, GroupCompositionId exportingGroup) { if ((importingGroup == null) || (importDefinition == null) || (exportingGroup == null)) { return false; } if (!Contains(importingGroup)) { return false; } lock (m_Lock) { return m_GroupConnections.InEdges(importingGroup).Any(e => e.Import.Equals(importDefinition) && e.Source.Equals(exportingGroup)); } }
/// <summary> /// Returns a collection of all imports owned by the specified group that have not been provided with an export. /// </summary> /// <param name="importOwner">The composition ID of the group that owns the imports.</param> /// <returns>A collection containing all imports that have not been provided with an export.</returns> public IEnumerable<GroupImportDefinition> UnsatisfiedImports(GroupCompositionId importOwner) { { Lokad.Enforce.Argument(() => importOwner); Lokad.Enforce.With<UnknownGroupCompositionIdException>( m_Groups.ContainsKey(importOwner), Resources.Exceptions_Messages_UnknownGroupCompositionId); } var definitionId = m_Groups[importOwner]; Debug.Assert(m_Definitions.ContainsKey(definitionId), "There should be a definition for the current group."); var definition = m_Definitions[definitionId]; var inEdges = m_GroupConnections.InEdges(importOwner); return definition.GroupImports.Where(i => !inEdges.Any(e => e.Import.Equals(i))); }
/// <summary> /// Disconnects the given group from all imports and exports. /// </summary> /// <param name="group">The group that should be disconnected.</param> /// <returns>A task that will finish when the disconnection action has completed.</returns> public Task Disconnect(GroupCompositionId group) { var globalTask = Task.Factory.StartNew( () => { var key = m_DatasetLock.LockForWriting(); try { m_CompositionLayer.Disconnect(group); } finally { m_DatasetLock.RemoveWriteLock(key); } }); return globalTask; }
/// <summary> /// Selects the current group and adds it to the composition graph. /// </summary> /// <returns>The task that will return the ID for the group in the graph.</returns> public Task<GroupCompositionId> Select() { var task = m_OnSelect(m_Group); var continuationTask = task.ContinueWith( t => { lock (m_Lock) { m_Id = t.Result; } return t.Result; }); return continuationTask; }
private void DisconnectParts(GroupCompositionId importingGroup, GroupImportDefinition importDefinition, GroupCompositionId exportingGroup) { var definitionId = m_Groups[importingGroup]; var importingGroupDefinition = m_Definitions[definitionId]; var importingParts = importDefinition .ImportsToMatch .Select(id => importingGroupDefinition.Parts.PartByImport(id)) .Join( m_Parts, partDef => new PartCompositionId(importingGroup, partDef.Id), pair => pair.Key, (partDef, pair) => pair.Key); definitionId = m_Groups[exportingGroup]; var exportingGroupDefinition = m_Definitions[definitionId]; var exportingParts = exportingGroupDefinition.GroupExport .ProvidedExports .Select(id => exportingGroupDefinition.Parts.PartByExport(id)) .Join( m_Parts, partDef => new PartCompositionId(exportingGroup, partDef.Id), pair => pair.Key, (partDef, pair) => pair.Key); foreach (var importingPart in importingParts) { var matchedExports = m_PartConnections .InEdges(importingPart) .Where(edge => exportingParts.Contains(edge.Source)) .Select(edge => new Tuple<ImportRegistrationId, PartCompositionId>(edge.ImportRegistration, edge.Source)); foreach (var pair in matchedExports) { DisconnectInstanceFromExport(importingPart, pair.Item1, pair.Item2); } m_PartConnections.RemoveInEdgeIf(importingPart, edge => exportingParts.Contains(edge.Source)); } }
/// <summary> /// Disconnects the current group from the import of the given group. /// </summary> /// <param name="group">The ID of the importing group.</param> /// <returns>The task that will finish once the given connection is removed.</returns> public Task DisconnectFrom(GroupCompositionId group) { return m_OnDisconnect(group, m_Id); }
/// <summary> /// Returns the <see cref="GroupDefinition"/> that was registered with the given ID. /// </summary> /// <param name="id">The composition ID of the group.</param> /// <returns>The definition for the group with the given ID.</returns> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="id"/> is <see langword="null" />. /// </exception> /// <exception cref="UnknownGroupCompositionIdException"> /// Thrown if <paramref name="id"/> does not belong to a known group. /// </exception> public GroupDefinition Group(GroupCompositionId id) { { Lokad.Enforce.Argument(() => id); Lokad.Enforce.With<UnknownGroupCompositionIdException>( m_Groups.ContainsKey(id), Resources.Exceptions_Messages_UnknownGroupCompositionId); } var definitionId = m_Groups[id]; Debug.Assert(m_Definitions.ContainsKey(definitionId), "There should be a definition with the given definition ID."); return m_Definitions[definitionId]; }
private IEnumerable <Tuple <PartCompositionId, GroupPartDefinition> > PartsForGroup(GroupCompositionId group) { return(m_Parts .Where(pair => pair.Key.Group.Equals(group)) .Select(pair => new Tuple <PartCompositionId, GroupPartDefinition>(pair.Key, m_Parts[pair.Key].Definition))); }
/// <summary> /// Connects the export of the current group to the given import of another group. /// </summary> /// <param name="group">The ID of the group containing the import.</param> /// <param name="importToMatch">The import.</param> /// <returns>The task that will finish once the give connection has been made.</returns> public Task ConnectTo(GroupCompositionId group, GroupImportDefinition importToMatch) { return m_OnConnect(group, importToMatch, m_Id, m_Group.GroupExport); }
/// <summary> /// Disconnects the group from all imports and exports. /// </summary> /// <param name="group">The composition ID of the group.</param> public void Disconnect(GroupCompositionId group) { if ((group == null) || !m_GroupConnections.ContainsVertex(group)) { return; } var matchingExports = m_GroupConnections .InEdges(group) .Select(edge => new Tuple<GroupCompositionId, GroupImportDefinition>(edge.Source, edge.Import)); foreach (var pair in matchingExports) { DisconnectParts(group, pair.Item2, pair.Item1); } var matchingImports = m_GroupConnections .OutEdges(group) .Select(edge => new Tuple<GroupCompositionId, GroupImportDefinition>(edge.Target, edge.Import)); foreach (var pair in matchingImports) { DisconnectParts(pair.Item1, pair.Item2, group); } m_GroupConnections.RemoveInEdgeIf(group, edge => true); m_GroupConnections.RemoveOutEdgeIf(group, edge => true); }
private Task OnGroupDeselect(GroupCompositionId id) { return m_Graph.Remove(id); }
public bool Contains(GroupCompositionId id) { lock (m_Lock) { return (id != null) && m_Groups.ContainsKey(id); } }
public bool CanConnectTo(GroupCompositionId importingGroup, GroupImportDefinition importDefinition, GroupCompositionId exportingGroup) { return CanConnectTo(importingGroup, importDefinition, new Dictionary<string, object>(), exportingGroup); }
public void DisconnectImportFromExport() { var lockKey = new DatasetLockKey(); var datasetLock = new Mock<ITrackDatasetLocks>(); { datasetLock.Setup(d => d.LockForWriting()) .Returns(lockKey) .Verifiable(); datasetLock.Setup(d => d.RemoveWriteLock(It.IsAny<DatasetLockKey>())) .Callback<DatasetLockKey>(key => Assert.AreSame(lockKey, key)) .Verifiable(); } var originalImportId = new GroupCompositionId(); var originalExportId = new GroupCompositionId(); var storage = new Mock<IStoreGroupsAndConnections>(); { storage.Setup(s => s.Disconnect(It.IsAny<GroupCompositionId>(), It.IsAny<GroupCompositionId>())) .Callback<GroupCompositionId, GroupCompositionId>( (importId, exportId) => { Assert.AreSame(originalImportId, importId); Assert.AreSame(originalExportId, exportId); }); } var commands = new CompositionCommands(datasetLock.Object, storage.Object); var task = commands.Remove(originalImportId); task.Wait(); datasetLock.Verify(d => d.LockForWriting(), Times.Once()); datasetLock.Verify(d => d.RemoveWriteLock(It.IsAny<DatasetLockKey>()), Times.Once()); }
/// <summary> /// Returns a collection of all imports owned by the specified group that have been provided with an export. /// </summary> /// <param name="importOwner">The composition ID of the group that owns the imports.</param> /// <returns>A collection containing all the imports with the group ID of the group providing the connected export.</returns> public IEnumerable<Tuple<GroupImportDefinition, GroupCompositionId>> SatisfiedImports(GroupCompositionId importOwner) { { Lokad.Enforce.Argument(() => importOwner); Lokad.Enforce.With<UnknownGroupCompositionIdException>( m_Groups.ContainsKey(importOwner), Resources.Exceptions_Messages_UnknownGroupCompositionId); } return m_GroupConnections.InEdges(importOwner).Select(e => new Tuple<GroupImportDefinition, GroupCompositionId>(e.Import, e.Source)); }
private Task OnGroupConnect( GroupCompositionId importingGroup, GroupImportDefinition importDefinition, GroupCompositionId exportingGroup, GroupExportDefinition exportDefinition) { if (!m_GroupImportEngine.Accepts(importDefinition, exportDefinition)) { throw new CannotMapExportToImportException(); } return m_Graph.Connect(importingGroup, importDefinition, exportingGroup); }
/// <summary> /// Removes the group that is related to the specified ID. /// </summary> /// <param name="group">The ID of the group that should be removed.</param> /// <returns>A task that indicates when the removal has taken place.</returns> public Task Remove(GroupCompositionId group) { { Debug.Assert(group != null, "The ID that should be removed should not be a null reference."); Debug.Assert(m_Groups.ContainsKey(group), "The ID should be known."); } m_Diagnostics.Log( LevelToLog.Trace, HostConstants.LogPrefix, string.Format( CultureInfo.InvariantCulture, Resources.ProxyCompositionLayer_LogMessage_RemovingGroup_WithId, group)); var remoteTask = m_Commands.Remove(group); return remoteTask.ContinueWith( t => { lock (m_Lock) { if (m_GroupConnections.ContainsVertex(group)) { m_GroupConnections.RemoveVertex(group); } if (m_Groups.ContainsKey(group)) { m_Groups.Remove(group); } } }); }
private Task OnGroupDisconnect(GroupCompositionId importingGroup, GroupCompositionId exportingGroup) { return m_Graph.Disconnect(importingGroup, exportingGroup); }
/// <summary> /// Returns a collection of all imports owned by the specified group that have been provided with an export. /// </summary> /// <param name="importOwner">The composition ID of the group that owns the imports.</param> /// <returns>A collection containing all the imports with the group ID of the group providing the connected export.</returns> public IEnumerable <Tuple <GroupImportDefinition, GroupCompositionId> > SatisfiedImports(GroupCompositionId importOwner) { { Lokad.Enforce.Argument(() => importOwner); Lokad.Enforce.With <UnknownGroupCompositionIdException>( m_Groups.ContainsKey(importOwner), Resources.Exceptions_Messages_UnknownGroupCompositionId); } return(m_GroupConnections.InEdges(importOwner).Select(e => new Tuple <GroupImportDefinition, GroupCompositionId>(e.Import, e.Source))); }
public bool CanConnectTo( GroupCompositionId importingGroup, GroupImportDefinition importDefinition, IDictionary<string, object> selectionCriteria, GroupCompositionId exportingGroup) { if (!m_Graph.Contains(importingGroup)) { return false; } if (!m_Graph.Contains(exportingGroup)) { return false; } if (m_Graph.IsConnected(importingGroup, importDefinition)) { return false; } var group = m_Graph.Group(exportingGroup); return m_GroupImportEngine.Accepts(importDefinition, group.GroupExport) && m_GroupImportEngine.ExportPassesSelectionCriteria(group.GroupExport, selectionCriteria); }
public void ReloadFromDataset() { var importingId = new GroupCompositionId(); var exportingId = new GroupCompositionId(); var importingGroup = new GroupDefinition("Group1"); var exportingGroup = new GroupDefinition("Group2"); var importDefinition = GroupImportDefinition.CreateDefinition( "a", new GroupRegistrationId("b"), null, Enumerable.Empty<ImportRegistrationId>()); var state = new GroupCompositionState( new List<Tuple<GroupCompositionId, GroupDefinition>> { new Tuple<GroupCompositionId, GroupDefinition>(importingId, importingGroup), new Tuple<GroupCompositionId, GroupDefinition>(exportingId, exportingGroup), }, new List<Tuple<GroupCompositionId, GroupImportDefinition, GroupCompositionId>> { new Tuple<GroupCompositionId, GroupImportDefinition, GroupCompositionId>(importingId, importDefinition, exportingId) }); using (var source = new CancellationTokenSource()) { var commands = new Mock<ICompositionCommands>(); { commands.Setup(c => c.CurrentState()) .Returns( Task<GroupCompositionState>.Factory.StartNew( () => state, source.Token, TaskCreationOptions.None, new CurrentThreadTaskScheduler())); } var connector = new Mock<IConnectGroups>(); var systemDiagnostics = new SystemDiagnostics((p, s) => { }, null); var layer = new ProxyCompositionLayer(commands.Object, connector.Object, systemDiagnostics); var task = layer.ReloadFromDataset(); task.Wait(); Assert.IsTrue(layer.Contains(importingId)); Assert.AreEqual(importingGroup, layer.Group(importingId)); Assert.IsTrue(layer.Contains(exportingId)); Assert.AreEqual(exportingGroup, layer.Group(exportingId)); Assert.IsTrue(layer.IsConnected(importingId, importDefinition)); Assert.IsTrue(layer.IsConnected(importingId, importDefinition, exportingId)); Assert.AreEqual(exportingId, layer.ConnectedTo(importingId, importDefinition)); } }
private IEnumerable<Tuple<PartCompositionId, GroupPartDefinition>> PartsForGroup(GroupCompositionId group) { return m_Parts .Where(pair => pair.Key.Group.Equals(group)) .Select(pair => new Tuple<PartCompositionId, GroupPartDefinition>(pair.Key, m_Parts[pair.Key].Definition)); }