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>/<context>/<shard>/<action></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