You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2017/08/18 08:04:52 UTC

[05/20] lucenenet git commit: LUCENENET-565: Porting of Lucene Replicator - Commit is for Review with comments about original Java Source for assistance.

LUCENENET-565: Porting of Lucene Replicator - Commit is for Review with comments about original Java Source for assistance.


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/6da4dd20
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/6da4dd20
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/6da4dd20

Branch: refs/heads/replicator
Commit: 6da4dd20d45b152df0c0cf5f4e6c90a8024682e5
Parents: e67244a
Author: jeme <je...@outlook.com>
Authored: Sat Jul 22 12:52:19 2017 +0200
Committer: jeme <je...@outlook.com>
Committed: Sat Jul 22 14:12:02 2017 +0200

----------------------------------------------------------------------
 Lucene.Net.sln                                  |  78 +++
 .../AspNetCoreReplicationRequest.cs             |  49 ++
 .../AspNetCoreReplicationResponse.cs            |  56 ++
 .../AspNetCoreReplicationServiceExtentions.cs   |  17 +
 .../Lucene.Net.Replicator.AspNetCore.csproj     |  82 +++
 .../Properties/AssemblyInfo.cs                  |  21 +
 .../packages.config                             |   9 +
 .../ComponentWrapperInfoStream.cs               |  54 ++
 .../Http/Abstractions/IReplicationRequest.cs    |  27 +
 .../Http/Abstractions/IReplicationResponse.cs   |  29 +
 .../Http/EnumerableExtensions.cs                |  32 +
 .../Http/HttpClientBase.cs                      | 516 ++++++++++++++
 .../Http/HttpReplicator.cs                      | 145 ++++
 .../Http/ReplicationService.cs                  | 211 ++++++
 src/Lucene.Net.Replicator/Http/package.html     |  28 +
 .../IReplicationHandler.cs                      |  32 +
 .../ISourceDirectoryFactory.cs                  |  27 +
 .../IndexAndTaxonomyReplicationHandler.cs       | 276 ++++++++
 .../IndexAndTaxonomyRevision.cs                 | 334 +++++++++
 .../IndexInputInputStream.cs                    | 102 +++
 .../IndexReplicationHandler.cs                  | 510 ++++++++++++++
 src/Lucene.Net.Replicator/IndexRevision.cs      | 200 ++++++
 src/Lucene.Net.Replicator/LocalReplicator.cs    | 416 ++++++++++++
 .../Lucene.Net.Replicator.csproj                | 108 +++
 .../PerSessionDirectoryFactory.cs               |  96 +++
 .../Properties/AssemblyInfo.cs                  |  24 +
 src/Lucene.Net.Replicator/ReplicationClient.cs  | 673 +++++++++++++++++++
 src/Lucene.Net.Replicator/Replicator.cs         |  91 +++
 src/Lucene.Net.Replicator/Revision.cs           |  81 +++
 src/Lucene.Net.Replicator/RevisionFile.cs       |  87 +++
 .../SessionExpiredException.cs                  |  58 ++
 src/Lucene.Net.Replicator/SessionToken.cs       | 129 ++++
 src/Lucene.Net.Replicator/packages.config       |   4 +
 .../Http/HttpReplicatorTest.cs                  | 104 +++
 .../Http/ReplicationServlet.cs                  |  22 +
 .../IndexAndTaxonomyReplicationClientTest.cs    | 518 ++++++++++++++
 .../IndexAndTaxonomyRevisionTest.cs             | 188 ++++++
 .../IndexReplicationClientTest.cs               | 513 ++++++++++++++
 .../IndexRevisionTest.cs                        | 177 +++++
 .../LocalReplicatorTest.cs                      | 225 +++++++
 .../Lucene.Net.Tests.Replicator.csproj          | 219 ++++++
 .../Properties/AssemblyInfo.cs                  |  19 +
 .../ReplicatorTestCase.cs                       | 192 ++++++
 .../SessionTokenTest.cs                         |  67 ++
 src/Lucene.Net.Tests.Replicator/packages.config |  52 ++
 45 files changed, 6898 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/Lucene.Net.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.sln b/Lucene.Net.sln
