Repository: reef
Updated Branches:
  refs/heads/master f5fd01fc7 -> 3818bf454


[REEF-1168] Support TaskStart and TaskStop

JIRA:
  [REEF-1168](https://issues.apache.org/jira/browse/REEF-1168)

This closes #841


Project: http://git-wip-us.apache.org/repos/asf/reef/repo
Commit: http://git-wip-us.apache.org/repos/asf/reef/commit/3818bf45
Tree: http://git-wip-us.apache.org/repos/asf/reef/tree/3818bf45
Diff: http://git-wip-us.apache.org/repos/asf/reef/diff/3818bf45

Branch: refs/heads/master
Commit: 3818bf454ab1f9eb8b35bbcb2457d7726bc5f540
Parents: f5fd01f
Author: Andrew Chung <[email protected]>
Authored: Fri Feb 12 10:49:39 2016 -0800
Committer: Julia Wang <[email protected]>
Committed: Wed Feb 17 12:54:44 2016 -0800

----------------------------------------------------------------------
 .../Runtime/Evaluator/Task/TaskLifeCycle.cs     |  73 ++++++---
 .../Runtime/Evaluator/Task/TaskStartImpl.cs     |   6 +-
 .../Runtime/Evaluator/Task/TaskStatus.cs        |   6 +-
 .../Runtime/Evaluator/Task/TaskStopImpl.cs      |   6 +-
 .../Tasks/Events/ITaskStart.cs                  |   4 +
 .../Tasks/Events/ITaskStop.cs                   |   4 +
 .../TaskRuntimeTests.cs                         | 159 ++++++++++++++++++-
 .../Collections/ReadOnlySet.cs                  | 137 ++++++++++++++++
 .../Org.Apache.Reef.Utilities.csproj            |   1 +
 9 files changed, 363 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskLifeCycle.cs
----------------------------------------------------------------------
diff --git 
a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskLifeCycle.cs 
b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskLifeCycle.cs
index bdff836..369fbf0 100644
--- a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskLifeCycle.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskLifeCycle.cs
@@ -17,49 +17,78 @@
 
 using System;
 using System.Collections.Generic;
+using Org.Apache.REEF.Common.Tasks;
 using Org.Apache.REEF.Common.Tasks.Events;
+using Org.Apache.REEF.Tang.Annotations;
+using Org.Apache.REEF.Utilities;
+using Org.Apache.REEF.Utilities.Collections;
 
 namespace Org.Apache.REEF.Common.Runtime.Evaluator.Task
 {
     internal sealed class TaskLifeCycle
     {
-        private readonly HashSet<IObserver<ITaskStop>> _taskStopHandlers;
-        private readonly HashSet<IObserver<ITaskStart>> _taskStartHandlers;
-        private readonly ITaskStart _taskStart;
-        private readonly ITaskStop _taskStop;
+        private readonly IReadOnlyCollection<IObserver<ITaskStop>> 
_taskStopHandlers;
+        private readonly IReadOnlyCollection<IObserver<ITaskStart>> 
_taskStartHandlers;
+        private readonly Optional<ITaskStart> _taskStart;
+        private readonly Optional<ITaskStop> _taskStop;
 
-        // INJECT
-        public TaskLifeCycle(
-            HashSet<IObserver<ITaskStop>> taskStopHandlers,
-            HashSet<IObserver<ITaskStart>> taskStartHandlers,
-            TaskStartImpl taskStart,
-            TaskStopImpl taskStop)
+        /// <summary>
+        /// TODO[JIRA REEF-1167]: Remove constructor.
+        /// </summary>
+        [Obsolete("Deprecated in 0.14. Will be removed.")]
+        [Inject]
+        private TaskLifeCycle(
+            [Parameter(typeof(TaskConfigurationOptions.StartHandlers))] 
ISet<IObserver<ITaskStart>> taskStartHandlers,
+            [Parameter(typeof(TaskConfigurationOptions.StopHandlers))] 
ISet<IObserver<ITaskStop>> taskStopHandlers)
+            : this(taskStartHandlers, taskStopHandlers, 
Optional<ITaskStart>.Empty(), Optional<ITaskStop>.Empty())
         {
-            _taskStartHandlers = taskStartHandlers;
-            _taskStopHandlers = taskStopHandlers;
-            _taskStart = taskStart;
-            _taskStop = taskStop;
         }
 
-        public TaskLifeCycle()
+        [Inject]
+        private TaskLifeCycle(
+            [Parameter(typeof(TaskConfigurationOptions.StartHandlers))] 
ISet<IObserver<ITaskStart>> taskStartHandlers,
+            [Parameter(typeof(TaskConfigurationOptions.StopHandlers))] 
ISet<IObserver<ITaskStop>> taskStopHandlers,
+            ITaskStart taskStart,
+            ITaskStop taskStop)
+            : this(taskStartHandlers, taskStopHandlers, 
Optional<ITaskStart>.Of(taskStart), Optional<ITaskStop>.Of(taskStop))
         {
-            _taskStartHandlers = new HashSet<IObserver<ITaskStart>>();
-            _taskStopHandlers = new HashSet<IObserver<ITaskStop>>();
         }
-        
+
+        private TaskLifeCycle(
+            IEnumerable<IObserver<ITaskStart>> taskStartHandlers,
+            IEnumerable<IObserver<ITaskStop>> taskStopHandlers,
+            Optional<ITaskStart> taskStart,
+            Optional<ITaskStop> taskStop)
+        {
+            _taskStartHandlers = new 
ReadOnlySet<IObserver<ITaskStart>>(taskStartHandlers);
+            _taskStopHandlers = new 
ReadOnlySet<IObserver<ITaskStop>>(taskStopHandlers);
+            _taskStart = taskStart;
+            _taskStop = taskStop;
+        }
+
         public void Start() 
         {
-            foreach (IObserver<ITaskStart> startHandler in _taskStartHandlers) 
+            if (!_taskStart.IsPresent())
+            {
+                return;
+            }
+
+            foreach (var startHandler in _taskStartHandlers)
             {
-                startHandler.OnNext(_taskStart);
+                startHandler.OnNext(_taskStart.Value);
             }
         }
 
         public void Stop() 
         {
-            foreach (IObserver<ITaskStop> stopHandler in _taskStopHandlers)
+            if (!_taskStop.IsPresent())
+            {
+                return;
+            }
+
+            foreach (var stopHandler in _taskStopHandlers)
             {
-                stopHandler.OnNext(_taskStop);
+                stopHandler.OnNext(_taskStop.Value);
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStartImpl.cs
----------------------------------------------------------------------
diff --git 
a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStartImpl.cs 
b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStartImpl.cs
index 0571719..f35ab82 100644
--- a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStartImpl.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStartImpl.cs
@@ -15,14 +15,16 @@
 // specific language governing permissions and limitations
 // under the License.
 
+using Org.Apache.REEF.Common.Tasks;
 using Org.Apache.REEF.Common.Tasks.Events;
+using Org.Apache.REEF.Tang.Annotations;
 
 namespace Org.Apache.REEF.Common.Runtime.Evaluator.Task
 {
     internal sealed class TaskStartImpl : ITaskStart
     {        
-        // INJECT
-        public TaskStartImpl(string id)
+        [Inject]
+        private 
TaskStartImpl([Parameter(typeof(TaskConfigurationOptions.Identifier))] string 
id)
         {
             Id = id;
         }

http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStatus.cs
----------------------------------------------------------------------
diff --git 
a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStatus.cs 
b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStatus.cs
index 31ce771..ab10c63 100644
--- a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStatus.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStatus.cs
@@ -22,6 +22,7 @@ using Org.Apache.REEF.Common.Context;
 using Org.Apache.REEF.Common.Protobuf.ReefProtocol;
 using Org.Apache.REEF.Common.Tasks;
 using Org.Apache.REEF.Tang.Annotations;
+using Org.Apache.REEF.Tang.Implementations.Tang;
 using Org.Apache.REEF.Utilities;
 using Org.Apache.REEF.Utilities.Logging;
 
@@ -47,10 +48,11 @@ namespace Org.Apache.REEF.Common.Runtime.Evaluator.Task
             [Parameter(typeof(ContextConfigurationOptions.ContextIdentifier))] 
string contextId,
             [Parameter(typeof(TaskConfigurationOptions.Identifier))] string 
taskId,
             [Parameter(typeof(TaskConfigurationOptions.TaskMessageSources))] 
ISet<ITaskMessageSource> taskMessageSources,
+            TaskLifeCycle taskLifeCycle,
             IHeartBeatManager heartBeatManager)
         {
             _heartBeatManager = heartBeatManager;
-            _taskLifeCycle = new TaskLifeCycle();
+            _taskLifeCycle = taskLifeCycle;
             _evaluatorMessageSources = 
Optional<ISet<ITaskMessageSource>>.OfNullable(taskMessageSources);
             State = TaskState.Init;
             _taskId = taskId;
@@ -64,7 +66,7 @@ namespace Org.Apache.REEF.Common.Runtime.Evaluator.Task
         public TaskStatus(IHeartBeatManager heartBeatManager, string 
contextId, string taskId, Optional<ISet<ITaskMessageSource>> 
evaluatorMessageSources)
         {
             _heartBeatManager = heartBeatManager;
-            _taskLifeCycle = new TaskLifeCycle();
+            _taskLifeCycle = 
TangFactory.GetTang().NewInjector().GetInstance<TaskLifeCycle>();
             _evaluatorMessageSources = evaluatorMessageSources;
             State = TaskState.Init;
             _taskId = taskId;

http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStopImpl.cs
----------------------------------------------------------------------
diff --git 
a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStopImpl.cs 
b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStopImpl.cs
index b2830e5..07739b9 100644
--- a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStopImpl.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/Task/TaskStopImpl.cs
@@ -15,14 +15,16 @@
 // specific language governing permissions and limitations
 // under the License.
 
+using Org.Apache.REEF.Common.Tasks;
 using Org.Apache.REEF.Common.Tasks.Events;
+using Org.Apache.REEF.Tang.Annotations;
 
 namespace Org.Apache.REEF.Common.Runtime.Evaluator.Task
 {
     internal sealed class TaskStopImpl : ITaskStop
     {
-        // INJECT
-        public TaskStopImpl(string id)
+        [Inject]
+        private 
TaskStopImpl([Parameter(typeof(TaskConfigurationOptions.Identifier))] string id)
         {
             Id = id;
         }

http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStart.cs
----------------------------------------------------------------------
diff --git a/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStart.cs 
b/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStart.cs
index 7cf5b75..24b495b 100644
--- a/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStart.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStart.cs
@@ -15,8 +15,12 @@
 // specific language governing permissions and limitations
 // under the License.
 
+using Org.Apache.REEF.Common.Runtime.Evaluator.Task;
+using Org.Apache.REEF.Tang.Annotations;
+
 namespace Org.Apache.REEF.Common.Tasks.Events
 {
+    [DefaultImplementation(typeof(TaskStartImpl))]
     public interface ITaskStart
     {
         string Id { get; set; }

http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStop.cs
----------------------------------------------------------------------
diff --git a/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStop.cs 
b/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStop.cs
index 24fa016..4d4850f 100644
--- a/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStop.cs
+++ b/lang/cs/Org.Apache.REEF.Common/Tasks/Events/ITaskStop.cs
@@ -15,8 +15,12 @@
 // specific language governing permissions and limitations
 // under the License.
 
+using Org.Apache.REEF.Common.Runtime.Evaluator.Task;
+using Org.Apache.REEF.Tang.Annotations;
+
 namespace Org.Apache.REEF.Common.Tasks.Events
 {
+    [DefaultImplementation(typeof(TaskStopImpl))]
     public interface ITaskStop
     {
         string Id { get; }

http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Evaluator.Tests/TaskRuntimeTests.cs
----------------------------------------------------------------------
diff --git a/lang/cs/Org.Apache.REEF.Evaluator.Tests/TaskRuntimeTests.cs 
b/lang/cs/Org.Apache.REEF.Evaluator.Tests/TaskRuntimeTests.cs
index 44d691f..0435357 100644
--- a/lang/cs/Org.Apache.REEF.Evaluator.Tests/TaskRuntimeTests.cs
+++ b/lang/cs/Org.Apache.REEF.Evaluator.Tests/TaskRuntimeTests.cs
@@ -16,6 +16,8 @@
 // under the License.
 
 using System;
+using System.Collections.Generic;
+using System.Linq;
 using System.Threading;
 using NSubstitute;
 using Org.Apache.REEF.Common.Context;
@@ -23,16 +25,24 @@ using Org.Apache.REEF.Common.Protobuf.ReefProtocol;
 using Org.Apache.REEF.Common.Runtime.Evaluator;
 using Org.Apache.REEF.Common.Runtime.Evaluator.Task;
 using Org.Apache.REEF.Common.Tasks;
+using Org.Apache.REEF.Common.Tasks.Events;
 using Org.Apache.REEF.Tang.Annotations;
 using Org.Apache.REEF.Tang.Implementations.Tang;
 using Org.Apache.REEF.Tang.Interface;
 using Org.Apache.REEF.Tang.Util;
+using Org.Apache.REEF.Utilities;
 using Xunit;
 
 namespace Org.Apache.REEF.Evaluator.Tests
 {
+    /// <summary>
+    /// Tests for TaskRuntime and Task events.
+    /// </summary>
     public sealed class TaskRuntimeTests
     {
+        /// <summary>
+        /// Tests that Task ID and Context ID are properly passed to 
TaskRuntime.
+        /// </summary>
         [Fact]
         public void TestTaskRuntimeFields()
         {
@@ -44,6 +54,9 @@ namespace Org.Apache.REEF.Evaluator.Tests
             Assert.Equal(taskRuntime.ContextId, contextId);
         }
 
+        /// <summary>
+        /// Tests that TaskRuntime has proper state at initialization.
+        /// </summary>
         [Fact]
         public void TestTaskRuntimeInitialization()
         {
@@ -53,6 +66,10 @@ namespace Org.Apache.REEF.Evaluator.Tests
             Assert.False(taskRuntime.HasEnded());
         }
 
+        /// <summary>
+        /// Tests a simple Task on TaskRuntime and tests that the Task is
+        /// properly disposed.
+        /// </summary>
         [Fact]
         public void TestTaskRuntimeRunsAndDisposesTask()
         {
@@ -66,6 +83,9 @@ namespace Org.Apache.REEF.Evaluator.Tests
             Assert.True(taskRuntime.HasEnded());
         }
 
+        /// <summary>
+        /// Tests the correctness of TaskRuntime state on Task failure.
+        /// </summary>
         [Fact]
         public void TestTaskRuntimeFailure()
         {
@@ -78,6 +98,10 @@ namespace Org.Apache.REEF.Evaluator.Tests
             Assert.True(taskRuntime.HasEnded());
         }
 
+        /// <summary>
+        /// Tests the correctness of TaskRuntime state throughout the lifecycle
+        /// of a Task. Also tests that the Task runs properly.
+        /// </summary>
         [Fact]
         public void TestTaskLifeCycle()
         {
@@ -107,6 +131,89 @@ namespace Org.Apache.REEF.Evaluator.Tests
             Assert.Equal(taskRuntime.GetTaskState(), TaskState.Done);
         }
 
+        /// <summary>
+        /// Tests whether task start and stop handlers are properly 
instantiated and invoked
+        /// in the happy path.
+        /// </summary>
+        [Fact]
+        public void TestTaskEvents()
+        {
+            var contextId = Guid.NewGuid().ToString();
+            var taskId = Guid.NewGuid().ToString();
+
+            var injector = GetInjector(typeof(CountDownAction), contextId, 
taskId);
+            var taskRuntime = injector.GetInstance<TaskRuntime>();
+            var startHandlers = 
injector.GetNamedInstance<TaskConfigurationOptions.StartHandlers, 
ISet<IObserver<ITaskStart>>>();
+
+            Assert.Equal(startHandlers.Count, 1);
+
+            var testTaskEventStartHandler = startHandlers.Single() as 
TestTaskEventHandler;
+            Assert.NotNull(testTaskEventStartHandler);
+            if (testTaskEventStartHandler == null)
+            {
+                throw new Exception("Event handler is not expected to be 
null.");
+            }
+
+            taskRuntime.RunTask();
+
+            Assert.True(testTaskEventStartHandler.StartInvoked.IsPresent());
+            Assert.Equal(testTaskEventStartHandler.StartInvoked.Value, taskId);
+            Assert.False(testTaskEventStartHandler.StopInvoked.IsPresent());
+
+            var countDownAction = injector.GetInstance<CountDownAction>();
+            countDownAction.CountdownEvent.Signal();
+
+            var task = injector.GetInstance<TestTask>();
+            task.FinishCountdownEvent.Wait();
+            task.DisposeCountdownEvent.Wait();
+
+            var stopHandlers = 
injector.GetNamedInstance<TaskConfigurationOptions.StopHandlers, 
ISet<IObserver<ITaskStop>>>();
+
+            Assert.Equal(stopHandlers.Count, 1);
+
+            var testTaskEventStopHandler = stopHandlers.Single() as 
TestTaskEventHandler;
+            Assert.NotNull(testTaskEventStopHandler);
+            if (testTaskEventStopHandler == null)
+            {
+                throw new Exception("Event handler is not expected to be 
null.");
+            }
+
+            Assert.True(ReferenceEquals(testTaskEventStartHandler, 
testTaskEventStopHandler));
+            Assert.True(testTaskEventStopHandler.StopInvoked.IsPresent());
+            Assert.Equal(testTaskEventStopHandler.StopInvoked.Value, taskId);
+        }
+
+        /// <summary>
+        /// Tests whether task start and stop handlers are properly 
instantiated and invoked
+        /// on the failure of a task.
+        /// </summary>
+        [Fact]
+        public void TestTaskEventsOnFailure()
+        {
+            var contextId = Guid.NewGuid().ToString();
+            var taskId = Guid.NewGuid().ToString();
+
+            var injector = GetInjector(typeof(ExceptionAction), contextId, 
taskId);
+            var taskRuntime = injector.GetInstance<TaskRuntime>();
+
+            taskRuntime.RunTask();
+
+            var task = injector.GetInstance<TestTask>();
+            task.FinishCountdownEvent.Wait();
+            task.DisposeCountdownEvent.Wait();
+
+            var stopHandlers = 
injector.GetNamedInstance<TaskConfigurationOptions.StopHandlers, 
ISet<IObserver<ITaskStop>>>();
+            var testTaskEventStopHandler = stopHandlers.Single() as 
TestTaskEventHandler;
+            Assert.NotNull(testTaskEventStopHandler);
+            if (testTaskEventStopHandler == null)
+            {
+                throw new Exception("Event handler is not expected to be 
null.");
+            }
+
+            Assert.True(testTaskEventStopHandler.StopInvoked.IsPresent());
+            Assert.Equal(testTaskEventStopHandler.StopInvoked.Value, taskId);
+        }
+
         private static IInjector GetInjector(string contextId = "contextId", 
string taskId = "taskId")
         {
             return GetInjector(typeof(DefaultAction), contextId, taskId);
@@ -117,19 +224,61 @@ namespace Org.Apache.REEF.Evaluator.Tests
             var confBuilder = TangFactory.GetTang().NewConfigurationBuilder();
             var heartbeatManager = Substitute.For<IHeartBeatManager>();
 
-            var evaluatorConfig = confBuilder
-                
.BindNamedParameter(typeof(ContextConfigurationOptions.ContextIdentifier), 
contextId)
-                
.BindNamedParameter(typeof(TaskConfigurationOptions.Identifier), taskId)
-                .BindImplementation(typeof(ITask), typeof(TestTask))
+            var contextConfig = ContextConfiguration.ConfigurationModule
+                .Set(ContextConfiguration.Identifier, contextId)
+                .Build();
+
+            var taskConfig = TaskConfiguration.ConfigurationModule
+                .Set(TaskConfiguration.Identifier, taskId)
+                .Set(TaskConfiguration.OnTaskStart, 
GenericType<TestTaskEventHandler>.Class)
+                .Set(TaskConfiguration.OnTaskStop, 
GenericType<TestTaskEventHandler>.Class)
+                .Set(TaskConfiguration.Task, GenericType<TestTask>.Class)
+                .Build();
+            
+            var actionConfig = confBuilder
                 .BindImplementation(typeof(IAction), actionType)
                 .Build();
 
-            var injector = TangFactory.GetTang().NewInjector(evaluatorConfig);
+            var injector = TangFactory.GetTang().NewInjector(contextConfig, 
taskConfig, actionConfig);
             
injector.BindVolatileInstance(GenericType<IHeartBeatManager>.Class, 
heartbeatManager);
 
             return injector;
         }
 
+        private sealed class TestTaskEventHandler : IObserver<ITaskStart>, 
IObserver<ITaskStop>
+        {
+            [Inject]
+            private TestTaskEventHandler()
+            {
+                StartInvoked = Optional<string>.Empty();
+                StopInvoked = Optional<string>.Empty();
+            }
+
+            public Optional<string> StartInvoked { get; private set; }
+
+            public Optional<string> StopInvoked { get; private set; }
+
+            public void OnNext(ITaskStart value)
+            {
+                StartInvoked = Optional<string>.Of(value.Id);
+            }
+
+            public void OnNext(ITaskStop value)
+            {
+                StopInvoked = Optional<string>.Of(value.Id);
+            }
+
+            public void OnError(Exception error)
+            {
+                throw new NotImplementedException();
+            }
+
+            public void OnCompleted()
+            {
+                throw new NotImplementedException();
+            }
+        }
+
         private sealed class TestTask : ITask
         {
             private readonly IAction _action;

http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Utilities/Collections/ReadOnlySet.cs
----------------------------------------------------------------------
diff --git a/lang/cs/Org.Apache.REEF.Utilities/Collections/ReadOnlySet.cs 
b/lang/cs/Org.Apache.REEF.Utilities/Collections/ReadOnlySet.cs
new file mode 100644
index 0000000..d7f4414
--- /dev/null
+++ b/lang/cs/Org.Apache.REEF.Utilities/Collections/ReadOnlySet.cs
@@ -0,0 +1,137 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace Org.Apache.REEF.Utilities.Collections
+{
+    /// <summary>
+    /// An implementation of a set that is read only.
+    /// Backed by a HashSet.
+    /// </summary>
+    public sealed class ReadOnlySet<T> : IReadOnlyCollection<T>, ISet<T>
+    {
+        private readonly ISet<T> _backingSet;
+
+        public ReadOnlySet(IEnumerable<T> enumerable)
+        {
+            _backingSet = new HashSet<T>(enumerable);
+        }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            return _backingSet.GetEnumerator();
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        void ICollection<T>.Add(T item)
+        {
+            throw new NotSupportedException("ReadOnlySet does not support 
Add.");
+        }
+
+        public bool Add(T item)
+        {
+            throw new NotSupportedException("ReadOnlySet does not support 
Add.");
+        }
+
+        public void UnionWith(IEnumerable<T> other)
+        {
+            throw new NotSupportedException("ReadOnlySet does not support 
UnionWith.");
+        }
+
+        public void IntersectWith(IEnumerable<T> other)
+        {
+            throw new NotSupportedException("ReadOnlySet does not support 
IntersectWith.");
+        }
+
+        public void ExceptWith(IEnumerable<T> other)
+        {
+            throw new NotSupportedException("ReadOnlySet does not support 
ExceptWith.");
+        }
+
+        public void SymmetricExceptWith(IEnumerable<T> other)
+        {
+            throw new NotSupportedException("ReadOnlySet does not support 
SymmetricExceptWith.");
+        }
+
+        public bool IsSubsetOf(IEnumerable<T> other)
+        {
+            return _backingSet.IsSubsetOf(other);
+        }
+
+        public bool IsSupersetOf(IEnumerable<T> other)
+        {
+            return _backingSet.IsSupersetOf(other);
+        }
+
+        public bool IsProperSupersetOf(IEnumerable<T> other)
+        {
+            return _backingSet.IsProperSupersetOf(other);
+        }
+
+        public bool IsProperSubsetOf(IEnumerable<T> other)
+        {
+            return _backingSet.IsProperSubsetOf(other);
+        }
+
+        public bool Overlaps(IEnumerable<T> other)
+        {
+            return _backingSet.Overlaps(other);
+        }
+
+        public bool SetEquals(IEnumerable<T> other)
+        {
+            return _backingSet.SetEquals(other);
+        }
+
+        public void Clear()
+        {
+            throw new NotSupportedException("ReadOnlySet does not support 
Clear.");
+        }
+
+        public bool Contains(T item)
+        {
+            return _backingSet.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            _backingSet.CopyTo(array, arrayIndex);
+        }
+
+        public bool Remove(T item)
+        {
+            throw new NotSupportedException("ReadOnlySet does not support 
Remove.");
+        }
+
+        public int Count
+        {
+            get { return _backingSet.Count; }
+        }
+
+        public bool IsReadOnly
+        {
+            get { return true; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/reef/blob/3818bf45/lang/cs/Org.Apache.REEF.Utilities/Org.Apache.Reef.Utilities.csproj
----------------------------------------------------------------------
diff --git a/lang/cs/Org.Apache.REEF.Utilities/Org.Apache.Reef.Utilities.csproj 
b/lang/cs/Org.Apache.REEF.Utilities/Org.Apache.Reef.Utilities.csproj
index 5d5129c..7baf88f 100644
--- a/lang/cs/Org.Apache.REEF.Utilities/Org.Apache.Reef.Utilities.csproj
+++ b/lang/cs/Org.Apache.REEF.Utilities/Org.Apache.Reef.Utilities.csproj
@@ -50,6 +50,7 @@ under the License.
     <Compile Include="AvroUtils.cs" />
     <Compile Include="ByteUtilities.cs" />
     <Compile Include="Collections\PriorityQueue.cs" />
+    <Compile Include="Collections\ReadOnlySet.cs" />
     <Compile Include="Diagnostics\DiagnosticsMessages.cs" />
     <Compile Include="Diagnostics\Exceptions.cs" />
     <Compile Include="IIdentifiable.cs" />

Reply via email to