index a187ccc..73e8562 100644
--- a/Lucene.Net.sln
+++ b/Lucene.Net.sln
@@ -106,6 +106,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Demo", "src\Luce
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Demo", "src\Lucene.Net.Tests.Demo\Lucene.Net.Tests.Demo.csproj", "{571B361E-B0D4-445E-A0BC-1A24AA184258}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Replicator", "src\Lucene.Net.Replicator\Lucene.Net.Replicator.csproj", "{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Replicator.AspNetCore", "src\Lucene.Net.Replicator.AspNetCore\Lucene.Net.Replicator.AspNetCore.csproj", "{763CCB5A-E397-456A-AF47-7C6E228B1852}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Replicator", "src\Lucene.Net.Tests.Replicator\Lucene.Net.Tests.Replicator.csproj", "{418E9D8E-2369-4B52-8D2F-5A987213999B}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -1059,6 +1065,78 @@ Global
 		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
 		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|x86.ActiveCfg = Release|Any CPU
 		{571B361E-B0D4-445E-A0BC-1A24AA184258}.Release35|x86.Build.0 = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug|x86.Build.0 = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug35|x86.ActiveCfg = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Debug35|x86.Build.0 = Debug|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release|x86.ActiveCfg = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release|x86.Build.0 = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release35|Any CPU.Build.0 = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release35|x86.ActiveCfg = Release|Any CPU
+		{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}.Release35|x86.Build.0 = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug|x86.Build.0 = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug35|x86.ActiveCfg = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Debug35|x86.Build.0 = Debug|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release|Any CPU.Build.0 = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release|x86.ActiveCfg = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release|x86.Build.0 = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release35|Any CPU.Build.0 = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release35|x86.ActiveCfg = Release|Any CPU
+		{763CCB5A-E397-456A-AF47-7C6E228B1852}.Release35|x86.Build.0 = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug|x86.Build.0 = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug35|x86.ActiveCfg = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Debug35|x86.Build.0 = Debug|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release|x86.ActiveCfg = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release|x86.Build.0 = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release35|Any CPU.Build.0 = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release35|x86.ActiveCfg = Release|Any CPU
+		{418E9D8E-2369-4B52-8D2F-5A987213999B}.Release35|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationRequest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationRequest.cs b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationRequest.cs
new file mode 100644
index 0000000..7a9fba2
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationRequest.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Lucene.Net.Replicator.Http;
+using Lucene.Net.Replicator.Http.Abstractions;
+using Microsoft.AspNetCore.Http;
+
+namespace Lucene.Net.Replicator.AspNetCore
+{
+    /// <summary>
+    /// Abstraction for remote replication requests, allows easy integration into any hosting frameworks.
+    /// </summary>
+    /// <remarks>
+    /// .NET Specific Implementation of the Lucene Replicator using AspNetCore  
+    /// </remarks>
+    //Note: LUCENENET specific
+    public class AspNetCoreReplicationRequest : IReplicationRequest
+    {
+        private readonly HttpRequest request;
+
+        /// <summary>
+        /// Creates a <see cref="IReplicationRequest"/> wrapper around the provided <see cref="HttpRequest"/>
+        /// </summary>
+        /// <param name="request">the request to wrap</param>
+        public AspNetCoreReplicationRequest(HttpRequest request)
+        {
+            this.request = request;
+        }
+
+        /// <summary>
+        /// Provides the requested path which mapps to a replication operation.
+        /// </summary>
+        public string Path { get { return request.PathBase + request.Path; } }
+
+        /// <summary>
+        /// Returns the requested query parameter or null if not present.
+        /// Throws an exception if the same parameter is provided multiple times.
+        /// </summary>
+        /// <param name="name">the name of the requested parameter</param>
+        /// <returns>the value of the requested parameter or null if not present</returns>
+        /// <exception cref="InvalidOperationException">More than one parameter with the name was given.</exception>
+        public string QueryParam(string name)
+        {
+            return request.Query[name].SingleOrDefault();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationResponse.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationResponse.cs b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationResponse.cs
new file mode 100644
index 0000000..e671101
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationResponse.cs
@@ -0,0 +1,56 @@
+using System.IO;
+using Lucene.Net.Replicator.Http;
+using Lucene.Net.Replicator.Http.Abstractions;
+using Microsoft.AspNetCore.Http;
+
+namespace Lucene.Net.Replicator.AspNetCore
+{
+    /// <summary>
+    /// Implementation of the <see cref="IReplicationResponse"/> abstraction for the AspNetCore framework.
+    /// </summary>
+    /// <remarks>
+    /// .NET Specific Implementation of the Lucene Replicator using AspNetCore  
+    /// </remarks>
+    //Note: LUCENENET specific
+    public class AspNetCoreReplicationResponse : IReplicationResponse
+    {
+        private readonly HttpResponse response;
+
+        /// <summary>
+        /// Creates a <see cref="IReplicationResponse"/> wrapper around the provided <see cref="HttpResponse"/>
+        /// </summary>
+        /// <param name="response">the response to wrap</param>
+        public AspNetCoreReplicationResponse(HttpResponse response)
+        {
+            this.response = response;
+        }
+
+        /// <summary>
+        /// Gets or sets the http status code of the response.
+        /// </summary>
+        public int StatusCode
+        {
+            get { return response.StatusCode; }
+            set { response.StatusCode = value; }
+        }
+
+        /// <summary>
+        /// The response content.
+        /// </summary>
+        /// <remarks>
+        /// This simply returns the <see cref="HttpResponse.Body"/>.
+        /// </remarks>
+        public Stream Body { get { return response.Body; } }
+
+        /// <summary>
+        /// Flushes the reponse to the underlying response stream.
+        /// </summary>
+        /// <remarks>
+        /// This simply calls <see cref="Stream.Flush"/> on the <see cref="HttpResponse.Body"/>.
+        /// </remarks>
+        public void Flush()
+        {
+            response.Body.Flush();
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationServiceExtentions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationServiceExtentions.cs b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationServiceExtentions.cs
new file mode 100644
index 0000000..f772bfd
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationServiceExtentions.cs
@@ -0,0 +1,17 @@
+using Lucene.Net.Replicator.Http;
+using Microsoft.AspNetCore.Http;
+
+namespace Lucene.Net.Replicator.AspNetCore
+{
+    //Note: LUCENENET specific
+    public static class AspNetCoreReplicationServiceExtentions
+    {
+        /// <summary>
+        /// Extensiont method that mirrors the signature of <see cref="ReplicationService.Perform"/> using AspNetCore as implementation.
+        /// </summary>
+        public static void Perform(this ReplicationService self, HttpRequest request, HttpResponse response)
+        {
+            self.Perform(new AspNetCoreReplicationRequest(request), new AspNetCoreReplicationResponse(response));
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.csproj b/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.csproj
new file mode 100644
index 0000000..cdb84b6
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.csproj
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{763CCB5A-E397-456A-AF47-7C6E228B1852}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Replicator.AspNetCore</RootNamespace>
+    <AssemblyName>Lucene.Net.Replicator.AspNetCore</AssemblyName>
+    <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.AspNetCore.Http.Abstractions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.Http.Abstractions.1.0.3\lib\net451\Microsoft.AspNetCore.Http.Abstractions.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.AspNetCore.Http.Features, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.Http.Features.1.0.3\lib\net451\Microsoft.AspNetCore.Http.Features.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Primitives, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Primitives.1.0.1\lib\netstandard1.0\Microsoft.Extensions.Primitives.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.ComponentModel.Composition" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Text.Encodings.Web, Version=4.0.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Text.Encodings.Web.4.0.1\lib\netstandard1.0\System.Text.Encodings.Web.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AspNetCoreReplicationRequest.cs" />
+    <Compile Include="AspNetCoreReplicationResponse.cs" />
+    <Compile Include="AspNetCoreReplicationServiceExtentions.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Lucene.Net.Replicator\Lucene.Net.Replicator.csproj">
+      <Project>{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}</Project>
+      <Name>Lucene.Net.Replicator</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator.AspNetCore/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/Properties/AssemblyInfo.cs b/src/Lucene.Net.Replicator.AspNetCore/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..c0e4fd2
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/Properties/AssemblyInfo.cs
@@ -0,0 +1,21 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Lucene.Net.Replicator.AspNetCore")]
+[assembly: AssemblyDescription("AspNetCore implementation of request and response abstractions for the Lucene.Net.Replicator " +
+                               "for the Lucene.Net full - text search engine library from The Apache Software Foundation.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyDefaultAlias("Lucene.Net.Replicator.AspNetCore")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("763ccb5a-e397-456a-af47-7c6e228b1852")]

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator.AspNetCore/packages.config
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/packages.config b/src/Lucene.Net.Replicator.AspNetCore/packages.config
new file mode 100644
index 0000000..3ffed90
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/packages.config
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Microsoft.AspNetCore.Http.Abstractions" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.Http.Features" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.Extensions.Primitives" version="1.0.1" targetFramework="net451" />
+  <package id="System.Resources.ResourceManager" version="4.0.1" targetFramework="net451" />
+  <package id="System.Runtime" version="4.1.0" targetFramework="net451" />
+  <package id="System.Text.Encodings.Web" version="4.0.1" targetFramework="net451" />
+</packages>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/ComponentWrapperInfoStream.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/ComponentWrapperInfoStream.cs b/src/Lucene.Net.Replicator/ComponentWrapperInfoStream.cs
new file mode 100644
index 0000000..20d1e0e
--- /dev/null
+++ b/src/Lucene.Net.Replicator/ComponentWrapperInfoStream.cs
@@ -0,0 +1,54 @@
+using Lucene.Net.Util;
+
+namespace Lucene.Net.Replicator
+{
+    /// <summary>
+    /// Wraps a InfoStream for a specific component.
+    /// This is intented to make it a little easier to work with the InfoStreams.
+    /// </summary>
+    /// <remarks>
+    /// .NET Specific
+    /// </remarks>
+    public sealed class ComponentWrapperInfoStream : InfoStream
+    {
+        private readonly string component;
+        private readonly InfoStream innerStream;
+
+        public ComponentWrapperInfoStream(string component, InfoStream innerStream)
+        {
+            this.component = component;
+            this.innerStream = innerStream;
+        }
+
+        public override void Message(string component, string message)
+        {
+            if (IsEnabled(component))
+                innerStream.Message(component, message);
+        }
+
+        public bool IsEnabled()
+        {
+            return IsEnabled(component);
+        }
+
+        public override bool IsEnabled(string component)
+        {
+            return innerStream.IsEnabled(component);
+        }
+
+        public override object Clone()
+        {
+            return new ComponentWrapperInfoStream(component, (InfoStream)innerStream.Clone());
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                innerStream.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationRequest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationRequest.cs b/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationRequest.cs
new file mode 100644
index 0000000..ad869af
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationRequest.cs
@@ -0,0 +1,27 @@
+namespace Lucene.Net.Replicator.Http.Abstractions
+{
+    /// <summary>
+    /// Abstraction for remote replication requests, allows easy integration into any hosting frameworks.
+    /// </summary>
+    /// <remarks>
+    /// .NET Specific Abstraction  
+    /// </remarks>
+    //Note: LUCENENET specific
+    public interface IReplicationRequest
+    {
+        /// <summary>
+        /// Provides the requested path which mapps to a replication operation.
+        /// </summary>
+        string Path { get; }
+
+        /// <summary>
+        /// Returns the requested query parameter or null if not present.
+        /// </summary>
+        /// <remarks>
+        ///  May though execeptions if the same parameter is provided multiple times, consult the documentation for the specific implementation.
+        /// </remarks>
+        /// <param name="name">the name of the requested parameter</param>
+        /// <returns>the value of the requested parameter or null if not present</returns>
+        string QueryParam(string name);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationResponse.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationResponse.cs b/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationResponse.cs
new file mode 100644
index 0000000..e46f358
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationResponse.cs
@@ -0,0 +1,29 @@
+using System.IO;
+
+namespace Lucene.Net.Replicator.Http.Abstractions
+{
+    /// <summary>
+    /// Abstraction for remote replication response, allows easy integration into any hosting frameworks.
+    /// </summary>
+    /// <remarks>
+    /// .NET Specific Abstraction  
+    /// </remarks>
+    //Note: LUCENENET specific
+    public interface IReplicationResponse
+    {
+        /// <summary>
+        /// Gets or sets the http status code of the response.
+        /// </summary>
+        int StatusCode { get; set; }
+
+        /// <summary>
+        /// The response content.
+        /// </summary>
+        Stream Body { get; }
+
+        /// <summary>
+        /// Flushes the reponse to the underlying response stream.
+        /// </summary>
+        void Flush();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Http/EnumerableExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Http/EnumerableExtensions.cs b/src/Lucene.Net.Replicator/Http/EnumerableExtensions.cs
new file mode 100644
index 0000000..5247f40
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Http/EnumerableExtensions.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Replicator.Http
+{
+    /// <summary>
+    /// 
+    /// </summary>
+    /// <remarks>
+    /// .NET Specific Helper Extensions for IEnumerable
+    /// </remarks>
+    //Note: LUCENENET specific
+    public static class EnumerableExtensions
+    {
+        public static IEnumerable<TOut> InPairs<T, TOut>(this IEnumerable<T> list, Func<T, T, TOut> join)
+        {
+            using (var enumerator = list.GetEnumerator())
+            {
+                while (true)
+                {
+                    if (!enumerator.MoveNext())
+                        yield break;
+
+                    T x = enumerator.Current;
+                    if (!enumerator.MoveNext())
+                        yield return join(x, default(T));
+                    yield return join(x, enumerator.Current);
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Http/HttpClientBase.cs b/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
new file mode 100644
index 0000000..17f1c3a
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
@@ -0,0 +1,516 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+namespace Lucene.Net.Replicator.Http
+{
+    /*
+	 * 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.
+	 */
+
+    /// <summary>
+    /// Base class for Http clients.
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public abstract class HttpClientBase : IDisposable
+    {
+        /// <summary>
+        /// Default connection timeout for this client, in milliseconds.
+        /// <see cref="ConnectionTimeout"/>
+        /// </summary>
+        public const int DEFAULT_CONNECTION_TIMEOUT = 1000;
+
+        /**
+         * Default socket timeout for this client, in milliseconds.
+         * 
+         * @see #setSoTimeout(int)
+         */
+        //TODO: This goes to the Read and Write timeouts in the request (Closest we can get to a socket timeout in .NET?), those should be controlled in the messageHandler
+        //      if the choosen messagehandler provides such mechanishm (e.g. the WebRequestHandler) so this doesn't seem to make sense in .NET. 
+        //public const int DEFAULT_SO_TIMEOUT = 60000;
+
+        // TODO compression?
+
+        /// <summary>
+        /// The URL to execute requests against. 
+        /// </summary>
+        protected string Url { get; private set; }
+
+        private readonly HttpClient httpc;
+
+        //JAVA: /**
+        //JAVA:  * Set the connection timeout for this client, in milliseconds. This setting
+        //JAVA:  * is used to modify {@link HttpConnectionParams#setConnectionTimeout}.
+        //JAVA:  * 
+        //JAVA:  * @param timeout timeout to set, in millisecopnds
+        //JAVA:  */
+        //JAVA: public void setConnectionTimeout(int timeout) {
+        //JAVA:   HttpConnectionParams.setConnectionTimeout(httpc.getParams(), timeout);
+        //JAVA: }
+        /// <summary>
+        /// Gets or Sets the connection timeout for this client, in milliseconds. This setting
+        /// is used to modify <see cref="HttpClient.Timeout"/>.
+        /// </summary>
+        public int ConnectionTimeout
+        {
+            get { return (int) httpc.Timeout.TotalMilliseconds; }
+            set { httpc.Timeout = TimeSpan.FromMilliseconds(value); }
+        }
+
+        //JAVA: /**
+        //JAVA:  * Set the socket timeout for this client, in milliseconds. This setting
+        //JAVA:  * is used to modify {@link HttpConnectionParams#setSoTimeout}.
+        //JAVA:  * 
+        //JAVA:  * @param timeout timeout to set, in millisecopnds
+        //JAVA:  */
+        //JAVA: public void setSoTimeout(int timeout) {
+        //JAVA:   HttpConnectionParams.setSoTimeout(httpc.getParams(), timeout);
+        //JAVA: }
+        //TODO: This goes to the Read and Write timeouts in the request (Closest we can get to a socket timeout in .NET?), those should be controlled in the messageHandler
+        //      if the choosen messagehandler provides such mechanishm (e.g. the WebRequestHandler) so this doesn't seem to make sense in .NET. 
+        //public int SoTimeout { get; set; }
+
+        /// <summary>
+        /// Returns true if this instance was <see cref="Dispose(bool)"/>ed, otherwise
+        /// returns false. Note that if you override <see cref="Dispose(bool)"/>, you must call
+        /// <see cref="Dispose(bool)"/> on the base class, in order for this instance to be properly disposed.
+        /// </summary>
+        public bool IsDisposed { get; private set; }
+
+        //TODO: HttpMessageHandler is not really a replacement for the ClientConnectionManager, allowing for custom message handlers will
+        //      provide flexibility, this is AFAIK also where users would be able to controll the equivalent of the SO timeout.
+        protected HttpClientBase(string host, int port, string path, HttpMessageHandler messageHandler)
+        {
+            IsDisposed = false;
+
+            #region Java
+            //JAVA: /**
+            //JAVA:  * @param conMgr connection manager to use for this http client.
+            //JAVA:  *        <b>NOTE:</b>The provided {@link ClientConnectionManager} will not be
+            //JAVA:  *        {@link ClientConnectionManager#shutdown()} by this class.
+            //JAVA:  */
+            //JAVA: protected HttpClientBase(String host, int port, String path, ClientConnectionManager conMgr) {
+            //JAVA:   url = normalizedURL(host, port, path);
+            //JAVA:   httpc = new DefaultHttpClient(conMgr);
+            //JAVA:   setConnectionTimeout(DEFAULT_CONNECTION_TIMEOUT);
+            //JAVA:   setSoTimeout(DEFAULT_SO_TIMEOUT);
+            //JAVA: }
+            #endregion
+
+            Url = NormalizedUrl(host, port, path);
+            httpc = new HttpClient(messageHandler ?? new HttpClientHandler());
+            httpc.Timeout = TimeSpan.FromMilliseconds(DEFAULT_CONNECTION_TIMEOUT);
+        }
+
+        /// <summary>
+        /// Throws <see cref="ObjectDisposedException"/> if this client is already closed. 
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">client is already closed.</exception>
+        protected void EnsureOpen()
+        {
+            #region Java
+            //JAVA: protected final void ensureOpen() throws AlreadyClosedException {
+            //JAVA:   if (closed) {
+            //JAVA:     throw new AlreadyClosedException("HttpClient already closed");
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            if (IsDisposed)
+            {
+                throw new ObjectDisposedException("HttpClient already closed");
+            }
+        }
+
+        private static string NormalizedUrl(string host, int port, string path)
+        {
+            #region Java
+            //JAVA: /**
+            //JAVA:  * Create a URL out of the given parameters, translate an empty/null path to '/'
+            //JAVA:  */
+            //JAVA: private static String normalizedURL(String host, int port, String path) {
+            //JAVA:   if (path == null || path.length() == 0) {
+            //JAVA:     path = "/";
+            //JAVA:   }
+            //JAVA:   return "http://" + host + ":" + port + path;
+            //JAVA: }
+            #endregion
+
+            if (string.IsNullOrEmpty(path))
+                path = "/";
+            return string.Format("http://{0}:{1}{2}", host, port, path);
+        }
+
+        /// <summary>
+        /// Verifies the response status and if not successfull throws an exception.
+        /// </summary>
+        /// <exception cref="IOException">IO Error happened at the server, check inner exception for details.</exception>
+        /// <exception cref="HttpRequestException">Unknown error received from the server.</exception>
+        protected void VerifyStatus(HttpResponseMessage response)
+        {
+            #region Java
+            //JAVA: 
+            //JAVA: /**
+            //JAVA:  * <b>Internal:</b> response status after invocation, and in case or error attempt to read the 
+            //JAVA:  * exception sent by the server. 
+            //JAVA:  */
+            //JAVA: protected void verifyStatus(HttpResponse response) throws IOException {
+            //JAVA:   StatusLine statusLine = response.getStatusLine();
+            //JAVA:   if (statusLine.getStatusCode() != HttpStatus.SC_OK) {
+            //JAVA:     throwKnownError(response, statusLine); 
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            if (!response.IsSuccessStatusCode)
+            {
+                ThrowKnownError(response);
+            }
+        }
+
+        /// <summary>
+        /// Throws an exception for any errors.
+        /// </summary>
+        /// <exception cref="IOException">IO Error happened at the server, check inner exception for details.</exception>
+        /// <exception cref="HttpRequestException">Unknown error received from the server.</exception>
+        protected void ThrowKnownError(HttpResponseMessage response)
+        {
+            #region Java
+            //JAVA: protected void throwKnownError(HttpResponse response, StatusLine statusLine) throws IOException {
+            //JAVA:   ObjectInputStream in = null;
+            //JAVA:   try {
+            //JAVA:     in = new ObjectInputStream(response.getEntity().getContent());
+            //JAVA:   } catch (Exception e) {
+            //JAVA:     // the response stream is not an exception - could be an error in servlet.init().
+            //JAVA:     throw new RuntimeException("Uknown error: " + statusLine);
+            //JAVA:   }
+            //JAVA:   
+            //JAVA:   Throwable t;
+            //JAVA:   try {
+            //JAVA:     t = (Throwable) in.readObject();
+            //JAVA:   } catch (Exception e) { 
+            //JAVA:     //not likely
+            //JAVA:     throw new RuntimeException("Failed to read exception object: " + statusLine, e);
+            //JAVA:   } finally {
+            //JAVA:     in.close();
+            //JAVA:   }
+            //JAVA:   if (t instanceof IOException) {
+            //JAVA:     throw (IOException) t;
+            //JAVA:   }
+            //JAVA:   if (t instanceof RuntimeException) {
+            //JAVA:     throw (RuntimeException) t;
+            //JAVA:   }
+            //JAVA:   throw new RuntimeException("unknown exception "+statusLine,t);
+            //JAVA: }
+            #endregion
+
+            Stream input;
+            try
+            {
+                //.NET Note: Bridging from Async to Sync, this is not ideal and we could consider changing the interface to be Async or provide Async overloads
+                //      and have these Sync methods with their caveats.
+                input = response.Content.ReadAsStreamAsync().ConfigureAwait(false).GetAwaiter().GetResult();
+            }
+            catch (Exception)
+            {
+                // the response stream is not an exception - could be an error in servlet.init().
+                //JAVA: throw new RuntimeException("Uknown error: " + statusLine);
+                response.EnsureSuccessStatusCode();
+                //Note: This is unreachable, but the compiler and resharper cant see that EnsureSuccessStatusCode always
+                //      throws an exception in this scenario. So it complains later on in the method.
+                throw;
+            }
+
+            Exception exception;
+            try
+            {
+                TextReader reader = new StreamReader(input);
+                JsonSerializer serializer = JsonSerializer.Create(ReplicationService.JSON_SERIALIZER_SETTINGS);
+                exception = (Exception)serializer.Deserialize(new JsonTextReader(reader));
+            }
+            catch (Exception e)
+            {
+                //not likely
+                throw new HttpRequestException(string.Format("Failed to read exception object: {0} {1}", response.StatusCode, response.ReasonPhrase), e);
+            }
+            finally
+            {
+                input.Dispose();
+            }
+
+            if (exception is IOException)
+            {
+                //NOTE: Preserve server stacktrace, but there are probably better options.
+                throw new IOException(exception.Message, exception);
+            }
+            throw new HttpRequestException(string.Format("unknown exception: {0} {1}", response.StatusCode, response.ReasonPhrase), exception);
+        }
+
+        protected HttpResponseMessage ExecutePost(string request, object entity, params string[] parameters)
+        {
+            #region Java
+            //JAVA: /**
+            //JAVA:  * <b>internal:</b> execute a request and return its result
+            //JAVA:  * The <code>params</code> argument is treated as: name1,value1,name2,value2,...
+            //JAVA:  */
+            //JAVA: protected HttpResponse executePOST(String request, HttpEntity entity, String... params) throws IOException {
+            //JAVA:   ensureOpen();
+            //JAVA:   HttpPost m = new HttpPost(queryString(request, params));
+            //JAVA:   m.setEntity(entity);
+            //JAVA:   HttpResponse response = httpc.execute(m);
+            //JAVA:   verifyStatus(response);
+            //JAVA:   return response;
+            //JAVA: }
+            #endregion
+
+            EnsureOpen();
+            //.NET Note: No headers? No ContentType?... Bad use of Http?
+            HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Post, QueryString(request, parameters));
+            
+            req.Content = new StringContent(JToken.FromObject(entity, JsonSerializer.Create(ReplicationService.JSON_SERIALIZER_SETTINGS))
+                .ToString(Formatting.None), Encoding.UTF8, "application/json");
+
+            //.NET Note: Bridging from Async to Sync, this is not ideal and we could consider changing the interface to be Async or provide Async overloads
+            //      and have these Sync methods with their caveats.
+            HttpResponseMessage response = httpc.SendAsync(req).ConfigureAwait(false).GetAwaiter().GetResult();
+            VerifyStatus(response);
+            return response;
+        }
+
+        protected HttpResponseMessage ExecuteGet(string request, params string[] parameters)
+        {
+            #region Java
+            //JAVA: /**
+            //JAVA:  * <b>internal:</b> execute a request and return its result
+            //JAVA:  * The <code>params</code> argument is treated as: name1,value1,name2,value2,...
+            //JAVA:  */
+            //JAVA: protected HttpResponse executeGET(String request, String... params) throws IOException {
+            //JAVA:   ensureOpen();
+            //JAVA:   HttpGet m = new HttpGet(queryString(request, params));
+            //JAVA:   HttpResponse response = httpc.execute(m);
+            //JAVA:   verifyStatus(response);
+            //JAVA:   return response;
+            //JAVA: }
+            #endregion
+
+            EnsureOpen();
+            //Note: No headers? No ContentType?... Bad use of Http?
+            HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, QueryString(request, parameters));
+            //.NET Note: Bridging from Async to Sync, this is not ideal and we could consider changing the interface to be Async or provide Async overloads
+            //      and have these Sync methods with their caveats.
+            HttpResponseMessage response = httpc.SendAsync(req).ConfigureAwait(false).GetAwaiter().GetResult();
+            VerifyStatus(response);
+            return response;
+        }
+
+        private string QueryString(string request, params string[] parameters)
+        {
+            #region Java
+            //JAVA: private String queryString(String request, String... params) throws UnsupportedEncodingException {
+            //JAVA:   StringBuilder query = new StringBuilder(url).append('/').append(request).append('?');
+            //JAVA:   if (params != null) {
+            //JAVA:     for (int i = 0; i < params.length; i += 2) {
+            //JAVA:       query.append(params[i]).append('=').append(URLEncoder.encode(params[i+1], "UTF8")).append('&');
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA:   return query.substring(0, query.length() - 1);
+            //JAVA: }
+            #endregion
+
+            return parameters == null 
+                ? string.Format("{0}/{1}", Url, request) 
+                : string.Format("{0}/{1}?{2}", Url, request, string
+                .Join("&", parameters.Select(WebUtility.UrlEncode).InPairs((key, val) => string.Format("{0}={1}", key, val))));
+        }
+
+        /// <summary>
+        /// Internal utility: input stream of the provided response
+        /// </summary>
+        /// <exception cref="IOException"></exception>
+        public Stream ResponseInputStream(HttpResponseMessage response)// throws IOException
+        {
+            #region Java
+            //JAVA: /** Internal utility: input stream of the provided response */
+            //JAVA: public InputStream responseInputStream(HttpResponse response) throws IOException {
+            //JAVA:   return responseInputStream(response, false);
+            //JAVA: }
+            #endregion
+
+            return ResponseInputStream(response, false);
+        }
+
+        /// <summary>
+        /// Internal utility: input stream of the provided response
+        /// </summary>
+        /// <exception cref="IOException"></exception>
+        public Stream ResponseInputStream(HttpResponseMessage response, bool consume)// throws IOException
+        {
+            #region Java
+            //JAVA: TODO: can we simplify this Consuming !?!?!?
+            //JAVA: /**
+            //JAVA:  * Internal utility: input stream of the provided response, which optionally 
+            //JAVA:  * consumes the response's resources when the input stream is exhausted.
+            //JAVA:  */
+            //JAVA: public InputStream responseInputStream(HttpResponse response, boolean consume) throws IOException {
+            //JAVA:   final HttpEntity entity = response.getEntity();
+            //JAVA:   final InputStream in = entity.getContent();
+            //JAVA:   if (!consume) {
+            //JAVA:     return in;
+            //JAVA:   }
+            //JAVA:   return new InputStream() {
+            //JAVA:     private boolean consumed = false;
+            //JAVA:     @Override
+            //JAVA:     public int read() throws IOException {
+            //JAVA:       final int res = in.read();
+            //JAVA:       consume(res);
+            //JAVA:       return res;
+            //JAVA:     }
+            //JAVA:     @Override
+            //JAVA:     public void close() throws IOException {
+            //JAVA:       super.close();
+            //JAVA:       consume(-1);
+            //JAVA:     }
+            //JAVA:     @Override
+            //JAVA:     public int read(byte[] b) throws IOException {
+            //JAVA:       final int res = super.read(b);
+            //JAVA:       consume(res);
+            //JAVA:       return res;
+            //JAVA:     }
+            //JAVA:     @Override
+            //JAVA:     public int read(byte[] b, int off, int len) throws IOException {
+            //JAVA:       final int res = super.read(b, off, len);
+            //JAVA:       consume(res);
+            //JAVA:       return res;
+            //JAVA:     }
+            //JAVA:     private void consume(int minusOne) {
+            //JAVA:       if (!consumed && minusOne==-1) {
+            //JAVA:         try {
+            //JAVA:           EntityUtils.consume(entity);
+            //JAVA:         } catch (Exception e) {
+            //JAVA:           // ignored on purpose
+            //JAVA:         }
+            //JAVA:         consumed = true;
+            //JAVA:       }
+            //JAVA:     }
+            //JAVA:   };
+            //JAVA: }
+            #endregion
+
+            return response.Content.ReadAsStreamAsync().ConfigureAwait(false).GetAwaiter().GetResult();
+        }
+
+        protected T DoAction<T>(HttpResponseMessage response, Func<T> call)
+        {
+            #region Java
+            //JAVA: /**
+            //JAVA:  * Same as {@link #doAction(HttpResponse, boolean, Callable)} but always do consume at the end.
+            //JAVA:  */
+            //JAVA: protected <T> T doAction(HttpResponse response, Callable<T> call) throws IOException {
+            //JAVA:   return doAction(response, true, call);
+            //JAVA: }
+            #endregion
+
+            return DoAction(response, true, call);
+        }
+
+        protected T DoAction<T>(HttpResponseMessage response, bool consume, Func<T> call)
+        {
+            #region Java
+            //JAVA: /**
+            //JAVA:  * Do a specific action and validate after the action that the status is still OK, 
+            //JAVA:  * and if not, attempt to extract the actual server side exception. Optionally
+            //JAVA:  * release the response at exit, depending on <code>consume</code> parameter.
+            //JAVA:  */
+            //JAVA: protected <T> T doAction(HttpResponse response, boolean consume, Callable<T> call) throws IOException {
+            //JAVA:   IOException error = null;
+            //JAVA:   try {
+            //JAVA:     return call.call();
+            //JAVA:   } catch (IOException e) {
+            //JAVA:     error = e;
+            //JAVA:   } catch (Exception e) {
+            //JAVA:     error = new IOException(e);
+            //JAVA:   } finally {
+            //JAVA:     try {
+            //JAVA:       verifyStatus(response);
+            //JAVA:     } finally {
+            //JAVA:       if (consume) {
+            //JAVA:         try {
+            //JAVA:           EntityUtils.consume(response.getEntity());
+            //JAVA:         } catch (Exception e) {
+            //JAVA:           // ignoring on purpose
+            //JAVA:         }
+            //JAVA:       }
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA:   throw error; // should not get here
+            //JAVA: }
+            #endregion
+
+            Exception error = new NotImplementedException();
+            try
+            {
+                return call();
+            }
+            catch (IOException e)
+            {
+                error = e;
+            }
+            catch (Exception e)
+            {
+                error = new IOException(e.Message, e);
+            }
+            finally
+            {
+                try
+                {
+                    VerifyStatus(response);
+                }
+                finally
+                {
+                    //TODO: Is there any reason for this on .NET?... What are they trying to achieve?
+                    //JAVA:       if (consume) {
+                    //JAVA:         try {
+                    //JAVA:           EntityUtils.consume(response.getEntity());
+                    //JAVA:         } catch (Exception e) {
+                    //JAVA:           // ignoring on purpose
+                    //JAVA:         }
+                    //JAVA:       }
+                }
+            }
+            throw error; // should not get here
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            IsDisposed = true;
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Http/HttpReplicator.cs b/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
new file mode 100644
index 0000000..90df85b
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
@@ -0,0 +1,145 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Lucene.Net.Support.IO;
+
+namespace Lucene.Net.Replicator.Http
+{
+    /*
+	 * 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.
+	 */
+
+    /// <summary>
+    /// An HTTP implementation of <see cref="IReplicator"/>. Assumes the API supported by <see cref="ReplicationService"/>.
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public class HttpReplicator : HttpClientBase, IReplicator
+    {
+        public HttpReplicator(string host, int port, string path, HttpMessageHandler messageHandler) 
+            : base(host, port, path, messageHandler)
+        {
+            #region Java
+            //JAVA: /** Construct with specified connection manager. */
+            //JAVA: public HttpReplicator(String host, int port, String path, ClientConnectionManager conMgr) {
+            //JAVA:   super(host, port, path, conMgr);
+            //JAVA: }
+            #endregion
+        }
+        
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="revision"></param>
+        /// <exception cref="NotSupportedException">this replicator implementation does not support remote publishing of revisions</exception>
+        public void Publish(IRevision revision)
+        {
+            throw new NotSupportedException("this replicator implementation does not support remote publishing of revisions");
+        }
+
+        public SessionToken CheckForUpdate(string currentVersion)
+        {
+            #region Java
+            //JAVA: public SessionToken checkForUpdate(String currVersion) throws IOException {
+            //JAVA:   String[] params = null;
+            //JAVA:   if (currVersion != null) {
+            //JAVA:     params = new String[] { ReplicationService.REPLICATE_VERSION_PARAM, currVersion };
+            //JAVA:   }
+            //JAVA:   final HttpResponse response = executeGET(ReplicationAction.UPDATE.name(), params);
+            //JAVA:   return doAction(response, new Callable<SessionToken>() {
+            //JAVA:     @Override
+            //JAVA:     public SessionToken call() throws Exception {
+            //JAVA:       final DataInputStream dis = new DataInputStream(responseInputStream(response));
+            //JAVA:       try {
+            //JAVA:         if (dis.readByte() == 0) {
+            //JAVA:           return null;
+            //JAVA:         } else {
+            //JAVA:           return new SessionToken(dis);
+            //JAVA:         }
+            //JAVA:       } finally {
+            //JAVA:         dis.close();
+            //JAVA:       }
+            //JAVA:     }
+            //JAVA:   });
+            //JAVA: }
+            #endregion
+
+            string[] parameters = null;
+            if (currentVersion != null)
+                parameters = new [] { ReplicationService.REPLICATE_VERSION_PARAM, currentVersion };
+
+            HttpResponseMessage response = base.ExecuteGet( ReplicationService.ReplicationAction.UPDATE.ToString(), parameters);
+            return DoAction(response, () =>
+            {
+                using (DataInputStream inputStream = new DataInputStream(ResponseInputStream(response)))
+                {
+                    return inputStream.ReadByte() == 0 ? null : new SessionToken(inputStream);
+                }
+            });
+        }
+
+        public void Release(string sessionId)
+        {
+            #region Java
+            //JAVA: public void release(String sessionID) throws IOException {
+            //JAVA:   String[] params = new String[] {
+            //JAVA:       ReplicationService.REPLICATE_SESSION_ID_PARAM, sessionID
+            //JAVA:   };
+            //JAVA:   final HttpResponse response = executeGET(ReplicationAction.RELEASE.name(), params);
+            //JAVA:   doAction(response, new Callable<Object>() {
+            //JAVA:     @Override
+            //JAVA:     public Object call() throws Exception {
+            //JAVA:       return null; // do not remove this call: as it is still validating for us!
+            //JAVA:     }
+            //JAVA:   });
+            //JAVA: }
+            #endregion
+
+            HttpResponseMessage response = ExecuteGet(ReplicationService.ReplicationAction.RELEASE.ToString(), ReplicationService.REPLICATE_SESSION_ID_PARAM, sessionId);
+            // do not remove this call: as it is still validating for us!
+            DoAction<object>(response, () => null);
+        }
+
+        public Stream ObtainFile(string sessionId, string source, string fileName)
+        {
+            #region Java
+            //JAVA: public InputStream obtainFile(String sessionID, String source, String fileName) throws IOException {
+            //JAVA:   String[] params = new String[] {
+            //JAVA:       ReplicationService.REPLICATE_SESSION_ID_PARAM, sessionID,
+            //JAVA:       ReplicationService.REPLICATE_SOURCE_PARAM, source,
+            //JAVA:       ReplicationService.REPLICATE_FILENAME_PARAM, fileName,
+            //JAVA:   };
+            //JAVA:   final HttpResponse response = executeGET(ReplicationAction.OBTAIN.name(), params);
+            //JAVA:   return doAction(response, false, new Callable<InputStream>() {
+            //JAVA:     @Override
+            //JAVA:     public InputStream call() throws Exception {
+            //JAVA:       return responseInputStream(response,true);
+            //JAVA:     }
+            //JAVA:   });
+            //JAVA: }
+            #endregion
+            HttpResponseMessage response = ExecuteGet(ReplicationService.ReplicationAction.OBTAIN.ToString(), 
+                ReplicationService.REPLICATE_SESSION_ID_PARAM, sessionId,
+                ReplicationService.REPLICATE_SOURCE_PARAM, source,
+                ReplicationService.REPLICATE_FILENAME_PARAM, fileName);
+            return DoAction(response, false, () => ResponseInputStream(response));
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Http/ReplicationService.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Http/ReplicationService.cs b/src/Lucene.Net.Replicator/Http/ReplicationService.cs
new file mode 100644
index 0000000..d004fc7
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Http/ReplicationService.cs
@@ -0,0 +1,211 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Lucene.Net.Replicator.Http.Abstractions;
+using Lucene.Net.Support.IO;
+using Newtonsoft.Json;
+
+namespace Lucene.Net.Replicator.Http
+{
+    /*
+	 * 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.
+	 */
+
+    /// <summary>
+    /// A server-side service for handling replication requests. The service assumes
+    /// requests are sent in the format <code>/&lt;context&gt;/&lt;shard&gt;/&lt;action&gt;</code> where
+    /// <ul>
+    ///   <li><code>context</code> is the servlet context, e.g. <see cref="REPLICATION_CONTEXT"/></li>
+    ///   <li><code>shard</code> is the ID of the shard, e.g. "s1"</li>
+    ///   <li><code>action</code> is one of <see cref="ReplicationAction"/> values</li>
+    /// </ul>
+    /// For example, to check whether there are revision updates for shard "s1" you
+    /// should send the request: <code>http://host:port/replicate/s1/update</code>.
+    /// </summary>
+    /// <remarks>
+    /// This service is written using abstractions over requests and responses which makes it easy
+    /// to integrate into any hosting framework.
+    /// <p>
+    /// See the Lucene.Net.Replicator.AspNetCore for an example of an implementation for the AspNetCore Framework.
+    /// </p> 
+    /// </remarks>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public class ReplicationService
+    {
+        /// <summary>
+        /// Actions supported by the <see cref="ReplicationService"/>.
+        /// </summary>
+        public enum ReplicationAction
+        {
+            OBTAIN, RELEASE, UPDATE
+        }
+
+        /// <summary>
+        /// The default context path for the <see cref="ReplicationService"/>.
+        /// </summary>
+        public const string REPLICATION_CONTEXT = "/replicate";
+
+        /// <summary>
+        /// Request parameter name for providing the revision version.
+        /// </summary>
+        public const string REPLICATE_VERSION_PARAM = "version";
+
+        /// <summary>
+        /// Request parameter name for providing a session ID.
+        /// </summary>
+        public const string REPLICATE_SESSION_ID_PARAM = "sessionid";
+
+        /// <summary>
+        /// Request parameter name for providing the file's source.
+        /// </summary>
+        public const string REPLICATE_SOURCE_PARAM = "source";
+
+        /// <summary>
+        /// Request parameter name for providing the file's name.
+        /// </summary>
+        public const string REPLICATE_FILENAME_PARAM = "filename";
+
+        /// <summary>
+        /// Json Serializer Settings to use when serializing and deserializing errors.
+        /// </summary>
+        public static readonly JsonSerializerSettings JSON_SERIALIZER_SETTINGS = new JsonSerializerSettings()
+        {
+            TypeNameHandling = TypeNameHandling.All
+        };
+
+        private const int SHARD_IDX = 0, ACTION_IDX = 1;
+
+        private readonly string context;
+        private readonly IDictionary<string, IReplicator> replicators;
+
+        public ReplicationService(IDictionary<string, IReplicator> replicators, string context = REPLICATION_CONTEXT)
+        {
+            this.context = context;
+            this.replicators = replicators;
+        }
+
+        /// <summary>
+        /// Returns the path elements that were given in the servlet request, excluding the servlet's action context.
+        /// </summary>
+        private string[] GetPathElements(IReplicationRequest request)
+        {
+            string path = request.Path;
+
+            int actionLength = context.Length;
+            int startIndex = actionLength;
+
+            if (path.Length > actionLength && path[actionLength] == '/')
+                ++startIndex;
+
+            return path.Substring(startIndex).Split('/');
+        }
+
+        private static string ExtractRequestParam(IReplicationRequest request, string paramName)
+        {
+            string param = request.QueryParam(paramName);
+            if (param == null)
+            {
+                //JAVA: throw new ServletException("Missing mandatory parameter: " + paramName);
+                throw new InvalidOperationException("Missing mandatory parameter: " + paramName);
+            }
+            return param;
+        }
+
+
+        /// <summary>
+        /// Executes the replication task.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">required parameters are missing</exception>
+        public void Perform(IReplicationRequest request, IReplicationResponse response)
+        {
+            string[] pathElements = GetPathElements(request);
+            if (pathElements.Length != 2)
+            {
+                throw new InvalidOperationException("invalid path, must contain shard ID and action, e.g. */s1/update");
+            }
+
+            ReplicationAction action;
+            if (!Enum.TryParse(pathElements[ACTION_IDX], true, out action))
+            {
+                throw new InvalidOperationException("Unsupported action provided: " + pathElements[ACTION_IDX]);
+            }
+
+            IReplicator replicator;
+            if (!replicators.TryGetValue(pathElements[SHARD_IDX], out replicator))
+            {
+                throw new InvalidOperationException("unrecognized shard ID " + pathElements[SHARD_IDX]);
+            }
+
+            // SOLR-8933 Don't close this stream.
+            try
+            {
+                switch (action)
+                {
+                    case ReplicationAction.OBTAIN:
+                        string sessionId = ExtractRequestParam(request, REPLICATE_SESSION_ID_PARAM);
+                        string fileName = ExtractRequestParam(request, REPLICATE_FILENAME_PARAM);
+                        string source = ExtractRequestParam(request, REPLICATE_SOURCE_PARAM);
+                        using (Stream stream = replicator.ObtainFile(sessionId, source, fileName))
+                            stream.CopyTo(response.Body);
+                        break;
+
+                    case ReplicationAction.RELEASE:
+                        replicator.Release(ExtractRequestParam(request, REPLICATE_SESSION_ID_PARAM));
+                        break;
+
+                    case ReplicationAction.UPDATE:
+                        string currentVersion = request.QueryParam(REPLICATE_VERSION_PARAM);
+                        SessionToken token = replicator.CheckForUpdate(currentVersion);
+                        if (token == null)
+                        {
+                            response.Body.Write(new byte[] { 0 }, 0, 1); // marker for null token
+                        }
+                        else
+                        {
+                            response.Body.Write(new byte[] { 1 }, 0, 1);
+                            token.Serialize(new DataOutputStream(response.Body));
+                        }
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException();
+                }
+            }
+            catch (Exception e)
+            {
+                response.StatusCode = 500;
+                try
+                {
+                    TextWriter writer = new StreamWriter(response.Body);
+                    JsonSerializer serializer = JsonSerializer.Create(JSON_SERIALIZER_SETTINGS);
+                    serializer.Serialize(writer, e, e.GetType());
+                }
+                catch (Exception exception)
+                {
+                    throw new IOException("Could not serialize", exception);
+                }
+            }
+            finally
+            {
+                response.Flush();
+            }
+        }
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Http/package.html
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Http/package.html b/src/Lucene.Net.Replicator/Http/package.html
new file mode 100644
index 0000000..fce050b
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Http/package.html
@@ -0,0 +1,28 @@
+<html>
+
+<!-- 
+ 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.
+-->
+
+<head>
+<title>HTTP replication implementation</title>
+</head>
+
+<body>
+<h1>HTTP replication implementation</h1>
+</body>
+
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/IReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IReplicationHandler.cs b/src/Lucene.Net.Replicator/IReplicationHandler.cs
new file mode 100644
index 0000000..1976435
--- /dev/null
+++ b/src/Lucene.Net.Replicator/IReplicationHandler.cs
@@ -0,0 +1,32 @@
+//STATUS: DRAFT - 4.8.0
+using System;
+using System.Collections.Generic;
+using System.IO;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Replicator
+{
+    /// <summary>Handler for revisions obtained by the client.</summary>
+    //Note: LUCENENET specific denesting of interface
+    public interface IReplicationHandler
+    {
+        /// <summary>Returns the current revision files held by the handler.</summary>
+        string CurrentVersion { get; }
+
+        /// <summary>Returns the current revision version held by the handler.</summary>
+        IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; }
+
+        /// <summary>
+        /// Called when a new revision was obtained and is available (i.e. all needed files were successfully copied).
+        /// </summary>
+        /// <param name="version">The version of the <see cref="IRevision"/> that was copied</param>
+        /// <param name="revisionFiles"> the files contained by this <see cref="IRevision"/></param>
+        /// <param name="copiedFiles">the files that were actually copied</param>
+        /// <param name="sourceDirectory">a mapping from a source of files to the <see cref="Directory"/> they were copied into</param>
+        /// <see cref="IOException"/>
+        void RevisionReady(string version,
+            IDictionary<string, IList<RevisionFile>> revisionFiles,
+            IDictionary<string, IList<string>> copiedFiles,
+            IDictionary<string, Directory> sourceDirectory);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/ISourceDirectoryFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/ISourceDirectoryFactory.cs b/src/Lucene.Net.Replicator/ISourceDirectoryFactory.cs
new file mode 100644
index 0000000..7942b91
--- /dev/null
+++ b/src/Lucene.Net.Replicator/ISourceDirectoryFactory.cs
@@ -0,0 +1,27 @@
+using Lucene.Net.Store;
+
+namespace Lucene.Net.Replicator
+{
+    /// <summary>
+    /// Resolves a session and source into a <see cref="Directory"/> to use for copying
+    /// the session files to.
+    /// </summary>
+    //Note: LUCENENET specific denesting of interface
+    public interface ISourceDirectoryFactory
+    {
+        /// <summary>
+        /// Returns the <see cref="Directory"/> to use for the given session and source.
+        /// Implementations may e.g. return different directories for different
+        /// sessions, or the same directory for all sessions. In that case, it is
+        /// advised to clean the directory before it is used for a new session.
+        /// </summary>
+        /// <seealso cref="CleanupSession"/>
+        Directory GetDirectory(string sessionId, string source); //throws IOException;
+
+        /// <summary>
+        /// Called to denote that the replication actions for this session were finished and the directory is no longer needed. 
+        /// </summary>
+        /// <exception cref="System.IO.IOException"></exception>
+        void CleanupSession(string sessionId);
+    }
+}
\ No newline at end of file