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:48 UTC

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

Repository: lucenenet
Updated Branches:
  refs/heads/replicator [created] 140551230


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs b/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..457c56c
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs
@@ -0,0 +1,19 @@
+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.Tests.Replicator")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[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("418e9d8e-2369-4b52-8d2f-5a987213999b")]

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
new file mode 100644
index 0000000..1b8ec1e
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
@@ -0,0 +1,192 @@
+//STATUS: PENDING - 4.8.0
+
+using System;
+using Lucene.Net.Replicator.Http;
+using Lucene.Net.Util;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.TestHost;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Lucene.Net.Tests.Replicator
+{
+    /*
+	 * 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.
+	 */
+
+    public class ReplicatorTestCase : LuceneTestCase
+    {
+        //JAVA:  private static ClientConnectionManager clientConnectionManager;
+        //JAVA:  
+        //JAVA:  @AfterClass
+        //JAVA:  public static void afterClassReplicatorTestCase() throws Exception {
+        //JAVA:    if (clientConnectionManager != null) {
+        //JAVA:      clientConnectionManager.shutdown();
+        //JAVA:      clientConnectionManager = null;
+        //JAVA:    }
+        //JAVA:  }
+        //JAVA:  
+
+
+        public static TestServer NewHttpServer<TStartUp>(ReplicationService service) where TStartUp : class
+        {
+            #region JAVA
+            //JAVA:  /**
+            //JAVA:   * Returns a new {@link Server HTTP Server} instance. To obtain its port, use
+            //JAVA:   * {@link #serverPort(Server)}.
+            //JAVA:   */
+            //JAVA:  public static synchronized Server newHttpServer(Handler handler) throws Exception {
+            //JAVA:    Server server = new Server(0);
+            //JAVA:    
+            //JAVA:    server.setHandler(handler);
+            //JAVA:    
+            //JAVA:    final String connectorName = System.getProperty("tests.jettyConnector", "SelectChannel");
+            //JAVA:    
+            //JAVA:    // if this property is true, then jetty will be configured to use SSL
+            //JAVA:    // leveraging the same system properties as java to specify
+            //JAVA:    // the keystore/truststore if they are set
+            //JAVA:    //
+            //JAVA:    // This means we will use the same truststore, keystore (and keys) for
+            //JAVA:    // the server as well as any client actions taken by this JVM in
+            //JAVA:    // talking to that server, but for the purposes of testing that should 
+            //JAVA:    // be good enough
+            //JAVA:    final boolean useSsl = Boolean.getBoolean("tests.jettySsl");
+            //JAVA:    final SslContextFactory sslcontext = new SslContextFactory(false);
+            //JAVA:    
+            //JAVA:    if (useSsl) {
+            //JAVA:      if (null != System.getProperty("javax.net.ssl.keyStore")) {
+            //JAVA:        sslcontext.setKeyStorePath
+            //JAVA:        (System.getProperty("javax.net.ssl.keyStore"));
+            //JAVA:      }
+            //JAVA:      if (null != System.getProperty("javax.net.ssl.keyStorePassword")) {
+            //JAVA:        sslcontext.setKeyStorePassword
+            //JAVA:        (System.getProperty("javax.net.ssl.keyStorePassword"));
+            //JAVA:      }
+            //JAVA:      if (null != System.getProperty("javax.net.ssl.trustStore")) {
+            //JAVA:        sslcontext.setTrustStore
+            //JAVA:        (System.getProperty("javax.net.ssl.trustStore"));
+            //JAVA:      }
+            //JAVA:      if (null != System.getProperty("javax.net.ssl.trustStorePassword")) {
+            //JAVA:        sslcontext.setTrustStorePassword
+            //JAVA:        (System.getProperty("javax.net.ssl.trustStorePassword"));
+            //JAVA:      }
+            //JAVA:      sslcontext.setNeedClientAuth(Boolean.getBoolean("tests.jettySsl.clientAuth"));
+            //JAVA:    }
+            //JAVA:    
+            //JAVA:    final Connector connector;
+            //JAVA:    final QueuedThreadPool threadPool;
+            //JAVA:    if ("SelectChannel".equals(connectorName)) {
+            //JAVA:      final SelectChannelConnector c = useSsl ? new SslSelectChannelConnector(sslcontext) : new SelectChannelConnector();
+            //JAVA:      c.setReuseAddress(true);
+            //JAVA:      c.setLowResourcesMaxIdleTime(1500);
+            //JAVA:      connector = c;
+            //JAVA:      threadPool = (QueuedThreadPool) c.getThreadPool();
+            //JAVA:    } else if ("Socket".equals(connectorName)) {
+            //JAVA:      final SocketConnector c = useSsl ? new SslSocketConnector(sslcontext) : new SocketConnector();
+            //JAVA:      c.setReuseAddress(true);
+            //JAVA:      connector = c;
+            //JAVA:      threadPool = (QueuedThreadPool) c.getThreadPool();
+            //JAVA:    } else {
+            //JAVA:      throw new IllegalArgumentException("Illegal value for system property 'tests.jettyConnector': " + connectorName);
+            //JAVA:    }
+            //JAVA:    
+            //JAVA:    connector.setPort(0);
+            //JAVA:    connector.setHost("127.0.0.1");
+            //JAVA:    if (threadPool != null) {
+            //JAVA:      threadPool.setDaemon(true);
+            //JAVA:      threadPool.setMaxThreads(10000);
+            //JAVA:      threadPool.setMaxIdleTimeMs(5000);
+            //JAVA:      threadPool.setMaxStopTimeMs(30000);
+            //JAVA:    }
+            //JAVA:    
+            //JAVA:    server.setConnectors(new Connector[] {connector});
+            //JAVA:    server.setSessionIdManager(new HashSessionIdManager(new Random(random().nextLong())));
+            //JAVA:    
+            //JAVA:    server.start();
+            //JAVA:    
+            //JAVA:    return server;
+            //JAVA:  }
+            //JAVA:  
+            #endregion
+
+            var server = new TestServer(new WebHostBuilder()
+                .ConfigureServices(container =>
+                {
+                    container.AddSingleton(service);
+                }).UseStartup<TStartUp>());
+            server.BaseAddress = new Uri("http://localhost" + ReplicationService.REPLICATION_CONTEXT);
+            return server;
+        }
+
+        /// <summary>
+        /// Returns a <see cref="server"/>'s port. 
+        /// </summary>
+        public static int ServerPort(TestServer server)
+        {
+            //JAVA:  /** Returns a {@link Server}'s port. */
+            //JAVA:  public static int serverPort(Server server) {
+            //JAVA:    return server.getConnectors()[0].getLocalPort();
+            //JAVA:  }
+            return server.BaseAddress.Port;
+        }
+
+        /// <summary>
+        /// Returns a <see cref="server"/>'s host. 
+        /// </summary>
+        public static string ServerHost(TestServer server)
+        {
+            //JAVA:  /** Returns a {@link Server}'s host. */
+            //JAVA:  public static String serverHost(Server server) {
+            //JAVA:    return server.getConnectors()[0].getHost();
+            //JAVA:  }
+            return server.BaseAddress.Host;
+        }
+
+        /// <summary>
+        /// Stops the given HTTP Server instance.
+        /// </summary>
+        public static void StopHttpServer(TestServer server)
+        {
+            //JAVA:  /**
+            //JAVA:   * Stops the given HTTP Server instance. This method does its best to guarantee
+            //JAVA:   * that no threads will be left running following this method.
+            //JAVA:   */
+            //JAVA:  public static void stopHttpServer(Server httpServer) throws Exception {
+            //JAVA:    httpServer.stop();
+            //JAVA:    httpServer.join();
+            //JAVA:  }
+            server.Dispose();
+        }
+
+        //JAVA:  
+        //JAVA:  /**
+        //JAVA:   * Returns a {@link ClientConnectionManager}.
+        //JAVA:   * <p>
+        //JAVA:   * <b>NOTE:</b> do not {@link ClientConnectionManager#shutdown()} this
+        //JAVA:   * connection manager, it will be shutdown automatically after all tests have
+        //JAVA:   * finished.
+        //JAVA:   */
+        //JAVA:  public static synchronized ClientConnectionManager getClientConnectionManager() {
+        //JAVA:    if (clientConnectionManager == null) {
+        //JAVA:      PoolingClientConnectionManager ccm = new PoolingClientConnectionManager();
+        //JAVA:      ccm.setDefaultMaxPerRoute(128);
+        //JAVA:      ccm.setMaxTotal(128);
+        //JAVA:      clientConnectionManager = ccm;
+        //JAVA:    }
+        //JAVA:    
+        //JAVA:    return clientConnectionManager;
+        //JAVA:  }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs b/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
new file mode 100644
index 0000000..7c98f88
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
@@ -0,0 +1,67 @@
+//STATUS: DRAFT - 4.8.0
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Store;
+using Lucene.Net.Support.IO;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Tests.Replicator
+{
+    /*
+	 * 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.
+	 */
+
+    public class SessionTokenTest : ReplicatorTestCase
+    {
+        [Test]
+        public void TestSerialization()
+        {
+            Directory directory = NewDirectory();
+            IndexWriterConfig config = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            config.IndexDeletionPolicy = new SnapshotDeletionPolicy(config.IndexDeletionPolicy);
+
+            IndexWriter writer = new IndexWriter(directory, config);
+            writer.AddDocument(new Document());
+            writer.Commit();
+            IRevision revision = new IndexRevision(writer);
+
+            SessionToken session1 = new SessionToken("17", revision);
+            MemoryStream baos = new MemoryStream();
+            session1.Serialize(new DataOutputStream(baos));
+            byte[] b = baos.ToArray();
+
+            SessionToken session2 = new SessionToken(new DataInputStream(new MemoryStream(b)));
+            assertEquals(session1.Id, session2.Id);
+            assertEquals(session1.Version, session2.Version);
+            assertEquals(1, session2.SourceFiles.Count);
+            assertEquals(session1.SourceFiles.Count, session2.SourceFiles.Count);
+            assertEquals(session1.SourceFiles.Keys, session2.SourceFiles.Keys);
+            IList<RevisionFile> files1 = session1.SourceFiles.Values.First();
+            IList<RevisionFile> files2 = session2.SourceFiles.Values.First();
+            assertEquals(files1, files2);
+
+            IOUtils.Dispose(writer, directory);
+        }
+        
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/packages.config
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/packages.config b/src/Lucene.Net.Tests.Replicator/packages.config
new file mode 100644
index 0000000..1f96d54
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/packages.config
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Microsoft.AspNetCore.Hosting" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.Hosting.Abstractions" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.Hosting.Server.Abstractions" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.Http" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.Http.Abstractions" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.Http.Extensions" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.Http.Features" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.TestHost" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.AspNetCore.WebUtilities" version="1.0.3" targetFramework="net451" />
+  <package id="Microsoft.Extensions.Configuration" version="1.0.2" targetFramework="net451" />
+  <package id="Microsoft.Extensions.Configuration.Abstractions" version="1.0.2" targetFramework="net451" />
+  <package id="Microsoft.Extensions.Configuration.EnvironmentVariables" version="1.0.2" targetFramework="net451" />
+  <package id="Microsoft.Extensions.DependencyInjection" version="1.0.2" targetFramework="net451" />
+  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="1.0.2" targetFramework="net451" />
+  <package id="Microsoft.Extensions.FileProviders.Abstractions" version="1.0.1" targetFramework="net451" />
+  <package id="Microsoft.Extensions.FileProviders.Physical" version="1.0.1" targetFramework="net451" />
+  <package id="Microsoft.Extensions.FileSystemGlobbing" version="1.0.1" targetFramework="net451" />
+  <package id="Microsoft.Extensions.Logging" version="1.0.2" targetFramework="net451" />
+  <package id="Microsoft.Extensions.Logging.Abstractions" version="1.0.2" targetFramework="net451" />
+  <package id="Microsoft.Extensions.ObjectPool" version="1.0.1" targetFramework="net451" />
+  <package id="Microsoft.Extensions.Options" version="1.0.2" targetFramework="net451" />
+  <package id="Microsoft.Extensions.PlatformAbstractions" version="1.0.0" targetFramework="net451" />
+  <package id="Microsoft.Extensions.Primitives" version="1.0.1" targetFramework="net451" />
+  <package id="Microsoft.Net.Http.Headers" version="1.0.3" targetFramework="net451" />
+  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net451" />
+  <package id="NUnit" version="3.5.0" targetFramework="net451" />
+  <package id="System.Buffers" version="4.0.0" targetFramework="net451" />
+  <package id="System.Collections" version="4.0.11" targetFramework="net451" />
+  <package id="System.Collections.Concurrent" version="4.0.12" targetFramework="net451" />
+  <package id="System.Collections.Immutable" version="1.2.0" targetFramework="net451" />
+  <package id="System.ComponentModel" version="4.0.1" targetFramework="net451" />
+  <package id="System.Diagnostics.Contracts" version="4.0.1" targetFramework="net451" />
+  <package id="System.Diagnostics.Debug" version="4.0.11" targetFramework="net451" />
+  <package id="System.Diagnostics.DiagnosticSource" version="4.0.0" targetFramework="net451" />
+  <package id="System.Globalization" version="4.0.11" targetFramework="net451" />
+  <package id="System.IO" version="4.1.0" targetFramework="net451" />
+  <package id="System.Linq" version="4.1.0" targetFramework="net451" />
+  <package id="System.Linq.Expressions" version="4.1.1" targetFramework="net451" />
+  <package id="System.Reflection" version="4.1.0" targetFramework="net451" />
+  <package id="System.Reflection.Metadata" version="1.3.0" 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.Runtime.Extensions" version="4.1.0" targetFramework="net451" />
+  <package id="System.Runtime.InteropServices" version="4.1.0" targetFramework="net451" />
+  <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.0.0" targetFramework="net451" />
+  <package id="System.Text.Encoding" version="4.0.11" targetFramework="net451" />
+  <package id="System.Text.Encodings.Web" version="4.0.1" targetFramework="net451" />
+  <package id="System.Threading" version="4.0.11" targetFramework="net451" />
+  <package id="System.Threading.Tasks" version="4.0.11" targetFramework="net451" />
+</packages>
\ No newline at end of file


[07/20] lucenenet git commit: LUCENENET-565: Porting of Lucene Replicator, cleanup stage 1

Posted by ni...@apache.org.
LUCENENET-565: Porting of Lucene Replicator, cleanup stage 1


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

Branch: refs/heads/replicator
Commit: e3305307d237e2ffea30f66bb4f83e32830f20e6
Parents: 6da4dd2
Author: jeme <je...@outlook.com>
Authored: Tue Aug 8 00:12:44 2017 +0200
Committer: Jens Melgaard <ad...@it-links.dk>
Committed: Thu Aug 10 12:13:57 2017 +0200

----------------------------------------------------------------------
 .../Lucene.Net.Replicator.AspNetCore.csproj     |   1 +
 .../examples.md                                 |   1 +
 .../ComponentWrapperInfoStream.cs               |  54 ---
 .../Http/Abstractions/IReplicationRequest.cs    |  17 +
 .../Http/Abstractions/IReplicationResponse.cs   |  17 +
 .../Http/EnumerableExtensions.cs                |  32 --
 .../Http/HttpClientBase.cs                      | 352 ++++---------------
 .../Http/HttpReplicator.cs                      | 105 ++----
 .../Http/ReplicationService.cs                  |   5 +-
 .../IReplicationHandler.cs                      |   2 +-
 .../IndexAndTaxonomyReplicationHandler.cs       |  97 +----
 .../IndexAndTaxonomyRevision.cs                 | 137 +-------
 .../IndexReplicationHandler.cs                  | 202 +----------
 src/Lucene.Net.Replicator/IndexRevision.cs      |  63 ----
 src/Lucene.Net.Replicator/LocalReplicator.cs    | 128 +------
 .../Lucene.Net.Replicator.csproj                |   2 -
 .../PerSessionDirectoryFactory.cs               |  38 --
 .../Properties/AssemblyInfo.cs                  |   1 -
 src/Lucene.Net.Replicator/ReplicationClient.cs  | 199 +----------
 src/Lucene.Net.Replicator/Replicator.cs         |  10 +-
 src/Lucene.Net.Replicator/Revision.cs           |  10 +-
 src/Lucene.Net.Replicator/RevisionFile.cs       |   5 +-
 .../SessionExpiredException.cs                  |   3 -
 src/Lucene.Net.Replicator/SessionToken.cs       |   6 +-
 .../Lucene.Net.TestFramework.csproj             |   5 +-
 .../Http/HttpReplicatorTest.cs                  |   2 -
 .../IndexAndTaxonomyReplicationClientTest.cs    |  56 +--
 .../IndexAndTaxonomyRevisionTest.cs             |   6 +-
 .../IndexReplicationClientTest.cs               | 148 +-------
 .../IndexRevisionTest.cs                        |   8 +-
 .../LocalReplicatorTest.cs                      |   6 +-
 .../ReplicatorTestCase.cs                       | 126 -------
 src/Lucene.Net/Lucene.Net.csproj                |   1 +
 src/Lucene.Net/Support/EnumerableExtensions.cs  |  63 ++++
 34 files changed, 277 insertions(+), 1631 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/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
index cdb84b6..e4345b0 100644
--- a/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.csproj
+++ b/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.csproj
@@ -63,6 +63,7 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="examples.md" />
     <None Include="packages.config" />
   </ItemGroup>
   <ItemGroup>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator.AspNetCore/examples.md
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/examples.md b/src/Lucene.Net.Replicator.AspNetCore/examples.md
new file mode 100644
index 0000000..5f28270
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/examples.md
@@ -0,0 +1 @@
+
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/ComponentWrapperInfoStream.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/ComponentWrapperInfoStream.cs b/src/Lucene.Net.Replicator/ComponentWrapperInfoStream.cs
deleted file mode 100644
index 20d1e0e..0000000
--- a/src/Lucene.Net.Replicator/ComponentWrapperInfoStream.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-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/e3305307/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
index ad869af..e1c3de5 100644
--- a/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationRequest.cs
+++ b/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationRequest.cs
@@ -1,5 +1,22 @@
 namespace Lucene.Net.Replicator.Http.Abstractions
 {
+    /*
+	 * 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>
     /// Abstraction for remote replication requests, allows easy integration into any hosting frameworks.
     /// </summary>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/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
index e46f358..1865dd4 100644
--- a/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationResponse.cs
+++ b/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationResponse.cs
@@ -2,6 +2,23 @@ using System.IO;
 
 namespace Lucene.Net.Replicator.Http.Abstractions
 {
+    /*
+	 * 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>
     /// Abstraction for remote replication response, allows easy integration into any hosting frameworks.
     /// </summary>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/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
deleted file mode 100644
index 5247f40..0000000
--- a/src/Lucene.Net.Replicator/Http/EnumerableExtensions.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-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/e3305307/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
index 17f1c3a..139fffd 100644
--- a/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
+++ b/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
@@ -1,11 +1,10 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
+using System;
 using System.IO;
 using System.Linq;
 using System.Net;
 using System.Net.Http;
 using System.Text;
+using Lucene.Net.Support;
 using Newtonsoft.Json;
 using Newtonsoft.Json.Linq;
 
@@ -42,15 +41,6 @@ namespace Lucene.Net.Replicator.Http
         /// </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>
@@ -60,15 +50,6 @@ namespace Lucene.Net.Replicator.Http
 
         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"/>.
@@ -79,19 +60,6 @@ namespace Lucene.Net.Replicator.Http
             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
@@ -99,29 +67,56 @@ namespace Lucene.Net.Replicator.Http
         /// </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)
+        /// <summary>
+        /// Creates a new <see cref="HttpClientBase"/> with the given host, port and path.
+        /// </summary>
+        /// <remarks>
+        /// The host, port and path parameters are normalized to <code>http://{host}:{port}{path}</code>, 
+        /// if path is <code>null</code> or <code>empty</code> it defaults to <code>/</code>.
+        /// <p>
+        /// A <see cref="HttpMessageHandler"/> is taken as an optional parameter as well, if this is not provided it defaults to null.
+        /// In this case the internal <see cref="HttpClient"/> will default to use a <see cref="HttpClientHandler"/>.
+        /// </p>
+        /// </remarks>
+        /// <param name="host">The host that the client should retrieve data from.</param>
+        /// <param name="port">The port to be used to connect on.</param>
+        /// <param name="path">The path to the replicator on the host.</param>
+        /// <param name="messageHandler">Optional, The HTTP handler stack to use for sending requests, defaults to null.</param>
+        protected HttpClientBase(string host, int port, string path, HttpMessageHandler messageHandler = null)
+            : this(NormalizedUrl(host, port, path), 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
+        /// <summary>
+        /// Creates a new <see cref="HttpClientBase"/> with the given url.
+        /// </summary>
+        /// <remarks>
+        /// A <see cref="HttpMessageHandler"/> is taken as an optional parameter as well, if this is not provided it defaults to null.
+        /// In this case the internal <see cref="HttpClient"/> will default to use a <see cref="HttpClientHandler"/>.
+        /// </remarks>
+        /// <param name="url">The full url, including with host, port and path.</param>
+        /// <param name="messageHandler">Optional, The HTTP handler stack to use for sending requests.</param>
+        //Note: LUCENENET Specific
+        protected HttpClientBase(string url, HttpMessageHandler messageHandler = null)
+            : this(url, new HttpClient(messageHandler ?? new HttpClientHandler()) { Timeout = TimeSpan.FromMilliseconds(DEFAULT_CONNECTION_TIMEOUT) })
+        {
+        }
 
-            Url = NormalizedUrl(host, port, path);
-            httpc = new HttpClient(messageHandler ?? new HttpClientHandler());
-            httpc.Timeout = TimeSpan.FromMilliseconds(DEFAULT_CONNECTION_TIMEOUT);
+        /// <summary>
+        /// Creates a new <see cref="HttpClientBase"/> with the given url and HttpClient.
+        /// </summary>
+        /// <remarks>
+        /// This allows full controll over how the HttpClient is created, 
+        /// prefer the <see cref="HttpClientBase(string, HttpMessageHandler)"/> over this unless you know you need the control of the HttpClient.
+        /// </remarks>
+        /// <param name="url"></param>
+        /// <param name="client">The <see cref="HttpClient"/> to use make remote http calls.</param>
+        //Note: LUCENENET Specific
+        protected HttpClientBase(string url, HttpClient client)
+        {
+            Url = url;
+            httpc = client;
+            IsDisposed = false;
         }
 
         /// <summary>
@@ -130,14 +125,6 @@ namespace Lucene.Net.Replicator.Http
         /// <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");
@@ -146,18 +133,6 @@ namespace Lucene.Net.Replicator.Http
 
         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);
@@ -170,20 +145,6 @@ namespace Lucene.Net.Replicator.Http
         /// <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);
@@ -197,46 +158,16 @@ namespace Lucene.Net.Replicator.Http
         /// <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.
+                //           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.
@@ -270,21 +201,6 @@ namespace Lucene.Net.Replicator.Http
 
         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));
@@ -301,20 +217,6 @@ namespace Lucene.Net.Replicator.Http
 
         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));
@@ -327,18 +229,6 @@ namespace Lucene.Net.Replicator.Http
 
         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
@@ -349,15 +239,8 @@ namespace Lucene.Net.Replicator.Http
         /// Internal utility: input stream of the provided response
         /// </summary>
         /// <exception cref="IOException"></exception>
-        public Stream ResponseInputStream(HttpResponseMessage response)// throws IOException
+        public Stream ResponseInputStream(HttpResponseMessage response)
         {
-            #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);
         }
 
@@ -365,109 +248,26 @@ namespace Lucene.Net.Replicator.Http
         /// Internal utility: input stream of the provided response
         /// </summary>
         /// <exception cref="IOException"></exception>
-        public Stream ResponseInputStream(HttpResponseMessage response, bool consume)// throws IOException
+        public Stream ResponseInputStream(HttpResponseMessage response, bool consume)
         {
-            #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();
         }
 
+        /// <summary>
+        /// Calls the overload <see cref="DoAction{T}(HttpResponseMessage, Boolean, Func{T})"/> passing <code>true</code> to consume.
+        /// </summary>
         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);
         }
 
+        /// <summary>
+        /// Do a specific action and validate after the action that the status is still OK, 
+        /// and if not, attempt to extract the actual server side exception. Optionally
+        /// release the response at exit, depending on <code>consume</code> parameter.
+        /// </summary>
         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
             {
@@ -483,30 +283,32 @@ namespace Lucene.Net.Replicator.Http
             }
             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:       }
-                }
+                //JAVA: Had a TryCatch here and then used a EntityUtils class to consume the response,
+                //JAVA: Unsure of what that was trying to achieve it was left out.
+                //JAVA: This also means that right now this overload does nothing more than support the signature given by the Java ver.
+                //JAVA: Overall from a .NET perspective, this method is overly suspicious.
+                VerifyStatus(response);
             }
             throw error; // should not get here
         }
 
+        /// <summary>
+        /// Disposes this <see cref="HttpClientBase"/>. 
+        /// When called with <code>true</code>, this disposes the underlying <see cref="HttpClient"/>.
+        /// </summary>
         protected virtual void Dispose(bool disposing)
         {
+            if (disposing)
+            {
+                httpc.Dispose();
+            }
             IsDisposed = true;
         }
 
+        /// <summary>
+        /// Disposes this <see cref="HttpClientBase"/>. 
+        /// This disposes the underlying <see cref="HttpClient"/>.
+        /// </summary>
         public void Dispose()
         {
             Dispose(true);

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/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
index 90df85b..ab519c3 100644
--- a/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
+++ b/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
@@ -1,9 +1,6 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
+using System;
 using System.IO;
 using System.Net.Http;
-using System.Threading.Tasks;
 using Lucene.Net.Support.IO;
 
 namespace Lucene.Net.Replicator.Http
@@ -33,54 +30,49 @@ namespace Lucene.Net.Replicator.Http
     /// </remarks>
     public class HttpReplicator : HttpClientBase, IReplicator
     {
-        public HttpReplicator(string host, int port, string path, HttpMessageHandler messageHandler) 
+        /// <summary>
+        /// Creates a new <see cref="HttpReplicator"/> with the given host, port and path.
+        /// <see cref="HttpClientBase(string, int, string, HttpMessageHandler)"/> for more details.
+        /// </summary>
+        public HttpReplicator(string host, int port, string path, HttpMessageHandler messageHandler = null)
             : 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>
+        /// Creates a new <see cref="HttpReplicator"/> with the given url.
+        /// <see cref="HttpClientBase(string, HttpMessageHandler)"/> for more details.
+        /// </summary>
+        //Note: LUCENENET Specific
+        public HttpReplicator(string url, HttpMessageHandler messageHandler = null)
+            : this(url, new HttpClient(messageHandler ?? new HttpClientHandler()) { Timeout = TimeSpan.FromMilliseconds(DEFAULT_CONNECTION_TIMEOUT) })
+        {
+        }
+
+        /// <summary>
+        /// Creates a new <see cref="HttpReplicator"/> with the given url and HttpClient.
+        /// <see cref="HttpClientBase(string, HttpClient)"/> for more details.
+        /// </summary>
+        //Note: LUCENENET Specific
+        public HttpReplicator(string url, HttpClient client)
+            : base(url, client)
+        {
         }
         
         /// <summary>
-        /// 
+        /// Not supported.
         /// </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");
         }
 
+        /// <summary>
+        /// Checks for updates at the remote host.
+        /// </summary>
         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 };
@@ -95,46 +87,21 @@ namespace Lucene.Net.Replicator.Http
             });
         }
 
+        /// <summary>
+        /// Releases a session obtained from the remote host.
+        /// </summary>
         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);
         }
 
+        /// <summary>
+        /// Obtains the given file from it's source at the remote host.
+        /// </summary>
         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,

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/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
index d004fc7..090ca4d 100644
--- a/src/Lucene.Net.Replicator/Http/ReplicationService.cs
+++ b/src/Lucene.Net.Replicator/Http/ReplicationService.cs
@@ -1,6 +1,4 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using Lucene.Net.Replicator.Http.Abstractions;
@@ -122,7 +120,6 @@ namespace Lucene.Net.Replicator.Http
             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;

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/IReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IReplicationHandler.cs b/src/Lucene.Net.Replicator/IReplicationHandler.cs
index 1976435..d3e6504 100644
--- a/src/Lucene.Net.Replicator/IReplicationHandler.cs
+++ b/src/Lucene.Net.Replicator/IReplicationHandler.cs
@@ -1,5 +1,5 @@
 //STATUS: DRAFT - 4.8.0
-using System;
+
 using System.Collections.Generic;
 using System.IO;
 using Directory = Lucene.Net.Store.Directory;

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs b/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
index a9629b8..36bf271 100644
--- a/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
+++ b/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
@@ -1,14 +1,9 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using Lucene.Net.Index;
 using Lucene.Net.Store;
-using Lucene.Net.Support;
 using Lucene.Net.Util;
 using Directory = Lucene.Net.Store.Directory;
 
@@ -32,8 +27,8 @@ namespace Lucene.Net.Replicator
 	 */
 
     /// <summary>
-    /// A {@link ReplicationHandler} for replication of an index and taxonomy pair.
-    /// See {@link IndexReplicationHandler} for more detail. This handler ensures
+    /// A <see cref="IReplicationHandler"/> for replication of an index and taxonomy pair.
+    /// See <see cref="IReplicationHandler"/> for more detail. This handler ensures
     /// that the search and taxonomy indexes are replicated in a consistent way.
     /// 
     /// <see cref="IndexReplicationHandler"/>
@@ -51,7 +46,7 @@ namespace Lucene.Net.Replicator
     public class IndexAndTaxonomyReplicationHandler : IReplicationHandler
     {
         /// <summary>
-        /// The component used to log messages to the {@link InfoStream#getDefault()default} {@link InfoStream}.
+        /// The component used to log messages to the <see cref="InfoStream"/>.
         /// </summary>
         public const string INFO_STREAM_COMPONENT = "IndexAndTaxonomyReplicationHandler";
 
@@ -72,9 +67,6 @@ namespace Lucene.Net.Replicator
         /// <summary>
         /// Constructor with the given index directory and callback to notify when the indexes were updated.
         /// </summary>
-        /// <param name="indexDirectory"></param>
-        /// <param name="taxonomyDirectory"></param>
-        /// <param name="callback"></param>
         /// <exception cref="System.IO.IOException"></exception>
         public IndexAndTaxonomyReplicationHandler(Directory indexDirectory, Directory taxonomyDirectory, Func<bool?> callback)
         {
@@ -88,7 +80,6 @@ namespace Lucene.Net.Replicator
             bool indexExists = DirectoryReader.IndexExists(indexDirectory);
             bool taxonomyExists = DirectoryReader.IndexExists(taxonomyDirectory);
 
-            //JAVA: IllegalStateException
             if (indexExists != taxonomyExists)
                 throw new InvalidOperationException(string.Format("search and taxonomy indexes must either both exist or not: index={0} taxo={1}", indexExists, taxonomyExists));
 
@@ -107,92 +98,14 @@ namespace Lucene.Net.Replicator
         }
 
         /// <summary>
-        /// 
+        /// TODO
         /// </summary>
-        /// <param name="version"></param>
-        /// <param name="revisionFiles"></param>
-        /// <param name="copiedFiles"></param>
-        /// <param name="sourceDirectory"></param>
         /// <exception cref=""></exception>
         public void RevisionReady(string version,
             IDictionary<string, IList<RevisionFile>> revisionFiles,
             IDictionary<string, IList<string>> copiedFiles,
             IDictionary<string, Directory> sourceDirectory)
         {
-            #region Java
-            //JAVA: Directory taxoClientDir = sourceDirectory.get(IndexAndTaxonomyRevision.TAXONOMY_SOURCE);
-            //JAVA: Directory indexClientDir = sourceDirectory.get(IndexAndTaxonomyRevision.INDEX_SOURCE);
-            //JAVA: List<String> taxoFiles = copiedFiles.get(IndexAndTaxonomyRevision.TAXONOMY_SOURCE);
-            //JAVA: List<String> indexFiles = copiedFiles.get(IndexAndTaxonomyRevision.INDEX_SOURCE);
-            //JAVA: String taxoSegmentsFile = IndexReplicationHandler.getSegmentsFile(taxoFiles, true);
-            //JAVA: String indexSegmentsFile = IndexReplicationHandler.getSegmentsFile(indexFiles, false);
-            //JAVA:
-            //JAVA: boolean success = false;
-            //JAVA: try {
-            //JAVA:   // copy taxonomy files before index files
-            //JAVA:   IndexReplicationHandler.copyFiles(taxoClientDir, taxoDir, taxoFiles);
-            //JAVA:   IndexReplicationHandler.copyFiles(indexClientDir, indexDir, indexFiles);
-            //JAVA:
-            //JAVA:   // fsync all copied files (except segmentsFile)
-            //JAVA:   if (!taxoFiles.isEmpty()) {
-            //JAVA:     taxoDir.sync(taxoFiles);
-            //JAVA:   }
-            //JAVA:   indexDir.sync(indexFiles);
-            //JAVA:
-            //JAVA:   // now copy and fsync segmentsFile, taxonomy first because it is ok if a
-            //JAVA:   // reader sees a more advanced taxonomy than the index.
-            //JAVA:   if (taxoSegmentsFile != null) {
-            //JAVA:     taxoClientDir.copy(taxoDir, taxoSegmentsFile, taxoSegmentsFile, IOContext.READONCE);
-            //JAVA:   }
-            //JAVA:   indexClientDir.copy(indexDir, indexSegmentsFile, indexSegmentsFile, IOContext.READONCE);
-            //JAVA:
-            //JAVA:   if (taxoSegmentsFile != null) {
-            //JAVA:     taxoDir.sync(Collections.singletonList(taxoSegmentsFile));
-            //JAVA:   }
-            //JAVA:   indexDir.sync(Collections.singletonList(indexSegmentsFile));
-            //JAVA:
-            //JAVA:   success = true;
-            //JAVA: } finally {
-            //JAVA:   if (!success) {
-            //JAVA:     taxoFiles.add(taxoSegmentsFile); // add it back so it gets deleted too
-            //JAVA:     IndexReplicationHandler.cleanupFilesOnFailure(taxoDir, taxoFiles);
-            //JAVA:     indexFiles.add(indexSegmentsFile); // add it back so it gets deleted too
-            //JAVA:     IndexReplicationHandler.cleanupFilesOnFailure(indexDir, indexFiles);
-            //JAVA:   }
-            //JAVA: }
-            //JAVA:
-            //JAVA: // all files have been successfully copied + sync'd. update the handler's state
-            //JAVA: currentRevisionFiles = revisionFiles;
-            //JAVA: currentVersion = version;
-            //JAVA:
-            //JAVA: if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
-            //JAVA:   infoStream.message(INFO_STREAM_COMPONENT, "revisionReady(): currentVersion=" + currentVersion
-            //JAVA:       + " currentRevisionFiles=" + currentRevisionFiles);
-            //JAVA: }
-            //JAVA:
-            //JAVA: // update the segments.gen file
-            //JAVA: IndexReplicationHandler.writeSegmentsGen(taxoSegmentsFile, taxoDir);
-            //JAVA: IndexReplicationHandler.writeSegmentsGen(indexSegmentsFile, indexDir);
-            //JAVA:
-            //JAVA: // Cleanup the index directory from old and unused index files.
-            //JAVA: // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
-            //JAVA: // side-effects, e.g. if it hits sudden IO errors while opening the index
-            //JAVA: // (and can end up deleting the entire index). It is not our job to protect
-            //JAVA: // against those errors, app will probably hit them elsewhere.
-            //JAVA: IndexReplicationHandler.cleanupOldIndexFiles(indexDir, indexSegmentsFile);
-            //JAVA: IndexReplicationHandler.cleanupOldIndexFiles(taxoDir, taxoSegmentsFile);
-            //JAVA:
-            //JAVA: // successfully updated the index, notify the callback that the index is
-            //JAVA: // ready.
-            //JAVA: if (callback != null) {
-            //JAVA:   try {
-            //JAVA:     callback.call();
-            //JAVA:   } catch (Exception e) {
-            //JAVA:     throw new IOException(e);
-            //JAVA:   }
-            //JAVA: } 
-            #endregion
-
             Directory taxonomyClientDirectory = sourceDirectory[IndexAndTaxonomyRevision.TAXONOMY_SOURCE];
             Directory indexClientDirectory = sourceDirectory[IndexAndTaxonomyRevision.INDEX_SOURCE];
             IList<string> taxonomyFiles = copiedFiles[IndexAndTaxonomyRevision.TAXONOMY_SOURCE];

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs b/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
index 8d32fac..890f995 100644
--- a/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
+++ b/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
@@ -2,7 +2,6 @@
 
 using System;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.Diagnostics;
 using System.Globalization;
 using System.IO;
@@ -43,15 +42,6 @@ namespace Lucene.Net.Replicator
     /// </remarks>
     public class IndexAndTaxonomyRevision : IRevision
     {
-        #region Java
-        //JAVA: private final IndexWriter indexWriter;
-        //JAVA: private final SnapshotDirectoryTaxonomyWriter taxoWriter;
-        //JAVA: private final IndexCommit indexCommit, taxoCommit;
-        //JAVA: private final SnapshotDeletionPolicy indexSDP, taxoSDP;
-        //JAVA: private final String version;
-        //JAVA: private final Map<String, List<RevisionFile>> sourceFiles;
-        #endregion
-
         public const string INDEX_SOURCE = "index";
         public const string TAXONOMY_SOURCE = "taxonomy";
 
@@ -64,36 +54,11 @@ namespace Lucene.Net.Replicator
         public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
 
         /// <summary>
-        /// 
+        /// TODO
         /// </summary>
-        /// <param name="indexWriter"></param>
-        /// <param name="taxonomyWriter"></param>
         /// <exception cref="IOException"></exception>
         public IndexAndTaxonomyRevision(IndexWriter indexWriter, SnapshotDirectoryTaxonomyWriter taxonomyWriter)
         {
-            #region Java
-            //JAVA: /**
-            //JAVA:  * Constructor over the given {@link IndexWriter}. Uses the last
-            //JAVA:  * {@link IndexCommit} found in the {@link Directory} managed by the given
-            //JAVA:  * writer.
-            //JAVA:  */
-            //JAVA: public IndexAndTaxonomyRevision(IndexWriter indexWriter, SnapshotDirectoryTaxonomyWriter taxoWriter)
-            //JAVA:     throws IOException {
-            //JAVA:   IndexDeletionPolicy delPolicy = indexWriter.getConfig().getIndexDeletionPolicy();
-            //JAVA:   if (!(delPolicy instanceof SnapshotDeletionPolicy)) {
-            //JAVA:     throw new IllegalArgumentException("IndexWriter must be created with SnapshotDeletionPolicy");
-            //JAVA:   }
-            //JAVA:   this.indexWriter = indexWriter;
-            //JAVA:   this.taxoWriter = taxoWriter;
-            //JAVA:   this.indexSDP = (SnapshotDeletionPolicy) delPolicy;
-            //JAVA:   this.taxoSDP = taxoWriter.getDeletionPolicy();
-            //JAVA:   this.indexCommit = indexSDP.snapshot();
-            //JAVA:   this.taxoCommit = taxoSDP.snapshot();
-            //JAVA:   this.version = revisionVersion(indexCommit, taxoCommit);
-            //JAVA:   this.sourceFiles = revisionFiles(indexCommit, taxoCommit);
-            //JAVA: }
-            #endregion
-
             this.indexSdp = indexWriter.Config.IndexDeletionPolicy as SnapshotDeletionPolicy;
             if (indexSdp == null)
                 throw new ArgumentException("IndexWriter must be created with SnapshotDeletionPolicy", "indexWriter");
@@ -107,35 +72,17 @@ namespace Lucene.Net.Replicator
             this.SourceFiles = RevisionFiles(indexCommit, taxonomyCommit);
         }
 
+        /// <summary>
+        /// Compares this <see cref="IndexAndTaxonomyRevision"/> to the given <see cref="version"/>.
+        /// </summary>
         public int CompareTo(string version)
         {
-            #region Java
-            //JAVA: public int compareTo(String version) {
-            //JAVA:   final String[] parts = version.split(":");
-            //JAVA:   final long indexGen = Long.parseLong(parts[0], RADIX);
-            //JAVA:   final long taxoGen = Long.parseLong(parts[1], RADIX);
-            //JAVA:   final long indexCommitGen = indexCommit.getGeneration();
-            //JAVA:   final long taxoCommitGen = taxoCommit.getGeneration();
-            //JAVA:   
-            //JAVA:   // if the index generation is not the same as this commit's generation,
-            //JAVA:   // compare by it. Otherwise, compare by the taxonomy generation.
-            //JAVA:   if (indexCommitGen < indexGen) {
-            //JAVA:     return -1;
-            //JAVA:   } else if (indexCommitGen > indexGen) {
-            //JAVA:     return 1;
-            //JAVA:   } else {
-            //JAVA:     return taxoCommitGen < taxoGen ? -1 : (taxoCommitGen > taxoGen ? 1 : 0);
-            //JAVA:   }
-            //JAVA: }
-            #endregion
-
             string[] parts = version.Split(':');
             long indexGen = long.Parse(parts[0], NumberStyles.HexNumber);
             long taxonomyGen = long.Parse(parts[1], NumberStyles.HexNumber);
             long indexCommitGen = indexCommit.Generation;
             long taxonomyCommitGen = taxonomyCommit.Generation;
 
-            //TODO: long.CompareTo(); but which goes where.
             if (indexCommitGen < indexGen)
                 return -1;
 
@@ -147,68 +94,34 @@ namespace Lucene.Net.Replicator
 
         public int CompareTo(IRevision other)
         {
-            #region Java
-            //JAVA: public int compareTo(Revision o) {
-            //JAVA:   IndexAndTaxonomyRevision other = (IndexAndTaxonomyRevision) o;
-            //JAVA:   int cmp = indexCommit.compareTo(other.indexCommit);
-            //JAVA:   return cmp != 0 ? cmp : taxoCommit.compareTo(other.taxoCommit);
-            //JAVA: }
-            #endregion
+            if (other == null)
+                throw new ArgumentNullException("other");
+
+            IndexAndTaxonomyRevision itr = other as IndexAndTaxonomyRevision;
+            if(itr == null)
+                throw new ArgumentException(string.Format("Cannot compare IndexAndTaxonomyRevision to a {0}", other.GetType()), "other");
 
-            //TODO: This breaks the contract and will fail if called with a different implementation
-            //      This is a flaw inherited from the original source...
-            //      It should at least provide a better description to the InvalidCastException
-            IndexAndTaxonomyRevision or = (IndexAndTaxonomyRevision)other;
-            int cmp = indexCommit.CompareTo(or.indexCommit);
-            return cmp != 0 ? cmp : taxonomyCommit.CompareTo(or.taxonomyCommit);
+            int cmp = indexCommit.CompareTo(itr.indexCommit);
+            return cmp != 0 ? cmp : taxonomyCommit.CompareTo(itr.taxonomyCommit);
         }
 
         /// <summary>
-        /// 
+        /// TODO
         /// </summary>
-        /// <param name="source"></param>
-        /// <param name="fileName"></param>
-        /// <returns></returns>
         /// <exception cref="IOException"></exception>
         public Stream Open(string source, string fileName)
         {
-            #region Java
-            //JAVA: public InputStream open(String source, String fileName) throws IOException {
-            //JAVA:   assert source.equals(INDEX_SOURCE) || source.equals(TAXONOMY_SOURCE) : "invalid source; expected=(" + INDEX_SOURCE
-            //JAVA:   + " or " + TAXONOMY_SOURCE + ") got=" + source;
-            //JAVA:   IndexCommit ic = source.equals(INDEX_SOURCE) ? indexCommit : taxoCommit;
-            //JAVA:   return new IndexInputStream(ic.getDirectory().openInput(fileName, IOContext.READONCE));
-            //JAVA: }
-            #endregion
-
-            Debug.Assert(source.Equals(INDEX_SOURCE) || source.Equals(TAXONOMY_SOURCE), 
-                string.Format("invalid source; expected=({0} or {1}) got={2}", INDEX_SOURCE, TAXONOMY_SOURCE, source));
+            Debug.Assert(source.Equals(INDEX_SOURCE) || source.Equals(TAXONOMY_SOURCE), string.Format("invalid source; expected=({0} or {1}) got={2}", INDEX_SOURCE, TAXONOMY_SOURCE, source));
             IndexCommit commit = source.Equals(INDEX_SOURCE) ? indexCommit : taxonomyCommit;
             return new IndexInputStream(commit.Directory.OpenInput(fileName, IOContext.READ_ONCE));
         }
 
         /// <summary>
-        /// 
+        /// TODO
         /// </summary>
         /// <exception cref="IOException"></exception>
         public void Release()
         {
-            #region Java
-            //JAVA: public void release() throws IOException {
-            //JAVA:   try {
-            //JAVA:     indexSDP.release(indexCommit);
-            //JAVA:   } finally {
-            //JAVA:     taxoSDP.release(taxoCommit);
-            //JAVA:   }
-            //JAVA:   
-            //JAVA:   try {
-            //JAVA:     indexWriter.deleteUnusedFiles();
-            //JAVA:   } finally {
-            //JAVA:     taxoWriter.getIndexWriter().deleteUnusedFiles();
-            //JAVA:   }
-            //JAVA: }
-            #endregion
-
             try
             {
                 indexSdp.Release(indexCommit);
@@ -228,7 +141,6 @@ namespace Lucene.Net.Replicator
             }
         }
 
-        //.NET NOTE: Changed doc comment as the JAVA one seems to be a bit too much copy/paste
         /// <summary>
         /// Returns a map of the revision files from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.
         /// </summary>
@@ -238,17 +150,6 @@ namespace Lucene.Net.Replicator
         /// <exception cref="IOException"></exception>
         public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit indexCommit, IndexCommit taxonomyCommit)
         {
-            #region Java
-            //JAVA: /** Returns a singleton map of the revision files from the given {@link IndexCommit}. */
-            //JAVA: public static Map<String, List<RevisionFile>> revisionFiles(IndexCommit indexCommit, IndexCommit taxoCommit)
-            //JAVA:     throws IOException {
-            //JAVA:   HashMap<String,List<RevisionFile>> files = new HashMap<>();
-            //JAVA:   files.put(INDEX_SOURCE, IndexRevision.revisionFiles(indexCommit).values().iterator().next());
-            //JAVA:   files.put(TAXONOMY_SOURCE, IndexRevision.revisionFiles(taxoCommit).values().iterator().next());
-            //JAVA:   return files;
-            //JAVA: }
-            #endregion
-
             return new Dictionary<string, IList<RevisionFile>>{
                     { INDEX_SOURCE,  IndexRevision.RevisionFiles(indexCommit).Values.First() },
                     { TAXONOMY_SOURCE,  IndexRevision.RevisionFiles(taxonomyCommit).Values.First() }
@@ -263,12 +164,6 @@ namespace Lucene.Net.Replicator
         /// <returns>a String representation of a revision's version from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.</returns>
         public static string RevisionVersion(IndexCommit indexCommit, IndexCommit taxonomyCommit)
         {
-            #region Java
-            //JAVA: public static String revisionVersion(IndexCommit indexCommit, IndexCommit taxoCommit) {
-            //JAVA:   return Long.toString(indexCommit.getGeneration(), RADIX) + ":" + Long.toString(taxoCommit.getGeneration(), RADIX);
-            //JAVA: }   
-            #endregion
-
             return string.Format("{0:X}:{1:X}", indexCommit.Generation, taxonomyCommit.Generation);
         }
 
@@ -319,7 +214,7 @@ namespace Lucene.Net.Replicator
             }
 
             /// <summary>
-            /// 
+            /// TODO
             /// </summary>
             /// <param name="directory"></param>
             /// <param name="config"></param>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexReplicationHandler.cs b/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
index 474361a..7edc95c 100644
--- a/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
+++ b/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
@@ -1,5 +1,3 @@
-//STATUS: DRAFT - 4.8.0
-
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -7,7 +5,6 @@ using System.Linq;
 using System.Text.RegularExpressions;
 using Lucene.Net.Index;
 using Lucene.Net.Store;
-using Lucene.Net.Support;
 using Lucene.Net.Util;
 using Directory = Lucene.Net.Store.Directory;
 
@@ -56,8 +53,7 @@ namespace Lucene.Net.Replicator
     public class IndexReplicationHandler : IReplicationHandler
     {
         /// <summary>
-        /// The component used to log messages to the {@link InfoStream#getDefault()
-        /// default} <seealso cref="InfoStream"/>.
+        /// The component used to log messages to the <see cref="InfoStream"/>.
         /// </summary>
         public const string INFO_STREAM_COMPONENT = "IndexReplicationHandler";
 
@@ -78,32 +74,8 @@ namespace Lucene.Net.Replicator
         /// Constructor with the given index directory and callback to notify when the
         /// indexes were updated.
         /// </summary>
-        /// <param name="indexDirectory"></param>
-        /// <param name="callback"></param>
-        // .NET NOTE: Java uses a Callable<Boolean>, however it is never uses the returned value?
         public IndexReplicationHandler(Directory indexDirectory, Func<bool?> callback)
         {
-            #region JAVA
-            //JAVA: this.callback = callback;
-            //JAVA: this.indexDir = indexDir;
-            //JAVA: currentRevisionFiles = null;
-            //JAVA: currentVersion = null;
-            //JAVA: if (DirectoryReader.indexExists(indexDir))
-            //JAVA: {
-            //JAVA:     final List<IndexCommit> commits = DirectoryReader.listCommits(indexDir);
-            //JAVA:     final IndexCommit commit = commits.get(commits.size() - 1);
-            //JAVA:     currentRevisionFiles = IndexRevision.revisionFiles(commit);
-            //JAVA:     currentVersion = IndexRevision.revisionVersion(commit);
-            //JAVA:     final InfoStream infoStream = InfoStream.getDefault();
-            //JAVA:     if (infoStream.isEnabled(INFO_STREAM_COMPONENT))
-            //JAVA:     {
-            //JAVA:         infoStream.message(INFO_STREAM_COMPONENT, "constructor(): currentVersion=" + currentVersion
-            //JAVA:                                                   + " currentRevisionFiles=" + currentRevisionFiles);
-            //JAVA:         infoStream.message(INFO_STREAM_COMPONENT, "constructor(): commit=" + commit);
-            //JAVA:     }
-            //JAVA: }
-            #endregion
-
             this.InfoStream = InfoStream.Default;
             this.callback = callback;
             this.indexDirectory = indexDirectory;
@@ -130,65 +102,6 @@ namespace Lucene.Net.Replicator
             IDictionary<string, IList<string>> copiedFiles, 
             IDictionary<string, Directory> sourceDirectory)
         {
-            #region Java
-            //JAVA: if (revisionFiles.size() > 1) {
-            //JAVA:   throw new IllegalArgumentException("this handler handles only a single source; got " + revisionFiles.keySet());
-            //JAVA: }
-            //JAVA: 
-            //JAVA: Directory clientDir = sourceDirectory.values().iterator().next();
-            //JAVA: List<String> files = copiedFiles.values().iterator().next();
-            //JAVA: String segmentsFile = getSegmentsFile(files, false);
-            //JAVA: 
-            //JAVA: boolean success = false;
-            //JAVA: try {
-            //JAVA:   // copy files from the client to index directory
-            //JAVA:   copyFiles(clientDir, indexDir, files);
-            //JAVA:   
-            //JAVA:   // fsync all copied files (except segmentsFile)
-            //JAVA:   indexDir.sync(files);
-            //JAVA:   
-            //JAVA:   // now copy and fsync segmentsFile
-            //JAVA:   clientDir.copy(indexDir, segmentsFile, segmentsFile, IOContext.READONCE);
-            //JAVA:   indexDir.sync(Collections.singletonList(segmentsFile));
-            //JAVA:   
-            //JAVA:   success = true;
-            //JAVA: } finally {
-            //JAVA:   if (!success) {
-            //JAVA:     files.add(segmentsFile); // add it back so it gets deleted too
-            //JAVA:     cleanupFilesOnFailure(indexDir, files);
-            //JAVA:   }
-            //JAVA: }
-            //JAVA:
-            //JAVA: // all files have been successfully copied + sync'd. update the handler's state
-            //JAVA: currentRevisionFiles = revisionFiles;
-            //JAVA: currentVersion = version;
-            //JAVA: 
-            //JAVA: if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
-            //JAVA:   infoStream.message(INFO_STREAM_COMPONENT, "revisionReady(): currentVersion=" + currentVersion
-            //JAVA:       + " currentRevisionFiles=" + currentRevisionFiles);
-            //JAVA: }
-            //JAVA:
-            //JAVA: // update the segments.gen file
-            //JAVA: writeSegmentsGen(segmentsFile, indexDir);
-            //JAVA: 
-            //JAVA: // Cleanup the index directory from old and unused index files.
-            //JAVA: // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
-            //JAVA: // side-effects, e.g. if it hits sudden IO errors while opening the index
-            //JAVA: // (and can end up deleting the entire index). It is not our job to protect
-            //JAVA: // against those errors, app will probably hit them elsewhere.
-            //JAVA: cleanupOldIndexFiles(indexDir, segmentsFile);
-            //JAVA:
-            //JAVA: // successfully updated the index, notify the callback that the index is
-            //JAVA: // ready.
-            //JAVA: if (callback != null) {
-            //JAVA:   try {
-            //JAVA:     callback.call();
-            //JAVA:   } catch (Exception e) {
-            //JAVA:     throw new IOException(e);
-            //JAVA:   }
-            //JAVA: }             
-            #endregion
-            //TODO: ArgumentOutOfRangeException more suited?
             if (revisionFiles.Count > 1) throw new ArgumentException(string.Format("this handler handles only a single source; got {0}", revisionFiles.Keys));
 
             Directory clientDirectory = sourceDirectory.Values.First();
@@ -246,7 +159,7 @@ namespace Lucene.Net.Replicator
             }           
         }
 
-        // .NET NOTE: Utility Method
+        //Note: LUCENENET Specific Utility Method
         private void WriteToInfoStream(params string[] messages)
         {
             if (!InfoStream.IsEnabled(INFO_STREAM_COMPONENT))
@@ -260,25 +173,9 @@ namespace Lucene.Net.Replicator
         /// Returns the last <see cref="IndexCommit"/> found in the <see cref="Directory"/>, or
         /// <code>null</code> if there are no commits.
         /// </summary>
-        /// <param name="directory"></param>
-        /// <returns></returns>
-        /// <exception cref="System.IO.IOException"></exception>
+        /// <exception cref="IOException"></exception>
         public static IndexCommit GetLastCommit(Directory directory)
         {
-            #region Java
-            //JAVA: try {
-            //JAVA:   if (DirectoryReader.indexExists(dir)) {
-            //JAVA:     List<IndexCommit> commits = DirectoryReader.listCommits(dir);
-            //JAVA:     // listCommits guarantees that we get at least one commit back, or
-            //JAVA:     // IndexNotFoundException which we handle below
-            //JAVA:     return commits.get(commits.size() - 1);
-            //JAVA:   }
-            //JAVA: } catch (IndexNotFoundException e) {
-            //JAVA:   // ignore the exception and return null
-            //JAVA: }
-            //JAVA: return null;       
-            #endregion
-
             try
             {
                 // IndexNotFoundException which we handle below
@@ -304,28 +201,8 @@ namespace Lucene.Net.Replicator
         /// that this indicates an error in the Revision implementation.
         /// </para>
         /// </summary>
-        /// <param name="files"></param>
-        /// <param name="allowEmpty"></param>
-        /// <returns></returns>
         public static string GetSegmentsFile(IList<string> files, bool allowEmpty)
         {
-            #region Java
-            //JAVA: if (files.isEmpty()) {
-            //JAVA:   if (allowEmpty) {
-            //JAVA:     return null;
-            //JAVA:   } else {
-            //JAVA:     throw new IllegalStateException("empty list of files not allowed");
-            //JAVA:   }
-            //JAVA: }
-            //JAVA: 
-            //JAVA: String segmentsFile = files.remove(files.size() - 1);
-            //JAVA: if (!segmentsFile.startsWith(IndexFileNames.SEGMENTS) || segmentsFile.equals(IndexFileNames.SEGMENTS_GEN)) {
-            //JAVA:   throw new IllegalStateException("last file to copy+sync must be segments_N but got " + segmentsFile
-            //JAVA:       + "; check your Revision implementation!");
-            //JAVA: }
-            //JAVA: return segmentsFile;    
-            #endregion
-
             if (!files.Any())
             {
                 if (allowEmpty)
@@ -348,21 +225,8 @@ namespace Lucene.Net.Replicator
         /// Cleanup the index directory by deleting all given files. Called when file
         /// copy or sync failed.
         /// </summary>
-        /// <param name="directory"></param>
-        /// <param name="files"></param>
         public static void CleanupFilesOnFailure(Directory directory, IList<string> files)
         {
-            #region Java
-            //JAVA: for (String file : files) {
-            //JAVA:     try {
-            //JAVA:         dir.deleteFile(file);
-            //JAVA:     } catch (Throwable t) {
-            //JAVA:         // suppress any exception because if we're here, it means copy
-            //JAVA:         // failed, and we must cleanup after ourselves.
-            //JAVA:     }
-            //JAVA: }
-            #endregion
-
             foreach (string file in files)
             {
                 try
@@ -379,35 +243,6 @@ namespace Lucene.Net.Replicator
 
         public static void CleanupOldIndexFiles(Directory directory, string segmentsFile)
         {
-            #region Java
-            //JAVA: try {
-            //JAVA:   IndexCommit commit = getLastCommit(dir);
-            //JAVA:   // commit == null means weird IO errors occurred, ignore them
-            //JAVA:   // if there were any IO errors reading the expected commit point (i.e.
-            //JAVA:   // segments files mismatch), then ignore that commit either.
-            //JAVA:   if (commit != null && commit.getSegmentsFileName().equals(segmentsFile)) {
-            //JAVA:     Set<String> commitFiles = new HashSet<>();
-            //JAVA:     commitFiles.addAll(commit.getFileNames());
-            //JAVA:     commitFiles.add(IndexFileNames.SEGMENTS_GEN);
-            //JAVA:     Matcher matcher = IndexFileNames.CODEC_FILE_PATTERN.matcher("");
-            //JAVA:     for (String file : dir.listAll()) {
-            //JAVA:       if (!commitFiles.contains(file)
-            //JAVA:           && (matcher.reset(file).matches() || file.startsWith(IndexFileNames.SEGMENTS))) {
-            //JAVA:         try {
-            //JAVA:           dir.deleteFile(file);
-            //JAVA:         } catch (Throwable t) {
-            //JAVA:           // suppress, it's just a best effort
-            //JAVA:         }
-            //JAVA:       }
-            //JAVA:     }
-            //JAVA:   }
-            //JAVA: } catch (Throwable t) {
-            //JAVA:   // ignore any errors that happens during this state and only log it. this
-            //JAVA:   // cleanup will have a chance to succeed the next time we get a new
-            //JAVA:   // revision.
-            //JAVA: }             
-            #endregion
-
             try
             {
                 IndexCommit commit = GetLastCommit(directory);
@@ -445,22 +280,11 @@ namespace Lucene.Net.Replicator
         }
 
         /// <summary>
-        /// 
+        /// Copies the provided list of files from the <see cref="source"/> <see cref="Directory"/> to the <see cref="target"/> <see cref="Directory"/>.
         /// </summary>
-        /// <param name="source"></param>
-        /// <param name="target"></param>
-        /// <param name="files"></param>
-        /// <exception cref="System.IO.IOException"></exception>
+        /// <exception cref="IOException"></exception>
         public static void CopyFiles(Directory source, Directory target, IList<string> files)
         {
-            #region Java
-            //JAVA: if (!source.equals(target)) {
-            //JAVA:     for (String file : files) {
-            //JAVA:         source.copy(target, file, file, IOContext.READONCE);
-            //JAVA:     }
-            //JAVA: }
-            #endregion
-
             if (source.Equals(target))
                 return;
 
@@ -473,24 +297,8 @@ namespace Lucene.Net.Replicator
         /// the generation from the given <code>segmentsFile</code>. If it is <code>null</code>,
         /// this method deletes segments.gen from the directory.
         /// </summary>
-        /// <param name="segmentsFile"></param>
-        /// <param name="directory"></param>
         public static void WriteSegmentsGen(string segmentsFile, Directory directory)
         {
-            #region Java
-            //JAVA: public static void writeSegmentsGen(String segmentsFile, Directory dir) {
-            //JAVA:   if (segmentsFile != null) {
-            //JAVA:     SegmentInfos.writeSegmentsGen(dir, SegmentInfos.generationFromSegmentsFileName(segmentsFile));
-            //JAVA:   } else {
-            //JAVA:     try {
-            //JAVA:       dir.deleteFile(IndexFileNames.SEGMENTS_GEN);
-            //JAVA:     } catch (Throwable t) {
-            //JAVA:       // suppress any errors while deleting this file.
-            //JAVA:     }
-            //JAVA:   }
-            //JAVA: }
-            #endregion
-
             if (segmentsFile != null)
             {
                 SegmentInfos.WriteSegmentsGen(directory, SegmentInfos.GenerationFromSegmentsFileName(segmentsFile));

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/IndexRevision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexRevision.cs b/src/Lucene.Net.Replicator/IndexRevision.cs
index 930b120..5708bf1 100644
--- a/src/Lucene.Net.Replicator/IndexRevision.cs
+++ b/src/Lucene.Net.Replicator/IndexRevision.cs
@@ -3,7 +3,6 @@
 using System;
 using System.IO;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.Diagnostics;
 using System.Globalization;
 using System.Linq;
@@ -49,16 +48,6 @@ namespace Lucene.Net.Replicator
     /// </remarks>
     public class IndexRevision : IRevision
     {
-        #region Java
-        //JAVA: private static final int RADIX = 16;
-        //JAVA: private static final String SOURCE = "index";
-        //JAVA: private final IndexWriter writer;
-        //JAVA: private final IndexCommit commit;
-        //JAVA: private final SnapshotDeletionPolicy sdp;
-        //JAVA: private final String version;
-        //JAVA: private final Map<String, List<RevisionFile>> sourceFiles;
-        #endregion
-
         private const string SOURCE = "index";
 
         private readonly IndexWriter writer;
@@ -70,20 +59,6 @@ namespace Lucene.Net.Replicator
 
         public IndexRevision(IndexWriter writer)
         {
-            #region Java
-            //JAVA: public IndexRevision(IndexWriter writer) throws IOException {
-            //JAVA:   IndexDeletionPolicy delPolicy = writer.getConfig().getIndexDeletionPolicy();
-            //JAVA:   if (!(delPolicy instanceof SnapshotDeletionPolicy)) {
-            //JAVA:     throw new IllegalArgumentException("IndexWriter must be created with SnapshotDeletionPolicy");
-            //JAVA:   }
-            //JAVA:   this.writer = writer;
-            //JAVA:   this.sdp = (SnapshotDeletionPolicy) delPolicy;
-            //JAVA:   this.commit = sdp.snapshot();
-            //JAVA:   this.version = revisionVersion(commit);
-            //JAVA:   this.sourceFiles = revisionFiles(commit);
-            //JAVA: }              
-            #endregion
-
             sdp = writer.Config.IndexDeletionPolicy as SnapshotDeletionPolicy;
             if (sdp == null)
                 throw new ArgumentException("IndexWriter must be created with SnapshotDeletionPolicy", "writer");
@@ -96,11 +71,6 @@ namespace Lucene.Net.Replicator
 
         public int CompareTo(string version)
         {
-            #region Java
-            //JAVA: long gen = Long.parseLong(version, RADIX);
-            //JAVA: long commitGen = commit.getGeneration();
-            //JAVA: return commitGen < gen ? -1 : (commitGen > gen ? 1 : 0);
-            #endregion
             long gen = long.Parse(version, NumberStyles.HexNumber);
             long commitGen = commit.Generation;
             //TODO: long.CompareTo(); but which goes where.
@@ -109,10 +79,6 @@ namespace Lucene.Net.Replicator
 
         public int CompareTo(IRevision other)
         {
-            #region Java
-            //JAVA: IndexRevision other = (IndexRevision)o;
-            //JAVA: return commit.compareTo(other.commit);
-            #endregion
             //TODO: This breaks the contract and will fail if called with a different implementation
             //      This is a flaw inherited from the original source...
             //      It should at least provide a better description to the InvalidCastException
@@ -140,36 +106,12 @@ namespace Lucene.Net.Replicator
         // returns a RevisionFile with some metadata
         private static RevisionFile CreateRevisionFile(string fileName, Directory directory)
         {
-            #region Java
-            //JAVA: private static RevisionFile newRevisionFile(String file, Directory dir) throws IOException {
-            //JAVA:   RevisionFile revFile = new RevisionFile(file);
-            //JAVA:   revFile.size = dir.fileLength(file);
-            //JAVA:   return revFile;
-            //JAVA: }             
-            #endregion
             return new RevisionFile(fileName, directory.FileLength(fileName));
         }
 
         /** Returns a singleton map of the revision files from the given {@link IndexCommit}. */
         public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit commit)
         {
-            #region Java
-            //JAVA: public static Map<String,List<RevisionFile>> revisionFiles(IndexCommit commit) throws IOException {
-            //JAVA:   Collection<String> commitFiles = commit.getFileNames();
-            //JAVA:   List<RevisionFile> revisionFiles = new ArrayList<>(commitFiles.size());
-            //JAVA:   String segmentsFile = commit.getSegmentsFileName();
-            //JAVA:   Directory dir = commit.getDirectory();
-            //JAVA:   
-            //JAVA:   for (String file : commitFiles) {
-            //JAVA:     if (!file.equals(segmentsFile)) {
-            //JAVA:       revisionFiles.add(newRevisionFile(file, dir));
-            //JAVA:     }
-            //JAVA:   }
-            //JAVA:   revisionFiles.add(newRevisionFile(segmentsFile, dir)); // segments_N must be last
-            //JAVA:   return Collections.singletonMap(SOURCE, revisionFiles);
-            //JAVA: }
-            #endregion
-
             List<RevisionFile> revisionFiles = commit.FileNames
                 .Where(file => !string.Equals(file, commit.SegmentsFileName))
                 .Select(file => CreateRevisionFile(file, commit.Directory))
@@ -189,11 +131,6 @@ namespace Lucene.Net.Replicator
         /// <returns></returns>
         public static string RevisionVersion(IndexCommit commit)
         {
-            #region Java
-            //JAVA: public static String revisionVersion(IndexCommit commit) {
-            //JAVA:   return Long.toString(commit.getGeneration(), RADIX);
-            //JAVA: }  
-            #endregion           
             return commit.Generation.ToString("X");
         }
     }


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

Posted by ni...@apache.org.
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


[06/20] lucenenet git commit: LUCENENET-565: Porting of Lucene Replicator, cleanup stage 1

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/LocalReplicator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/LocalReplicator.cs b/src/Lucene.Net.Replicator/LocalReplicator.cs
index ae3a3a9..c32f8b7 100644
--- a/src/Lucene.Net.Replicator/LocalReplicator.cs
+++ b/src/Lucene.Net.Replicator/LocalReplicator.cs
@@ -2,10 +2,10 @@
 
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
-using Lucene.Net.Search;
 using Lucene.Net.Support;
 
 namespace Lucene.Net.Replicator
@@ -76,36 +76,6 @@ namespace Lucene.Net.Replicator
 
         public void Publish(IRevision revision)
         {
-            #region Java
-            //JAVA: public synchronized void publish(Revision revision) throws IOException {
-            //JAVA:   ensureOpen();
-            //JAVA:   if (currentRevision != null) {
-            //JAVA:     int compare = revision.compareTo(currentRevision.revision);
-            //JAVA:     if (compare == 0) {
-            //JAVA:       // same revision published again, ignore but release it
-            //JAVA:       revision.release();
-            //JAVA:       return;
-            //JAVA:     }
-            //JAVA:
-            //JAVA:     if (compare < 0) {
-            //JAVA:       revision.release();
-            //JAVA:       throw new IllegalArgumentException("Cannot publish an older revision: rev=" + revision + " current="
-            //JAVA:           + currentRevision);
-            //JAVA:     } 
-            //JAVA:   }
-            //JAVA:
-            //JAVA:   // swap revisions
-            //JAVA:   final RefCountedRevision oldRevision = currentRevision;
-            //JAVA:   currentRevision = new RefCountedRevision(revision);
-            //JAVA:   if (oldRevision != null) {
-            //JAVA:     oldRevision.decRef();
-            //JAVA:   }
-            //JAVA:
-            //JAVA:   // check for expired sessions
-            //JAVA:   checkExpiredSessions();
-            //JAVA: } 
-            #endregion
-
             lock (padlock)
             {
                 EnsureOpen();
@@ -137,34 +107,11 @@ namespace Lucene.Net.Replicator
         }
 
         /// <summary>
-        /// 
+        /// TODO
         /// </summary>
-        /// <param name="currentVersion"></param>
         /// <returns></returns>
         public SessionToken CheckForUpdate(string currentVersion)
         {
-            #region Java
-            //JAVA: public synchronized SessionToken checkForUpdate(String currentVersion) {
-            //JAVA:   ensureOpen();
-            //JAVA:   if (currentRevision == null) { // no published revisions yet
-            //JAVA:     return null;
-            //JAVA:   }
-            //JAVA:
-            //JAVA:   if (currentVersion != null && currentRevision.revision.compareTo(currentVersion) <= 0) {
-            //JAVA:     // currentVersion is newer or equal to latest published revision
-            //JAVA:     return null;
-            //JAVA:   }
-            //JAVA:
-            //JAVA:   // currentVersion is either null or older than latest published revision
-            //JAVA:   currentRevision.incRef();
-            //JAVA:   final String sessionID = Integer.toString(sessionToken.incrementAndGet());
-            //JAVA:   final SessionToken sessionToken = new SessionToken(sessionID, currentRevision.revision);
-            //JAVA:   final ReplicationSession timedSessionToken = new ReplicationSession(sessionToken, currentRevision);
-            //JAVA:   sessions.put(sessionID, timedSessionToken);
-            //JAVA:   return sessionToken;
-            //JAVA: } 
-            #endregion
-
             lock (padlock)
             {
                 EnsureOpen();
@@ -186,9 +133,8 @@ namespace Lucene.Net.Replicator
         }
 
         /// <summary>
-        /// 
+        /// TODO
         /// </summary>
-        /// <param name="sessionId"></param>
         /// <exception cref="InvalidOperationException"></exception>
         public void Release(string sessionId)
         {
@@ -199,26 +145,11 @@ namespace Lucene.Net.Replicator
             }
         }
 
+        /// <summary>
+        /// TODO
+        /// </summary>
         public Stream ObtainFile(string sessionId, string source, string fileName)
         {
-            #region Java
-            //JAVA: public synchronized InputStream obtainFile(String sessionID, String source, String fileName) throws IOException {
-            //JAVA:   ensureOpen();
-            //JAVA:   ReplicationSession session = sessions.get(sessionID);
-            //JAVA:   if (session != null && session.isExpired(expirationThresholdMilllis)) {
-            //JAVA:     releaseSession(sessionID);
-            //JAVA:     session = null;
-            //JAVA:   }
-            //JAVA:   // session either previously expired, or we just expired it
-            //JAVA:   if (session == null) {
-            //JAVA:     throw new SessionExpiredException("session (" + sessionID + ") expired while obtaining file: source=" + source
-            //JAVA:         + " file=" + fileName);
-            //JAVA:   }
-            //JAVA:   sessions.get(sessionID).markAccessed();
-            //JAVA:   return session.revision.revision.open(source, fileName);
-            //JAVA: }
-            #endregion
-
             lock (padlock)
             {
                 EnsureOpen();
@@ -240,21 +171,11 @@ namespace Lucene.Net.Replicator
 
         }
 
+        /// <summary>
+        /// TODO
+        /// </summary>
         public void Dispose()
         {
-            #region Java
-            //JAVA: public synchronized void close() throws IOException {
-            //JAVA:   if (!closed) {
-            //JAVA:     // release all managed revisions
-            //JAVA:     for (ReplicationSession session : sessions.values()) {
-            //JAVA:       session.revision.decRef();
-            //JAVA:     }
-            //JAVA:     sessions.clear();
-            //JAVA:     closed = true;
-            //JAVA:   }
-            //JAVA: }
-            #endregion
-
             if (disposed)
                 return;
 
@@ -270,21 +191,6 @@ namespace Lucene.Net.Replicator
         /// <exception cref="InvalidOperationException"></exception>
         private void CheckExpiredSessions()
         {
-            #region Java
-            //JAVA: private void checkExpiredSessions() throws IOException {
-            //JAVA:   // make a "to-delete" list so we don't risk deleting from the map while iterating it
-            //JAVA:   final ArrayList<ReplicationSession> toExpire = new ArrayList<>();
-            //JAVA:   for (ReplicationSession token : sessions.values()) {
-            //JAVA:     if (token.isExpired(expirationThresholdMilllis)) {
-            //JAVA:       toExpire.add(token);
-            //JAVA:     }
-            //JAVA:   }
-            //JAVA:   for (ReplicationSession token : toExpire) {
-            //JAVA:     releaseSession(token.session.id);
-            //JAVA:   }
-            //JAVA: }  
-            #endregion
-            
             // .NET NOTE: .ToArray() so we don't modify a collection we are enumerating...
             //            I am wondering if it would be overall more practical to switch to a concurrent dictionary...
             foreach (ReplicationSession token in sessions.Values.Where(token => token.IsExpired(ExpirationThreshold)).ToArray())
@@ -296,17 +202,6 @@ namespace Lucene.Net.Replicator
         /// <exception cref="InvalidOperationException"></exception>
         private void ReleaseSession(string sessionId)
         {
-            #region Java
-            //JAVA: private void releaseSession(String sessionID) throws IOException {
-            //JAVA:   ReplicationSession session = sessions.remove(sessionID);
-            //JAVA:   // if we're called concurrently by close() and release(), could be that one
-            //JAVA:   // thread beats the other to release the session.
-            //JAVA:   if (session != null) {
-            //JAVA:     session.revision.decRef();
-            //JAVA:   }
-            //JAVA: }          
-            #endregion
-
             ReplicationSession session;
             // if we're called concurrently by close() and release(), could be that one
             // thread beats the other to release the session.
@@ -349,7 +244,6 @@ namespace Lucene.Net.Replicator
             {
                 if (refCount.Get() <= 0)
                 {
-                    //JAVA: throw new IllegalStateException("this revision is already released");
                     throw new InvalidOperationException("this revision is already released");
                 }
 
@@ -373,7 +267,6 @@ namespace Lucene.Net.Replicator
                 }
                 else if (rc < 0)
                 {
-                    //JAVA: throw new IllegalStateException("too many decRef calls: refCount is " + rc + " after decrement");
                     throw new InvalidOperationException(string.Format("too many decRef calls: refCount is {0} after decrement", rc));
                 }
             }
@@ -395,19 +288,16 @@ namespace Lucene.Net.Replicator
             {
                 Session = session;
                 Revision = revision;
-                //JAVA: lastAccessTime = System.currentTimeMillis();
                 lastAccessTime = Stopwatch.GetTimestamp();
             }
 
             public bool IsExpired(long expirationThreshold)
             {
-                //JAVA: return lastAccessTime < (System.currentTimeMillis() - expirationThreshold);
                 return lastAccessTime < Stopwatch.GetTimestamp() - expirationThreshold * Stopwatch.Frequency / 1000;
             }
 
             public void MarkAccessed()
             {
-                //JAVA: lastAccessTime = System.currentTimeMillis();
                 lastAccessTime = Stopwatch.GetTimestamp();
             }
         }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
index 9481bd4..1b0b90f 100644
--- a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
+++ b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
@@ -64,8 +64,6 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="ComponentWrapperInfoStream.cs" />
-    <Compile Include="Http\EnumerableExtensions.cs" />
     <Compile Include="Http\HttpClientBase.cs" />
     <Compile Include="Http\HttpReplicator.cs" />
     <Compile Include="Http\Abstractions\IReplicationRequest.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs b/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
index e7f1d80..e65c8cb 100644
--- a/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
+++ b/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
@@ -1,5 +1,3 @@
-//STATUS: DRAFT - 4.8.0
-
 using System;
 using System.IO;
 using Lucene.Net.Store;
@@ -34,9 +32,6 @@ namespace Lucene.Net.Replicator
     /// </remarks>
     public class PerSessionDirectoryFactory : ISourceDirectoryFactory
     {
-        #region Java
-        //JAVA: private final File workDir;
-        #endregion
         private readonly string workingDirectory;
 
         /** Constructor with the given sources mapping. */
@@ -47,20 +42,6 @@ namespace Lucene.Net.Replicator
 
         public Directory GetDirectory(string sessionId, string source)
         {
-            #region Java
-            //JAVA: public Directory getDirectory(String sessionID, String source) throws IOException {
-            //JAVA:   File sessionDir = new File(workDir, sessionID);
-            //JAVA:   if (!sessionDir.exists() && !sessionDir.mkdirs()) {
-            //JAVA:     throw new IOException("failed to create session directory " + sessionDir);
-            //JAVA:   }
-            //JAVA:   File sourceDir = new File(sessionDir, source);
-            //JAVA:   if (!sourceDir.mkdirs()) {
-            //JAVA:     throw new IOException("failed to create source directory " + sourceDir);
-            //JAVA:   }
-            //JAVA:   return FSDirectory.open(sourceDir);
-            //JAVA: }
-            #endregion
-
             string sourceDirectory = Path.Combine(workingDirectory, sessionId, source);
             System.IO.Directory.CreateDirectory(sourceDirectory);
             return FSDirectory.Open(sourceDirectory);
@@ -70,27 +51,8 @@ namespace Lucene.Net.Replicator
         {
             if (string.IsNullOrEmpty(sessionId)) throw new ArgumentException("sessionID cannot be empty", "sessionId");
 
-            #region Java
-            //JAVA: rm(new File(workDir, sessionID));
-            #endregion
-
             string sessionDirectory = Path.Combine(workingDirectory, sessionId);
             System.IO.Directory.Delete(sessionDirectory, true);
         }
-
-        #region Java
-        //JAVA: private void rm(File file) throws IOException {
-        //JAVA:   if (file.isDirectory()) {
-        //JAVA:     for (File f : file.listFiles()) {
-        //JAVA:       rm(f);
-        //JAVA:     }
-        //JAVA:   }
-        //JAVA:   
-        //JAVA:   // This should be either an empty directory, or a file
-        //JAVA:   if (!file.delete() && file.exists()) {
-        //JAVA:     throw new IOException("failed to delete " + file);
-        //JAVA:   }
-        //JAVA: }
-        #endregion
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs b/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
index 898ca18..6cc1e58 100644
--- a/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
+++ b/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
@@ -1,6 +1,5 @@
 using System;
 using System.Reflection;
-using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
 // General Information about an assembly is controlled through the following

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/ReplicationClient.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/ReplicationClient.cs b/src/Lucene.Net.Replicator/ReplicationClient.cs
index 63837c9..14c1c2b 100644
--- a/src/Lucene.Net.Replicator/ReplicationClient.cs
+++ b/src/Lucene.Net.Replicator/ReplicationClient.cs
@@ -1,14 +1,11 @@
-//STATUS: DRAFT - 4.8.0
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
-using System.Text;
 using System.Threading;
 using Lucene.Net.Store;
-using Lucene.Net.Support;
 using Lucene.Net.Support.Threading;
 using Lucene.Net.Util;
 using Directory = Lucene.Net.Store.Directory;
@@ -45,14 +42,16 @@ namespace Lucene.Net.Replicator
     /// <remarks>
     /// Lucene.Experimental
     /// </remarks>
-    public partial class ReplicationClient : IDisposable
+    public class ReplicationClient : IDisposable
     {
         /// <summary>
         /// The component name to use with <see cref="Util.InfoStream.IsEnabled"/>
         /// </summary>
         public const string INFO_STREAM_COMPONENT = "ReplicationThread";
 
-        /// <summary> Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages. </summary>
+        /// <summary> 
+        /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages. 
+        /// </summary>
         public InfoStream InfoStream
         {
             get { return infoStream; }
@@ -86,84 +85,6 @@ namespace Lucene.Net.Replicator
         /// <exception cref="IOException"></exception>
         private void DoUpdate()
         {
-            #region Java
-            //JAVA: private void doUpdate() throws IOException {
-            //JAVA:   SessionToken session = null;
-            //JAVA:   final Map<String,Directory> sourceDirectory = new HashMap<>();
-            //JAVA:   final Map<String,List<String>> copiedFiles = new HashMap<>();
-            //JAVA:   boolean notify = false;
-            //JAVA:   try {
-            //JAVA:     final String version = handler.currentVersion();
-            //JAVA:     session = replicator.checkForUpdate(version);
-            //JAVA:     if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
-            //JAVA:       infoStream.message(INFO_STREAM_COMPONENT, "doUpdate(): handlerVersion=" + version + " session=" + session);
-            //JAVA:     }
-            //JAVA:     if (session == null) {
-            //JAVA:       // already up to date
-            //JAVA:       return;
-            //JAVA:     }
-            //JAVA:     Map<String,List<RevisionFile>> requiredFiles = requiredFiles(session.sourceFiles);
-            //JAVA:     if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
-            //JAVA:       infoStream.message(INFO_STREAM_COMPONENT, "doUpdate(): requiredFiles=" + requiredFiles);
-            //JAVA:     }
-            //JAVA:     for (Entry<String,List<RevisionFile>> e : requiredFiles.entrySet()) {
-            //JAVA:       String source = e.getKey();
-            //JAVA:       Directory dir = factory.getDirectory(session.id, source);
-            //JAVA:       sourceDirectory.put(source, dir);
-            //JAVA:       List<String> cpFiles = new ArrayList<>();
-            //JAVA:       copiedFiles.put(source, cpFiles);
-            //JAVA:       for (RevisionFile file : e.getValue()) {
-            //JAVA:         if (closed) {
-            //JAVA:           // if we're closed, abort file copy
-            //JAVA:           if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
-            //JAVA:             infoStream.message(INFO_STREAM_COMPONENT, "doUpdate(): detected client was closed); abort file copy");
-            //JAVA:           }
-            //JAVA:           return;
-            //JAVA:         }
-            //JAVA:         InputStream in = null;
-            //JAVA:         IndexOutput out = null;
-            //JAVA:         try {
-            //JAVA:           in = replicator.obtainFile(session.id, source, file.fileName);
-            //JAVA:           out = dir.createOutput(file.fileName, IOContext.DEFAULT);
-            //JAVA:           copyBytes(out, in);
-            //JAVA:           cpFiles.add(file.fileName);
-            //JAVA:           // TODO add some validation, on size / checksum
-            //JAVA:         } finally {
-            //JAVA:           IOUtils.close(in, out);
-            //JAVA:         }
-            //JAVA:       }
-            //JAVA:     }
-            //JAVA:     // only notify if all required files were successfully obtained.
-            //JAVA:     notify = true;
-            //JAVA:   } finally {
-            //JAVA:     if (session != null) {
-            //JAVA:       try {
-            //JAVA:         replicator.release(session.id);
-            //JAVA:       } finally {
-            //JAVA:         if (!notify) { // cleanup after ourselves
-            //JAVA:           IOUtils.close(sourceDirectory.values());
-            //JAVA:           factory.cleanupSession(session.id);
-            //JAVA:         }
-            //JAVA:       }
-            //JAVA:     }
-            //JAVA:   }
-            //JAVA:   
-            //JAVA:   // notify outside the try-finally above, so the session is released sooner.
-            //JAVA:   // the handler may take time to finish acting on the copied files, but the
-            //JAVA:   // session itself is no longer needed.
-            //JAVA:   try {
-            //JAVA:     if (notify && !closed ) { // no use to notify if we are closed already
-            //JAVA:       handler.revisionReady(session.version, session.sourceFiles, copiedFiles, sourceDirectory);
-            //JAVA:     }
-            //JAVA:   } finally {
-            //JAVA:     IOUtils.close(sourceDirectory.values());
-            //JAVA:     if (session != null) {
-            //JAVA:       factory.cleanupSession(session.id);
-            //JAVA:     }
-            //JAVA:   }
-            //JAVA: }
-            #endregion
-
             SessionToken session = null;
             Dictionary<string, Directory> sourceDirectory = new Dictionary<string, Directory>();
             Dictionary<string, IList<string>> copiedFiles = new Dictionary<string, IList<string>>();
@@ -285,37 +206,6 @@ namespace Lucene.Net.Replicator
         /// <returns></returns>
         private IDictionary<string, IList<RevisionFile>> RequiredFiles(IDictionary<string, IList<RevisionFile>> newRevisionFiles)
         {
-            #region Java
-            //JAVA: protected Map<String,List<RevisionFile>> requiredFiles(Map<String,List<RevisionFile>> newRevisionFiles) {
-            //JAVA:   Map<String,List<RevisionFile>> handlerRevisionFiles = handler.currentRevisionFiles();
-            //JAVA:   if (handlerRevisionFiles == null) {
-            //JAVA:     return newRevisionFiles;
-            //JAVA:   }
-            //JAVA:   
-            //JAVA:   Map<String,List<RevisionFile>> requiredFiles = new HashMap<>();
-            //JAVA:   for (Entry<String,List<RevisionFile>> e : handlerRevisionFiles.entrySet()) {
-            //JAVA:     // put the handler files in a Set, for faster contains() checks later
-            //JAVA:     Set<String> handlerFiles = new HashSet<>();
-            //JAVA:     for (RevisionFile file : e.getValue()) {
-            //JAVA:       handlerFiles.add(file.fileName);
-            //JAVA:     }
-            //JAVA:     
-            //JAVA:     // make sure to preserve revisionFiles order
-            //JAVA:     ArrayList<RevisionFile> res = new ArrayList<>();
-            //JAVA:     String source = e.getKey();
-            //JAVA:     assert newRevisionFiles.containsKey(source) : "source not found in newRevisionFiles: " + newRevisionFiles;
-            //JAVA:     for (RevisionFile file : newRevisionFiles.get(source)) {
-            //JAVA:       if (!handlerFiles.contains(file.fileName)) {
-            //JAVA:         res.add(file);
-            //JAVA:       }
-            //JAVA:     }
-            //JAVA:     requiredFiles.put(source, res);
-            //JAVA:   }
-            //JAVA:   
-            //JAVA:   return requiredFiles;
-            //JAVA: }
-            #endregion
-
             IDictionary<string, IList<RevisionFile>> handlerRevisionFiles = handler.CurrentRevisionFiles;
             if (handlerRevisionFiles == null)
                 return newRevisionFiles;
@@ -346,22 +236,6 @@ namespace Lucene.Net.Replicator
         /// <exception cref="InvalidOperationException"> if the thread has already been started </exception>
         public void StartUpdateThread(long intervalMillis, string threadName)
         {
-            #region Java
-            //JAVA: public synchronized void startUpdateThread(long intervalMillis, String threadName) {
-            //JAVA:   ensureOpen();
-            //JAVA:   if (updateThread != null && updateThread.isAlive()) {
-            //JAVA:     throw new IllegalStateException(
-            //JAVA:         "cannot start an update thread when one is running, must first call 'stopUpdateThread()'");
-            //JAVA:   }
-            //JAVA:   threadName = threadName == null ? INFO_STREAM_COMPONENT : "ReplicationThread-" + threadName;
-            //JAVA:   updateThread = new ReplicationThread(intervalMillis);
-            //JAVA:   updateThread.setName(threadName);
-            //JAVA:   updateThread.start();
-            //JAVA:   // we rely on isAlive to return true in isUpdateThreadAlive, assert to be on the safe side
-            //JAVA:   assert updateThread.isAlive() : "updateThread started but not alive?";
-            //JAVA: }
-            #endregion
-
             EnsureOpen();
             if (updateThread != null && updateThread.IsAlive)
                 throw new InvalidOperationException("cannot start an update thread when one is running, must first call 'stopUpdateThread()'");
@@ -379,24 +253,6 @@ namespace Lucene.Net.Replicator
         /// </summary>
         public void StopUpdateThread()
         {
-            #region Java
-            //JAVA: public synchronized void stopUpdateThread() {
-            //JAVA:   if (updateThread != null) {
-            //JAVA:     // this will trigger the thread to terminate if it awaits the lock.
-            //JAVA:     // otherwise, if it's in the middle of replication, we wait for it to
-            //JAVA:     // stop.
-            //JAVA:     updateThread.stop.countDown();
-            //JAVA:     try {
-            //JAVA:       updateThread.join();
-            //JAVA:     } catch (InterruptedException e) {
-            //JAVA:       Thread.currentThread().interrupt();
-            //JAVA:       throw new ThreadInterruptedException(e);
-            //JAVA:     }
-            //JAVA:     updateThread = null;
-            //JAVA:   }
-            //JAVA: }
-            #endregion
-
             // this will trigger the thread to terminate if it awaits the lock.
             // otherwise, if it's in the middle of replication, we wait for it to
             // stop.
@@ -496,53 +352,6 @@ namespace Lucene.Net.Replicator
         //Note: LUCENENET specific, .NET does not work with Threads in the same way as Java does, so we mimic the same behavior using the ThreadPool instead.
         private class ReplicationThread
         {
-            #region Java
-            //JAVA: private class ReplicationThread extends Thread {
-            //JAVA:   private final long interval;
-            //JAVA:   // client uses this to stop us
-            //JAVA:   final CountDownLatch stop = new CountDownLatch(1);
-            //JAVA:   
-            //JAVA:   public ReplicationThread(long interval) {
-            //JAVA:     this.interval = interval;
-            //JAVA:   }
-            //JAVA:   
-            //JAVA:   @SuppressWarnings("synthetic-access")
-            //JAVA:   @Override
-            //JAVA:   public void run() {
-            //JAVA:     while (true) {
-            //JAVA:       long time = System.currentTimeMillis();
-            //JAVA:       updateLock.lock();
-            //JAVA:       try {
-            //JAVA:         doUpdate();
-            //JAVA:       } catch (Throwable t) {
-            //JAVA:         handleUpdateException(t);
-            //JAVA:       } finally {
-            //JAVA:         updateLock.unlock();
-            //JAVA:       }
-            //JAVA:       time = System.currentTimeMillis() - time;
-            //JAVA:       
-            //JAVA:       // adjust timeout to compensate the time spent doing the replication.
-            //JAVA:       final long timeout = interval - time;
-            //JAVA:       if (timeout > 0) {
-            //JAVA:         try {
-            //JAVA:           // this will return immediately if we were ordered to stop (count=0)
-            //JAVA:           // or the timeout has elapsed. if it returns true, it means count=0,
-            //JAVA:           // so terminate.
-            //JAVA:           if (stop.await(timeout, TimeUnit.MILLISECONDS)) {
-            //JAVA:             return;
-            //JAVA:           }
-            //JAVA:         } catch (InterruptedException e) {
-            //JAVA:           // if we were interruted, somebody wants to terminate us, so just
-            //JAVA:           // throw the exception further.
-            //JAVA:           Thread.currentThread().interrupt();
-            //JAVA:           throw new ThreadInterruptedException(e);
-            //JAVA:         }
-            //JAVA:       }
-            //JAVA:     }
-            //JAVA:   }
-            //JAVA: }
-            #endregion
-
             private readonly Action doUpdate;
             private readonly Action<Exception> handleException;
             private readonly ReentrantLock @lock;

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/Replicator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Replicator.cs b/src/Lucene.Net.Replicator/Replicator.cs
index af7ef51..28de0d3 100644
--- a/src/Lucene.Net.Replicator/Replicator.cs
+++ b/src/Lucene.Net.Replicator/Replicator.cs
@@ -1,4 +1,3 @@
-//STATUS: DRAFT - 4.8.0
 using System;
 using System.IO;
 
@@ -62,15 +61,12 @@ namespace Lucene.Net.Replicator
         /// should call <see cref="Release"/> so that the session resources can be
         /// reclaimed, including the revision files.
         /// </remarks>
-        /// <param name="currentVersion"></param>
-        /// <returns></returns>
         /// <exception cref="IOException"></exception>
-        SessionToken CheckForUpdate(string currentVersion);// throws IOException;
+        SessionToken CheckForUpdate(string currentVersion);
 
         /// <summary>
         /// Notify that the specified <see cref="SessionToken"/> is no longer needed by the caller.
         /// </summary>
-        /// <param name="sessionId"></param>
         /// <exception cref="IOException"></exception>
         void Release(string sessionId);
 
@@ -81,10 +77,6 @@ namespace Lucene.Net.Replicator
         /// <remarks>
         /// It is the caller's responsibility to call <see cref="IDisposable.Dispose"/> on the returned stream.
         /// </remarks>
-        /// <param name="sessionId"></param>
-        /// <param name="source"></param>
-        /// <param name="fileName"></param>
-        /// <returns></returns>
         /// <exception cref="SessionExpiredException">The specified session has already expired</exception>
         Stream ObtainFile(string sessionId, string source, string fileName);
     }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/Revision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Revision.cs b/src/Lucene.Net.Replicator/Revision.cs
index 3d6fe19..57d7ffb 100644
--- a/src/Lucene.Net.Replicator/Revision.cs
+++ b/src/Lucene.Net.Replicator/Revision.cs
@@ -1,5 +1,3 @@
-//STATUS: DRAFT - 4.8.0
-
 using System;
 using System.Collections.Generic;
 using System.IO;
@@ -60,15 +58,11 @@ namespace Lucene.Net.Replicator
         int CompareTo(string version);
 
         /// <summary>
-        /// Returns an {@link IndexInput} for the given fileName and source. It is the
-        /// caller's respnsibility to close the {@link IndexInput} when it has been
+        /// Returns a <see cref="Stream"/> for the given fileName and source. It is the
+        /// caller's respnsibility to close the <see cref="Stream"/> when it has been
         /// consumed.
         /// </summary>
-        /// <param name="source"></param>
-        /// <param name="fileName"></param>
-        /// <returns></returns>
         /// <exception cref="IOException"></exception>
-        //TODO: Stream or IndexInput?
         Stream Open(string source, string fileName);
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/RevisionFile.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/RevisionFile.cs b/src/Lucene.Net.Replicator/RevisionFile.cs
index abd7aff..3d54719 100644
--- a/src/Lucene.Net.Replicator/RevisionFile.cs
+++ b/src/Lucene.Net.Replicator/RevisionFile.cs
@@ -1,5 +1,3 @@
-//STATUS: DRAFT - 4.8.0
-
 using System;
 
 namespace Lucene.Net.Replicator
@@ -35,7 +33,6 @@ namespace Lucene.Net.Replicator
         /// </summary>
         public string FileName { get; private set; }
         
-        //TODO: can this be readonly?
         /// <summary>
         /// Gets or sets the length of the file denoted by <see cref="FileName"/>.
         /// </summary>
@@ -44,7 +41,7 @@ namespace Lucene.Net.Replicator
         /// <summary>
         /// Constructor with the given file name and optionally length. 
         /// </summary>
-        /// <param name="fileName"></param>
+        /// <param name="fileName">The name of the file</param>
         /// <param name="length">Optional, the length of the file.</param>
         public RevisionFile(string fileName, long length = -1)
         {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/SessionExpiredException.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/SessionExpiredException.cs b/src/Lucene.Net.Replicator/SessionExpiredException.cs
index 38eed6c..7aeb426 100644
--- a/src/Lucene.Net.Replicator/SessionExpiredException.cs
+++ b/src/Lucene.Net.Replicator/SessionExpiredException.cs
@@ -1,8 +1,5 @@
-//STATUS: DRAFT - 4.8.0
-
 using System;
 using System.IO;
-using System.Runtime.Serialization;
 
 namespace Lucene.Net.Replicator
 {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Replicator/SessionToken.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/SessionToken.cs b/src/Lucene.Net.Replicator/SessionToken.cs
index a9440d7..c998137 100644
--- a/src/Lucene.Net.Replicator/SessionToken.cs
+++ b/src/Lucene.Net.Replicator/SessionToken.cs
@@ -1,8 +1,4 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.IO;
 using Lucene.Net.Store;
 using Lucene.Net.Support.IO;
@@ -67,7 +63,7 @@ namespace Lucene.Net.Replicator
             Id = reader.ReadUTF();
             Version = reader.ReadUTF();
 
-            var sourceFiles = new Dictionary<string, IList<RevisionFile>>();
+            Dictionary<string, IList<RevisionFile>> sourceFiles = new Dictionary<string, IList<RevisionFile>>();
             int numSources = reader.ReadInt32();
             while (numSources > 0)
             {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj b/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj
index 533a4ec..d9f4abd 100644
--- a/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj
+++ b/src/Lucene.Net.TestFramework/Lucene.Net.TestFramework.csproj
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 
  Licensed to the Apache Software Foundation (ASF) under one
@@ -19,7 +19,6 @@
  under the License.
 
 -->
-
 <Project ToolsVersion="12.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>
@@ -530,4 +529,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
index 3d116f9..6254be6 100644
--- a/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
@@ -44,7 +44,6 @@ namespace Lucene.Net.Tests.Replicator.Http
         public override void SetUp()
         {
             base.SetUp();
-            //JAVA:    System.setProperty("org.eclipse.jetty.LEVEL", "DEBUG"); // sets stderr logging to DEBUG level
             clientWorkDir = CreateTempDir("httpReplicatorTest");
             handlerIndexDir = NewDirectory();
             serverIndexDir = NewDirectory();
@@ -61,7 +60,6 @@ namespace Lucene.Net.Tests.Replicator.Http
         {
             StopHttpServer(server);
             IOUtils.Dispose(reader, writer, handlerIndexDir, serverIndexDir);
-            //JAVA:    System.clearProperty("org.eclipse.jetty.LEVEL");
             base.TearDown();
         }
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
index 645888a..a6cdfbc 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
@@ -116,36 +116,6 @@ namespace Lucene.Net.Tests.Replicator
 
         private void AssertHandlerRevision(int expectedId, Directory dir)
         {
-            //JAVA: private void assertHandlerRevision(int expectedID, Directory dir) throws IOException {
-            //JAVA:   // loop as long as client is alive. test-framework will terminate us if
-            //JAVA:   // there's a serious bug, e.g. client doesn't really update. otherwise,
-            //JAVA:   // introducing timeouts is not good, can easily lead to false positives.
-            //JAVA:   while (client.isUpdateThreadAlive()) {
-            //JAVA:     // give client a chance to update
-            //JAVA:     try {
-            //JAVA:       Thread.sleep(100);
-            //JAVA:     } catch (InterruptedException e) {
-            //JAVA:       throw new ThreadInterruptedException(e);
-            //JAVA:     }
-            //JAVA:     
-            //JAVA:     try {
-            //JAVA:       DirectoryReader reader = DirectoryReader.open(dir);
-            //JAVA:       try {
-            //JAVA:         int handlerID = Integer.parseInt(reader.getIndexCommit().getUserData().get(VERSION_ID), 16);
-            //JAVA:         if (expectedID == handlerID) {
-            //JAVA:           return;
-            //JAVA:         }
-            //JAVA:       } finally {
-            //JAVA:         reader.close();
-            //JAVA:       }
-            //JAVA:     } catch (Exception e) {
-            //JAVA:       // we can hit IndexNotFoundException or e.g. EOFException (on
-            //JAVA:       // segments_N) because it is being copied at the same time it is read by
-            //JAVA:       // DirectoryReader.open().
-            //JAVA:     }
-            //JAVA:   }
-            //JAVA: }
-
             // loop as long as client is alive. test-framework will terminate us if
             // there's a serious bug, e.g. client doesn't really update. otherwise,
             // introducing timeouts is not good, can easily lead to false positives.
@@ -180,15 +150,6 @@ namespace Lucene.Net.Tests.Replicator
 
         private IRevision CreateRevision(int id)
         {
-            //JAVA: private Revision createRevision(final int id) throws IOException {
-            //JAVA:   publishIndexWriter.addDocument(newDocument(publishTaxoWriter, id));
-            //JAVA:   publishIndexWriter.setCommitData(new HashMap<String, String>() {{
-            //JAVA:     put(VERSION_ID, Integer.toString(id, 16));
-            //JAVA:   }});
-            //JAVA:   publishIndexWriter.commit();
-            //JAVA:   publishTaxoWriter.commit();
-            //JAVA:   return new IndexAndTaxonomyRevision(publishIndexWriter, publishTaxoWriter);
-            //JAVA: }
             publishIndexWriter.AddDocument(NewDocument(publishTaxoWriter, id));
             publishIndexWriter.SetCommitData(new Dictionary<string, string>{
                 { VERSION_ID, id.ToString("X") }
@@ -309,12 +270,10 @@ namespace Lucene.Net.Tests.Replicator
             newTaxo.Dispose();
         }
 
-        //JAVA: /*
-        //JAVA:  * This test verifies that the client and handler do not end up in a corrupt
-        //JAVA:  * index if exceptions are thrown at any point during replication. Either when
-        //JAVA:  * a client copies files from the server to the temporary space, or when the
-        //JAVA:  * handler copies them to the index directory.
-        //JAVA:  */
+        // This test verifies that the client and handler do not end up in a corrupt
+        // index if exceptions are thrown at any point during replication. Either when
+        // a client copies files from the server to the temporary space, or when the
+        // handler copies them to the index directory.
         [Test]
         public void TestConsistencyOnExceptions()
         {
@@ -482,11 +441,6 @@ namespace Lucene.Net.Tests.Replicator
                         // category to all documents, there's nothing much more to validate
                         TestUtil.CheckIndex(test.handlerTaxoDir.Delegate);
                     }
-                    //TODO: Java had this, but considering what it does do we need it?
-                    //JAVA: catch (IOException e)
-                    //JAVA: {
-                    //JAVA:     throw new RuntimeException(e);
-                    //JAVA: }
                     finally
                     {
                         // count-down number of failures
@@ -507,8 +461,6 @@ namespace Lucene.Net.Tests.Replicator
                 }
                 else
                 {
-                    //JAVA:          if (t instanceof RuntimeException) throw (RuntimeException) t;
-                    //JAVA:          throw new RuntimeException(t);
                     throw exception;
                 }
             }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
index dd20864..9a54148 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
@@ -2,6 +2,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using Lucene.Net.Documents;
 using Lucene.Net.Facet;
@@ -11,6 +12,7 @@ using Lucene.Net.Replicator;
 using Lucene.Net.Store;
 using Lucene.Net.Util;
 using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Tests.Replicator
 {
@@ -166,9 +168,7 @@ namespace Lucene.Net.Tests.Replicator
                             {
                                 skip = 0;
                             }
-                            //JAVA: in.skip(skip);
-                            byte[] skips = new byte[skip];
-                            @in.Read(skips, 0, skip);
+                            @in.Seek(skip, SeekOrigin.Current);
                             src.Seek(skip);
                             offset = skip;
                         }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
index 6a56c77..9d28332 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
@@ -28,14 +28,6 @@ namespace Lucene.Net.Tests.Replicator
 
             public IndexReadyCallback(Directory indexDir)
             {
-                //JAVA:    public IndexReadyCallback(Directory indexDir) throws IOException {
-                //JAVA:      this.indexDir = indexDir;
-                //JAVA:      if (DirectoryReader.indexExists(indexDir)) {
-                //JAVA:        reader = DirectoryReader.open(indexDir);
-                //JAVA:        lastGeneration = reader.getIndexCommit().getGeneration();
-                //JAVA:      }
-                //JAVA:    }
-
                 this.indexDir = indexDir;
                 if (DirectoryReader.IndexExists(indexDir))
                 {
@@ -46,22 +38,6 @@ namespace Lucene.Net.Tests.Replicator
 
             public bool? Call()
             {
-                //JAVA:    public Boolean call() throws Exception {
-                //JAVA:      if (reader == null) {
-                //JAVA:        reader = DirectoryReader.open(indexDir);
-                //JAVA:        lastGeneration = reader.getIndexCommit().getGeneration();
-                //JAVA:      } else {
-                //JAVA:        DirectoryReader newReader = DirectoryReader.openIfChanged(reader);
-                //JAVA:        assertNotNull("should not have reached here if no changes were made to the index", newReader);
-                //JAVA:        long newGeneration = newReader.getIndexCommit().getGeneration();
-                //JAVA:        assertTrue("expected newer generation; current=" + lastGeneration + " new=" + newGeneration, newGeneration > lastGeneration);
-                //JAVA:        reader.close();
-                //JAVA:        reader = newReader;
-                //JAVA:        lastGeneration = newGeneration;
-                //JAVA:        TestUtil.checkIndex(indexDir);
-                //JAVA:      }
-                //JAVA:      return null;
-                //JAVA:    }
                 if (reader == null)
                 {
                     reader = DirectoryReader.Open(indexDir);
@@ -94,44 +70,11 @@ namespace Lucene.Net.Tests.Replicator
         private IReplicationHandler handler;
         private IndexWriter publishWriter;
         private IndexReadyCallback callback;
-        //JAVA:  private IndexReadyCallback callback;
 
         private const string VERSION_ID = "version";
 
         private void AssertHandlerRevision(int expectedId, Directory dir)
         {
-            //JAVA:  private void assertHandlerRevision(int expectedID, Directory dir) throws IOException {
-            //JAVA:    // loop as long as client is alive. test-framework will terminate us if
-            //JAVA:    // there's a serious bug, e.g. client doesn't really update. otherwise,
-            //JAVA:    // introducing timeouts is not good, can easily lead to false positives.
-            //JAVA:    while (client.isUpdateThreadAlive()) {
-            //JAVA:      // give client a chance to update
-            //JAVA:      try {
-            //JAVA:        Thread.sleep(100);
-            //JAVA:      } catch (InterruptedException e) {
-            //JAVA:        throw new ThreadInterruptedException(e);
-            //JAVA:      }
-            //JAVA:
-            //JAVA:      try {
-            //JAVA:        DirectoryReader reader = DirectoryReader.open(dir);
-            //JAVA:        try {
-            //JAVA:          int handlerID = Integer.parseInt(reader.getIndexCommit().getUserData().get(VERSION_ID), 16);
-            //JAVA:          if (expectedID == handlerID) {
-            //JAVA:            return;
-            //JAVA:          } else if (VERBOSE) {
-            //JAVA:            System.out.println("expectedID=" + expectedID + " actual=" + handlerID + " generation=" + reader.getIndexCommit().getGeneration());
-            //JAVA:          }
-            //JAVA:        } finally {
-            //JAVA:          reader.close();
-            //JAVA:        }
-            //JAVA:      } catch (Exception e) {
-            //JAVA:        // we can hit IndexNotFoundException or e.g. EOFException (on
-            //JAVA:        // segments_N) because it is being copied at the same time it is read by
-            //JAVA:        // DirectoryReader.open().
-            //JAVA:      }
-            //JAVA:    }
-            //JAVA:  }
-
             // loop as long as client is alive. test-framework will terminate us if
             // there's a serious bug, e.g. client doesn't really update. otherwise,
             // introducing timeouts is not good, can easily lead to false positives.
@@ -170,14 +113,6 @@ namespace Lucene.Net.Tests.Replicator
 
         private IRevision CreateRevision(int id)
         {
-            //JAVA:  private Revision createRevision(final int id) throws IOException {
-            //JAVA:    publishWriter.addDocument(new Document());
-            //JAVA:    publishWriter.setCommitData(new HashMap<String, String>() {{
-            //JAVA:      put(VERSION_ID, Integer.toString(id, 16));
-            //JAVA:    }});
-            //JAVA:    publishWriter.commit();
-            //JAVA:    return new IndexRevision(publishWriter);
-            //JAVA:  }
             publishWriter.AddDocument(new Document());
             publishWriter.SetCommitData(new Dictionary<string, string>{
                 { VERSION_ID, id.ToString("X") }
@@ -188,20 +123,6 @@ namespace Lucene.Net.Tests.Replicator
 
         public override void SetUp()
         {
-            //JAVA:  public void setUp() throws Exception {
-            //JAVA:    super.setUp();
-            //JAVA:    publishDir = newMockDirectory();
-            //JAVA:    handlerDir = newMockDirectory();
-            //JAVA:    sourceDirFactory = new PerSessionDirectoryFactory(createTempDir("replicationClientTest"));
-            //JAVA:    replicator = new LocalReplicator();
-            //JAVA:    callback = new IndexReadyCallback(handlerDir);
-            //JAVA:    handler = new IndexReplicationHandler(handlerDir, callback);
-            //JAVA:    client = new ReplicationClient(replicator, handler, sourceDirFactory);
-            //JAVA:    
-            //JAVA:    IndexWriterConfig conf = newIndexWriterConfig(TEST_VERSION_CURRENT, null);
-            //JAVA:    conf.setIndexDeletionPolicy(new SnapshotDeletionPolicy(conf.getIndexDeletionPolicy()));
-            //JAVA:    publishWriter = new IndexWriter(publishDir, conf);
-            //JAVA:  }
             base.SetUp();
 
             publishDir = NewMockDirectory();
@@ -219,10 +140,6 @@ namespace Lucene.Net.Tests.Replicator
 
         public override void TearDown()
         {
-            //JAVA:  public void tearDown() throws Exception {
-            //JAVA:    IOUtils.close(client, callback, publishWriter, replicator, publishDir, handlerDir);
-            //JAVA:    super.tearDown();
-            //JAVA:  }
             IOUtils.Dispose(client, callback, publishWriter, replicator, publishDir, handlerDir);
             base.TearDown();
         }
@@ -230,21 +147,6 @@ namespace Lucene.Net.Tests.Replicator
         [Test]
         public void TestNoUpdateThread()
         {
-            //JAVA:  public void testNoUpdateThread() throws Exception {
-            //JAVA:    assertNull("no version expected at start", handler.currentVersion());
-            //JAVA:    
-            //JAVA:    // Callback validates the replicated index
-            //JAVA:    replicator.publish(createRevision(1));
-            //JAVA:    client.updateNow();
-            //JAVA:    
-            //JAVA:    replicator.publish(createRevision(2));
-            //JAVA:    client.updateNow();
-            //JAVA:    
-            //JAVA:    // Publish two revisions without update, handler should be upgraded to latest
-            //JAVA:    replicator.publish(createRevision(3));
-            //JAVA:    replicator.publish(createRevision(4));
-            //JAVA:    client.updateNow();
-            //JAVA:  }
             assertNull("no version expected at start", handler.CurrentVersion);
 
             // Callback validates the replicated ind
@@ -264,21 +166,6 @@ namespace Lucene.Net.Tests.Replicator
         [Test]
         public void TestUpdateThread()
         {
-            //JAVA:  public void testUpdateThread() throws Exception {
-            //JAVA:    client.startUpdateThread(10, "index");
-            //JAVA:    
-            //JAVA:    replicator.publish(createRevision(1));
-            //JAVA:    assertHandlerRevision(1, handlerDir);
-            //JAVA:    
-            //JAVA:    replicator.publish(createRevision(2));
-            //JAVA:    assertHandlerRevision(2, handlerDir);
-            //JAVA:    
-            //JAVA:    // Publish two revisions without update, handler should be upgraded to latest
-            //JAVA:    replicator.publish(createRevision(3));
-            //JAVA:    replicator.publish(createRevision(4));
-            //JAVA:    assertHandlerRevision(4, handlerDir);
-            //JAVA:  }
-
             client.StartUpdateThread(10, "index");
 
             replicator.Publish(CreateRevision(1));
@@ -296,22 +183,6 @@ namespace Lucene.Net.Tests.Replicator
         [Test]
         public void TestRestart()
         {
-            //JAVA:  public void testRestart() throws Exception {
-            //JAVA:    replicator.publish(createRevision(1));
-            //JAVA:    client.updateNow();
-            //JAVA:    
-            //JAVA:    replicator.publish(createRevision(2));
-            //JAVA:    client.updateNow();
-            //JAVA:    
-            //JAVA:    client.stopUpdateThread();
-            //JAVA:    client.close();
-            //JAVA:    client = new ReplicationClient(replicator, handler, sourceDirFactory);
-            //JAVA:    
-            //JAVA:    // Publish two revisions without update, handler should be upgraded to latest
-            //JAVA:    replicator.publish(createRevision(3));
-            //JAVA:    replicator.publish(createRevision(4));
-            //JAVA:    client.updateNow();
-            //JAVA:  }
             replicator.Publish(CreateRevision(1));
             client.UpdateNow();
 
@@ -328,12 +199,10 @@ namespace Lucene.Net.Tests.Replicator
             client.UpdateNow();
         }
 
-        //JAVA:  /*
-        //JAVA:   * This test verifies that the client and handler do not end up in a corrupt
-        //JAVA:   * index if exceptions are thrown at any point during replication. Either when
-        //JAVA:   * a client copies files from the server to the temporary space, or when the
-        //JAVA:   * handler copies them to the index directory.
-        //JAVA:   */
+        // This test verifies that the client and handler do not end up in a corrupt
+        // index if exceptions are thrown at any point during replication. Either when
+        // a client copies files from the server to the temporary space, or when the
+        // handler copies them to the index directory.
         [Test]
         public void TestConsistencyOnExceptions()
         {
@@ -352,7 +221,6 @@ namespace Lucene.Net.Tests.Replicator
             // where the handler overwrites an existing index file, but
             // there's nothing currently we can do about it, unless we don't
             // use MDW.
-            //JAVA:    handlerDir.setPreventDoubleWrite(false);
             handlerDir.PreventDoubleWrite = false;
 
             // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
@@ -478,12 +346,6 @@ namespace Lucene.Net.Tests.Replicator
                         // verify index consistency
                         TestUtil.CheckIndex(test.handlerDir.Delegate);
                     }
-                    //TODO: Java had this, but considering what it does do we need it?
-                    //JAVA: catch (IOException e)
-                    //JAVA: {
-                    //JAVA:     // exceptions here are bad, don't ignore them
-                    //JAVA:     throw new RuntimeException(e);
-                    //JAVA: }
                     finally
                     {
                         // count-down number of failures
@@ -502,8 +364,6 @@ namespace Lucene.Net.Tests.Replicator
                         }
                     }
                 } else {
-                    //JAVA:          if (t instanceof RuntimeException) throw (RuntimeException) t;
-                    //JAVA:          throw new RuntimeException(t);
                     throw exception;
                 }
             }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
index de4dbb4..ee0108b 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
@@ -1,6 +1,7 @@
 //STATUS: DRAFT - 4.8.0
 
 using System;
+using System.IO;
 using System.Linq;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
@@ -8,6 +9,7 @@ using Lucene.Net.Replicator;
 using Lucene.Net.Store;
 using Lucene.Net.Util;
 using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Tests.Replicator
 {
@@ -144,7 +146,7 @@ namespace Lucene.Net.Tests.Replicator
                 foreach (RevisionFile file in sourceFiles.Values.First())
                 {
                     IndexInput src = dir.OpenInput(file.FileName, IOContext.READ_ONCE);
-                    System.IO.Stream @in = rev.Open(source, file.FileName);
+                    Stream @in = rev.Open(source, file.FileName);
                     assertEquals(src.Length, @in.Length);
                     byte[] srcBytes = new byte[(int) src.Length];
                     byte[] inBytes = new byte[(int) src.Length];
@@ -156,9 +158,7 @@ namespace Lucene.Net.Tests.Replicator
                         {
                             skip = 0;
                         }
-                        //JAVA: in.skip(skip);
-                        byte[] skips = new byte[skip];
-                        @in.Read(skips, 0, skip);
+                        @in.Seek(skip, SeekOrigin.Current);
                         src.Seek(skip);
                         offset = skip;
                     }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
index 9946457..d54e2e1 100644
--- a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
@@ -61,9 +61,6 @@ namespace Lucene.Net.Tests.Replicator
         private IRevision CreateRevision(int id)
         {
             sourceWriter.AddDocument(new Document());
-            //JAVA: sourceWriter.setCommitData(new HashMap<String, String>() {{
-            //JAVA:     put(VERSION_ID, Integer.toString(id, 16));
-            //JAVA: }
             sourceWriter.SetCommitData(new Dictionary<string, string> {
                 { VERSION_ID, id.ToString() }
             });
@@ -175,8 +172,7 @@ namespace Lucene.Net.Tests.Replicator
                 replicator.ObtainFile(res.Id, res.SourceFiles.Keys.First(), "madeUpFile");
                 fail("should have failed obtaining an unrecognized file");
             }
-            //JAVA: } catch (FileNotFoundException | NoSuchFileException e) { -> Could not find a "NoSuchFileException" ?NoSuchItemException
-            catch (Exception e) when (e is FileNotFoundException)//|| e is NoSuchItemException)
+            catch (FileNotFoundException e)
             {
                 // expected
             }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
index 1b8ec1e..58e6ea9 100644
--- a/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
+++ b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
@@ -28,99 +28,8 @@ namespace Lucene.Net.Tests.Replicator
 
     public class ReplicatorTestCase : LuceneTestCase
     {
-        //JAVA:  private static ClientConnectionManager clientConnectionManager;
-        //JAVA:  
-        //JAVA:  @AfterClass
-        //JAVA:  public static void afterClassReplicatorTestCase() throws Exception {
-        //JAVA:    if (clientConnectionManager != null) {
-        //JAVA:      clientConnectionManager.shutdown();
-        //JAVA:      clientConnectionManager = null;
-        //JAVA:    }
-        //JAVA:  }
-        //JAVA:  
-
-
         public static TestServer NewHttpServer<TStartUp>(ReplicationService service) where TStartUp : class
         {
-            #region JAVA
-            //JAVA:  /**
-            //JAVA:   * Returns a new {@link Server HTTP Server} instance. To obtain its port, use
-            //JAVA:   * {@link #serverPort(Server)}.
-            //JAVA:   */
-            //JAVA:  public static synchronized Server newHttpServer(Handler handler) throws Exception {
-            //JAVA:    Server server = new Server(0);
-            //JAVA:    
-            //JAVA:    server.setHandler(handler);
-            //JAVA:    
-            //JAVA:    final String connectorName = System.getProperty("tests.jettyConnector", "SelectChannel");
-            //JAVA:    
-            //JAVA:    // if this property is true, then jetty will be configured to use SSL
-            //JAVA:    // leveraging the same system properties as java to specify
-            //JAVA:    // the keystore/truststore if they are set
-            //JAVA:    //
-            //JAVA:    // This means we will use the same truststore, keystore (and keys) for
-            //JAVA:    // the server as well as any client actions taken by this JVM in
-            //JAVA:    // talking to that server, but for the purposes of testing that should 
-            //JAVA:    // be good enough
-            //JAVA:    final boolean useSsl = Boolean.getBoolean("tests.jettySsl");
-            //JAVA:    final SslContextFactory sslcontext = new SslContextFactory(false);
-            //JAVA:    
-            //JAVA:    if (useSsl) {
-            //JAVA:      if (null != System.getProperty("javax.net.ssl.keyStore")) {
-            //JAVA:        sslcontext.setKeyStorePath
-            //JAVA:        (System.getProperty("javax.net.ssl.keyStore"));
-            //JAVA:      }
-            //JAVA:      if (null != System.getProperty("javax.net.ssl.keyStorePassword")) {
-            //JAVA:        sslcontext.setKeyStorePassword
-            //JAVA:        (System.getProperty("javax.net.ssl.keyStorePassword"));
-            //JAVA:      }
-            //JAVA:      if (null != System.getProperty("javax.net.ssl.trustStore")) {
-            //JAVA:        sslcontext.setTrustStore
-            //JAVA:        (System.getProperty("javax.net.ssl.trustStore"));
-            //JAVA:      }
-            //JAVA:      if (null != System.getProperty("javax.net.ssl.trustStorePassword")) {
-            //JAVA:        sslcontext.setTrustStorePassword
-            //JAVA:        (System.getProperty("javax.net.ssl.trustStorePassword"));
-            //JAVA:      }
-            //JAVA:      sslcontext.setNeedClientAuth(Boolean.getBoolean("tests.jettySsl.clientAuth"));
-            //JAVA:    }
-            //JAVA:    
-            //JAVA:    final Connector connector;
-            //JAVA:    final QueuedThreadPool threadPool;
-            //JAVA:    if ("SelectChannel".equals(connectorName)) {
-            //JAVA:      final SelectChannelConnector c = useSsl ? new SslSelectChannelConnector(sslcontext) : new SelectChannelConnector();
-            //JAVA:      c.setReuseAddress(true);
-            //JAVA:      c.setLowResourcesMaxIdleTime(1500);
-            //JAVA:      connector = c;
-            //JAVA:      threadPool = (QueuedThreadPool) c.getThreadPool();
-            //JAVA:    } else if ("Socket".equals(connectorName)) {
-            //JAVA:      final SocketConnector c = useSsl ? new SslSocketConnector(sslcontext) : new SocketConnector();
-            //JAVA:      c.setReuseAddress(true);
-            //JAVA:      connector = c;
-            //JAVA:      threadPool = (QueuedThreadPool) c.getThreadPool();
-            //JAVA:    } else {
-            //JAVA:      throw new IllegalArgumentException("Illegal value for system property 'tests.jettyConnector': " + connectorName);
-            //JAVA:    }
-            //JAVA:    
-            //JAVA:    connector.setPort(0);
-            //JAVA:    connector.setHost("127.0.0.1");
-            //JAVA:    if (threadPool != null) {
-            //JAVA:      threadPool.setDaemon(true);
-            //JAVA:      threadPool.setMaxThreads(10000);
-            //JAVA:      threadPool.setMaxIdleTimeMs(5000);
-            //JAVA:      threadPool.setMaxStopTimeMs(30000);
-            //JAVA:    }
-            //JAVA:    
-            //JAVA:    server.setConnectors(new Connector[] {connector});
-            //JAVA:    server.setSessionIdManager(new HashSessionIdManager(new Random(random().nextLong())));
-            //JAVA:    
-            //JAVA:    server.start();
-            //JAVA:    
-            //JAVA:    return server;
-            //JAVA:  }
-            //JAVA:  
-            #endregion
-
             var server = new TestServer(new WebHostBuilder()
                 .ConfigureServices(container =>
                 {
@@ -135,10 +44,6 @@ namespace Lucene.Net.Tests.Replicator
         /// </summary>
         public static int ServerPort(TestServer server)
         {
-            //JAVA:  /** Returns a {@link Server}'s port. */
-            //JAVA:  public static int serverPort(Server server) {
-            //JAVA:    return server.getConnectors()[0].getLocalPort();
-            //JAVA:  }
             return server.BaseAddress.Port;
         }
 
@@ -147,10 +52,6 @@ namespace Lucene.Net.Tests.Replicator
         /// </summary>
         public static string ServerHost(TestServer server)
         {
-            //JAVA:  /** Returns a {@link Server}'s host. */
-            //JAVA:  public static String serverHost(Server server) {
-            //JAVA:    return server.getConnectors()[0].getHost();
-            //JAVA:  }
             return server.BaseAddress.Host;
         }
 
@@ -159,34 +60,7 @@ namespace Lucene.Net.Tests.Replicator
         /// </summary>
         public static void StopHttpServer(TestServer server)
         {
-            //JAVA:  /**
-            //JAVA:   * Stops the given HTTP Server instance. This method does its best to guarantee
-            //JAVA:   * that no threads will be left running following this method.
-            //JAVA:   */
-            //JAVA:  public static void stopHttpServer(Server httpServer) throws Exception {
-            //JAVA:    httpServer.stop();
-            //JAVA:    httpServer.join();
-            //JAVA:  }
             server.Dispose();
         }
-
-        //JAVA:  
-        //JAVA:  /**
-        //JAVA:   * Returns a {@link ClientConnectionManager}.
-        //JAVA:   * <p>
-        //JAVA:   * <b>NOTE:</b> do not {@link ClientConnectionManager#shutdown()} this
-        //JAVA:   * connection manager, it will be shutdown automatically after all tests have
-        //JAVA:   * finished.
-        //JAVA:   */
-        //JAVA:  public static synchronized ClientConnectionManager getClientConnectionManager() {
-        //JAVA:    if (clientConnectionManager == null) {
-        //JAVA:      PoolingClientConnectionManager ccm = new PoolingClientConnectionManager();
-        //JAVA:      ccm.setDefaultMaxPerRoute(128);
-        //JAVA:      ccm.setMaxTotal(128);
-        //JAVA:      clientConnectionManager = ccm;
-        //JAVA:    }
-        //JAVA:    
-        //JAVA:    return clientConnectionManager;
-        //JAVA:  }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net/Lucene.Net.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Lucene.Net.csproj b/src/Lucene.Net/Lucene.Net.csproj
index d2b8e6e..50b1b14 100644
--- a/src/Lucene.Net/Lucene.Net.csproj
+++ b/src/Lucene.Net/Lucene.Net.csproj
@@ -395,6 +395,7 @@
     <Compile Include="Index\UpgradeIndexMergePolicy.cs" />
     <Compile Include="LucenePackage.cs" />
     <Compile Include="Support\Document\DocumentExtensions.cs" />
+    <Compile Include="Support\EnumerableExtensions.cs" />
     <Compile Include="Support\IO\Compression\LZOCompressor.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Search\AutomatonQuery.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e3305307/src/Lucene.Net/Support/EnumerableExtensions.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net/Support/EnumerableExtensions.cs b/src/Lucene.Net/Support/EnumerableExtensions.cs
new file mode 100644
index 0000000..f621289
--- /dev/null
+++ b/src/Lucene.Net/Support/EnumerableExtensions.cs
@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+
+namespace Lucene.Net.Support
+{
+    /*
+	 * 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>
+    /// .NET Specific Helper Extensions for IEnumerable
+    /// </summary>
+    //Note: LUCENENET specific
+    public static class EnumerableExtensions
+    {
+        /// <summary>
+        /// Enumerates a sequence in pairs  
+        /// </summary>
+        /// <remarks>
+        /// In the case of an uneven amount of elements, the list call to <paramref name="join" /> pases <code>default(T)</code> as the second parameter.
+        /// </remarks>
+        /// <typeparam name="T">The type of the elements of <paramref name="source" />.</typeparam>
+        /// <typeparam name="TOut">The type of the elements returned from <paramref name="join" />.</typeparam>
+        /// <param name="source">An <see cref="T:System.Collections.Generic.IEnumerable`1" /> to enumerate in pairs.</param>
+        /// <param name="join">A function that is invoked for each pair of elements.</param>
+        /// <exception cref="T:System.ArgumentNullException"><paramref name="source" /> or <paramref name="join" /> is <see langword="null" />.</exception>
+        /// <returns>A new <see cref="T:System.Collections.Generic.IEnumerable`1" /> containing the results from each pair.</returns>
+        public static IEnumerable<TOut> InPairs<T, TOut>(this IEnumerable<T> source, Func<T, T, TOut> join)
+        {
+            if (source == null)
+                throw new ArgumentNullException("source");
+            if (join == null)
+                throw new ArgumentNullException("join");
+
+            using (IEnumerator<T> enumerator = source.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


[18/20] lucenenet git commit: Lucene.Net.Replicator.RevisionFile: Corrected GetHashCode() logic

Posted by ni...@apache.org.
Lucene.Net.Replicator.RevisionFile: Corrected GetHashCode() logic


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

Branch: refs/heads/replicator
Commit: e83f40fc6a2a118ba3633249c31e1a5edffd6d81
Parents: 6469c62
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 07:59:50 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 07:59:50 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Replicator/RevisionFile.cs | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/e83f40fc/src/Lucene.Net.Replicator/RevisionFile.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/RevisionFile.cs b/src/Lucene.Net.Replicator/RevisionFile.cs
index 0fa897f..139ac23 100644
--- a/src/Lucene.Net.Replicator/RevisionFile.cs
+++ b/src/Lucene.Net.Replicator/RevisionFile.cs
@@ -69,10 +69,7 @@ namespace Lucene.Net.Replicator
 
         public override int GetHashCode()
         {
-            unchecked // LUCENENET TODO: Correct hash code logic
-            {
-                return (FileName.GetHashCode() * 397) ^ Length.GetHashCode();
-            }
+            return FileName.GetHashCode() ^ (int)(Length ^ (long)((ulong)Length >> 32));
         }
 
         public override string ToString()


[15/20] lucenenet git commit: BUG: Lucene.Net.Tests.Replicator.ReplicatorTestCase: Added missing SuppressCodecs attribute.

Posted by ni...@apache.org.
BUG: Lucene.Net.Tests.Replicator.ReplicatorTestCase: Added missing SuppressCodecs attribute.


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

Branch: refs/heads/replicator
Commit: 06ff981b98db213df3e2c068e546a15238d461e9
Parents: 4db2b0a
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 05:30:35 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 05:30:35 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/06ff981b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
index 0e35b2c..75743a3 100644
--- a/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
+++ b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
@@ -24,6 +24,7 @@ namespace Lucene.Net.Replicator
 	 * limitations under the License.
 	 */
 
+    [SuppressCodecs("Lucene3x")]
     public class ReplicatorTestCase : LuceneTestCase
     {
         public static TestServer NewHttpServer<TStartUp>(ReplicationService service) where TStartUp : class


[08/20] lucenenet git commit: Lucene.Net.Replicator: Cleaned up documentation and reverted code order back to the same as Lucene.

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/ReplicationClient.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/ReplicationClient.cs b/src/Lucene.Net.Replicator/ReplicationClient.cs
index 14c1c2b..6064856 100644
--- a/src/Lucene.Net.Replicator/ReplicationClient.cs
+++ b/src/Lucene.Net.Replicator/ReplicationClient.cs
@@ -32,32 +32,154 @@ namespace Lucene.Net.Replicator
     /// <summary>
     /// A client which monitors and obtains new revisions from a <see cref="IReplicator"/>.
     /// It can be used to either periodically check for updates by invoking
-    /// <see cref="StartUpdateThread"/>, or manually by calling <see cref="UpdateNow"/>.
-    /// <para>
+    /// <see cref="StartUpdateThread"/>, or manually by calling <see cref="UpdateNow()"/>.
+    /// <para/>
     /// Whenever a new revision is available, the <see cref="RequiredFiles"/> are
     /// copied to the <see cref="Directory"/> specified by <see cref="PerSessionDirectoryFactory"/> and
     /// a handler is notified.
-    /// </para>
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public class ReplicationClient : IDisposable
     {
+        //Note: LUCENENET specific, .NET does not work with Threads in the same way as Java does, so we mimic the same behavior using the ThreadPool instead.
+        private class ReplicationThread
+        {
+            private readonly Action doUpdate;
+            private readonly Action<Exception> handleException;
+            private readonly ReentrantLock @lock;
+            private readonly object controlLock = new object();
+
+            private readonly long interval;
+            private readonly AutoResetEvent handle = new AutoResetEvent(false);
+
+            private AutoResetEvent stopHandle;
+
+            /// <summary>
+            /// Gets or sets the name
+            /// </summary>
+            public string Name { get; private set; }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            /// <param name="intervalMillis">The interval in milliseconds.</param>
+            /// <param name="threadName">The thread name.</param>
+            /// <param name="doUpdate">A delegate to call to perform the update.</param>
+            /// <param name="handleException">A delegate to call to handle an exception.</param>
+            /// <param name="lock"></param>
+            public ReplicationThread(long intervalMillis, string threadName, Action doUpdate, Action<Exception> handleException, ReentrantLock @lock)
+            {
+                this.doUpdate = doUpdate;
+                this.handleException = handleException;
+                this.@lock = @lock;
+                Name = threadName;
+                this.interval = intervalMillis;
+            }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            public bool IsAlive { get; private set; }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            public void Start()
+            {
+                lock (controlLock)
+                {
+                    if (IsAlive)
+                        return;
+                    IsAlive = true;
+                }
+                RegisterWait(interval);
+            }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            public void Stop()
+            {
+                lock (controlLock)
+                {
+                    if (!IsAlive)
+                        return;
+                    IsAlive = false;
+                }
+                stopHandle = new AutoResetEvent(false);
+
+                //NOTE: Execute any outstanding, this execution will terminate almost instantaniously if it's not already running.
+                ExecuteImmediately();
+
+                stopHandle.WaitOne();
+                stopHandle = null;
+            }
+
+            /// <summary>
+            /// Executes the next cycle of work immediately
+            /// </summary>
+            public void ExecuteImmediately()
+            {
+                handle.Set();
+            }
+
+            private void RegisterWait(long timeout)
+            {
+                //NOTE: We don't care about timedout as it can either be because we was requested to run immidiately or stop.
+                if (IsAlive)
+                    ThreadPool.RegisterWaitForSingleObject(handle, (state, timedout) => Run(), null, timeout, true);
+                else
+                    SignalStop();
+            }
+
+            private void SignalStop()
+            {
+                if (stopHandle != null)
+                    stopHandle.Set();
+            }
+
+            private void Run()
+            {
+                if (!IsAlive)
+                {
+                    SignalStop();
+                    return;
+                }
+
+                Stopwatch timer = Stopwatch.StartNew();
+                @lock.Lock();
+                try
+                {
+                    doUpdate();
+                }
+                catch (Exception exception)
+                {
+                    handleException(exception);
+                }
+                finally
+                {
+                    @lock.Unlock();
+
+                    timer.Stop();
+                    long driftAdjusted = Math.Max(interval - timer.ElapsedMilliseconds, 0);
+                    if (IsAlive)
+                        RegisterWait(driftAdjusted);
+                    else
+                        SignalStop();
+                }
+            }
+        }
+
+        // LUCENENET specific - de-nested the IReplicationHandler and
+        // ISourceDirectoryFactory interfaces.
+
         /// <summary>
         /// The component name to use with <see cref="Util.InfoStream.IsEnabled"/>
         /// </summary>
         public const string INFO_STREAM_COMPONENT = "ReplicationThread";
 
-        /// <summary> 
-        /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages. 
-        /// </summary>
-        public InfoStream InfoStream
-        {
-            get { return infoStream; }
-            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
-        }
-
         private readonly IReplicator replicator;
         private readonly IReplicationHandler handler;
         private readonly ISourceDirectoryFactory factory;
@@ -83,6 +205,16 @@ namespace Lucene.Net.Replicator
         }
 
         /// <exception cref="IOException"></exception>
+        private void CopyBytes(IndexOutput output, Stream input)
+        {
+            int numBytes;
+            while ((numBytes = input.Read(copyBuffer, 0, copyBuffer.Length)) > 0)
+            {
+                output.WriteBytes(copyBuffer, 0, numBytes);
+            }
+        }
+
+        /// <exception cref="IOException"></exception>
         private void DoUpdate()
         {
             SessionToken session = null;
@@ -179,19 +311,18 @@ namespace Lucene.Net.Replicator
                     factory.CleanupSession(session.Id);
                 }
             }
-
         }
 
-        /// <exception cref="IOException"></exception>
-        private void CopyBytes(IndexOutput output, Stream input)
+        /// <summary>Throws <see cref="ObjectDisposedException"/> if the client has already been disposed.</summary>
+        protected virtual void EnsureOpen()
         {
-            int numBytes;
-            while ((numBytes = input.Read(copyBuffer, 0, copyBuffer.Length)) > 0) {
-                output.WriteBytes(copyBuffer, 0, numBytes);
-            }
+            if (!disposed)
+                return;
+
+            throw new ObjectDisposedException("this update client has already been closed");
         }
 
-        //.NET Note: Utility Method
+        // LUCENENET specific Utility Method
         private void WriteToInfoStream(string message)
         {
             if (infoStream.IsEnabled(INFO_STREAM_COMPONENT))
@@ -199,11 +330,26 @@ namespace Lucene.Net.Replicator
         }
 
         /// <summary>
+        /// Called when an exception is hit by the replication thread. The default
+        /// implementation prints the full stacktrace to the <see cref="Util.InfoStream"/> set in
+        /// <see cref="InfoStream"/>, or the <see cref="Util.InfoStream.Default"/>
+        /// one. You can override to log the exception elsewhere.
+        /// </summary>
+        /// <remarks>
+        /// <b>NOTE:</b> If you override this method to throw the exception further,
+        /// the replication thread will be terminated. The only way to restart it is to
+        /// call <see cref="StopUpdateThread"/> followed by
+        /// <see cref="StartUpdateThread"/>.
+        /// </remarks>
+        protected virtual void HandleUpdateException(Exception exception)
+        {
+            WriteToInfoStream(string.Format("an error occurred during revision update: {0}", exception));
+        }
+
+        /// <summary>
         /// Returns the files required for replication. By default, this method returns
         /// all files that exist in the new revision, but not in the handler.
         /// </summary>
-        /// <param name="newRevisionFiles"></param>
-        /// <returns></returns>
         private IDictionary<string, IList<RevisionFile>> RequiredFiles(IDictionary<string, IList<RevisionFile>> newRevisionFiles)
         {
             IDictionary<string, IList<RevisionFile>> handlerRevisionFiles = handler.CurrentRevisionFiles;
@@ -227,10 +373,25 @@ namespace Lucene.Net.Replicator
             return requiredFiles;
         }
 
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposed)
+                return;
+
+            StopUpdateThread();
+            disposed = true;
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
         /// <summary>
         /// Start the update thread with the specified interval in milliseconds. For
         /// debugging purposes, you can optionally set the name to set on
-        /// <see cref="ReplicationThread.Name"/>. If you pass <code>null</code>, a default name
+        /// <see cref="ReplicationThread.Name"/>. If you pass <c>null</c>, a default name
         /// will be set.
         /// </summary>
         /// <exception cref="InvalidOperationException"> if the thread has already been started </exception>
@@ -273,34 +434,15 @@ namespace Lucene.Net.Replicator
             get { return updateThread != null && updateThread.IsAlive; }
         }
 
-        /// <summary>Throws <see cref="ObjectDisposedException"/> if the client has already been disposed.</summary>
-        protected virtual void EnsureOpen()
-        {
-            if (!disposed)
-                return;
-
-            throw new ObjectDisposedException("this update client has already been closed");
-        }
-
-        /// <summary>
-        /// Called when an exception is hit by the replication thread. The default
-        /// implementation prints the full stacktrace to the <seealso cref="InfoStream"/> set in
-        /// <seealso cref="InfoStream"/>, or the <see cref="Util.InfoStream.Default"/>
-        /// one. You can override to log the exception elswhere.
-        /// </summary>
-        /// <remarks>
-        /// If you override this method to throw the exception further,
-        /// the replication thread will be terminated. The only way to restart it is to
-        /// call <seealso cref="StopUpdateThread"/> followed by
-        /// <seealso cref="StartUpdateThread"/>.
-        /// </remarks>
-        protected virtual void HandleUpdateException(Exception exception)
+        public override string ToString()
         {
-            WriteToInfoStream(string.Format("an error occurred during revision update: {0}", exception));
+            if (updateThread == null)
+                return "ReplicationClient";
+            return string.Format("ReplicationClient ({0})", updateThread.Name);
         }
 
         /// <summary>
-        /// Executes the update operation immediately, irregardess if an update thread
+        /// Executes the update operation immediately, regardless if an update thread
         /// is running or not.
         /// </summary>
         /// <exception cref="IOException"></exception>
@@ -327,156 +469,61 @@ namespace Lucene.Net.Replicator
             }
         }
 
-        protected virtual void Dispose(bool disposing)
-        {
-            if (disposed)
-                return;
-
-            StopUpdateThread();
-            disposed = true;
-        }
-
-        public void Dispose()
-        {
-            Dispose(true);
-            GC.SuppressFinalize(this);
-        }
-
-        public override string ToString()
+        /// <summary> 
+        /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages. 
+        /// </summary>
+        public InfoStream InfoStream
         {
-            if (updateThread == null)
-                return "ReplicationClient";
-            return string.Format("ReplicationClient ({0})", updateThread.Name);
+            get { return infoStream; }
+            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
         }
+    }
 
-        //Note: LUCENENET specific, .NET does not work with Threads in the same way as Java does, so we mimic the same behavior using the ThreadPool instead.
-        private class ReplicationThread
-        {
-            private readonly Action doUpdate;
-            private readonly Action<Exception> handleException;
-            private readonly ReentrantLock @lock;
-            private readonly object controlLock = new object();
-            
-            private readonly long interval;
-            private readonly AutoResetEvent handle = new AutoResetEvent(false);
-
-            private AutoResetEvent stopHandle;
-
-            /// <summary>
-            /// Gets or sets the name
-            /// </summary>
-            public string Name { get; private set; }
-
-            /// <summary>
-            /// 
-            /// </summary>
-            /// <param name="intervalMillis"></param>
-            /// <param name="threadName"></param>
-            /// <param name="doUpdate"></param>
-            /// <param name="handleException"></param>
-            /// <param name="lock"></param>
-            public ReplicationThread(long intervalMillis, string threadName, Action doUpdate, Action<Exception> handleException, ReentrantLock @lock)
-            {
-                this.doUpdate = doUpdate;
-                this.handleException = handleException;
-                this.@lock = @lock;
-                Name = threadName;
-                this.interval = intervalMillis;
-            }
-
-            /// <summary>
-            /// 
-            /// </summary>
-            public bool IsAlive { get; private set; }
-
-            /// <summary>
-            /// 
-            /// </summary>
-            public void Start()
-            {
-                lock (controlLock)
-                {
-                    if (IsAlive)
-                        return;
-                    IsAlive = true;
-                }
-                RegisterWait(interval);
-            }
-
-            /// <summary>
-            /// 
-            /// </summary>
-            public void Stop()
-            {
-                lock (controlLock)
-                {
-                    if (!IsAlive)
-                        return;
-                    IsAlive = false;
-                }
-                stopHandle = new AutoResetEvent(false);
-
-                //NOTE: Execute any outstanding, this execution will terminate almost instantaniously if it's not already running.
-                ExecuteImmediately();
-
-                stopHandle.WaitOne();
-                stopHandle = null;
-            }
-
-            /// <summary>
-            /// Executes the next cycle of work immediately
-            /// </summary>
-            public void ExecuteImmediately()
-            {
-                handle.Set();
-            }
-
-            private void RegisterWait(long timeout)
-            {
-                //NOTE: We don't care about timedout as it can either be because we was requested to run immidiately or stop.
-                if (IsAlive)
-                    ThreadPool.RegisterWaitForSingleObject(handle, (state, timedout) => Run(), null, timeout, true);
-                else
-                    SignalStop();
-            }
-
-            private void SignalStop()
-            {
-                if (stopHandle != null)
-                    stopHandle.Set();
-            }
+    /// <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; }
 
-            private void Run()
-            {
-                if (!IsAlive)
-                {
-                    SignalStop();
-                    return;
-                }
+        /// <summary>Returns the current revision version held by the handler.</summary>
+        IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; }
 
-                Stopwatch timer = Stopwatch.StartNew();
-                @lock.Lock();
-                try
-                {
-                    doUpdate();
-                }
-                catch (Exception exception)
-                {
-                    handleException(exception);
-                }
-                finally
-                {
-                    @lock.Unlock();
+        /// <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>
+        /// <exception cref="IOException"/>
+        void RevisionReady(string version,
+            IDictionary<string, IList<RevisionFile>> revisionFiles,
+            IDictionary<string, IList<string>> copiedFiles,
+            IDictionary<string, Directory> sourceDirectory);
+    }
 
-                    timer.Stop();
-                    long driftAdjusted = Math.Max(interval - timer.ElapsedMilliseconds, 0);
-                    if (IsAlive)
-                        RegisterWait(driftAdjusted);
-                    else
-                        SignalStop();
-                }
-            }
-        }
+    /// <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>
+        /// <exception cref="System.IO.IOException"></exception>
+        /// <seealso cref="CleanupSession(string)"/>
+        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

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/Replicator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Replicator.cs b/src/Lucene.Net.Replicator/Replicator.cs
index 28de0d3..05bbd5a 100644
--- a/src/Lucene.Net.Replicator/Replicator.cs
+++ b/src/Lucene.Net.Replicator/Replicator.cs
@@ -22,22 +22,21 @@ namespace Lucene.Net.Replicator
 
     /// <summary>
     /// An interface for replicating files. Allows a producer to 
-    /// <see cref="Publish"/> <see cref="IRevision"/>s and consumers to
-    /// <see cref="CheckForUpdate"/>. When a client needs to be
+    /// <see cref="Publish(IRevision)"/> <see cref="IRevision"/>s and consumers to
+    /// <see cref="CheckForUpdate(string)"/>. When a client needs to be
     /// updated, it is given a <see cref="SessionToken"/> through which it can
-    /// <see cref="ObtainFile"/> the files of that
+    /// <see cref="ObtainFile(string, string, string)"/> the files of that
     /// revision. After the client has finished obtaining all the files, it should
-    /// <see cref="Release"/> the given session, so that the files can be
+    /// <see cref="Release(string)"/> the given session, so that the files can be
     /// reclaimed if they are not needed anymore.
-    /// <p>
+    /// <para/>
     /// A client is always updated to the newest revision available. That is, if a
     /// client is on revision <em>r1</em> and revisions <em>r2</em> and <em>r3</em>
-    /// were published, then when the cllient will next check for update, it will
+    /// were published, then when the client will next check for update, it will
     /// receive <em>r3</em>.
-    /// </p>
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public interface IReplicator : IDisposable
     {
@@ -54,10 +53,10 @@ namespace Lucene.Net.Replicator
         /// <summary>
         /// Check whether the given version is up-to-date and returns a
         /// <see cref="SessionToken"/> which can be used for fetching the revision files,
-        /// otherwise returns <code>null</code>.
+        /// otherwise returns <c>null</c>.
         /// </summary>
         /// <remarks>
-        /// When the returned session token is no longer needed, you
+        /// <b>NOTE:</b> When the returned session token is no longer needed, you
         /// should call <see cref="Release"/> so that the session resources can be
         /// reclaimed, including the revision files.
         /// </remarks>
@@ -75,7 +74,7 @@ namespace Lucene.Net.Replicator
         /// context of the given <see cref="SessionToken.Id"/>.
         /// </summary>
         /// <remarks>
-        /// It is the caller's responsibility to call <see cref="IDisposable.Dispose"/> on the returned stream.
+        /// <b>NOTE:</b> It is the caller's responsibility to call <see cref="IDisposable.Dispose"/> on the returned stream.
         /// </remarks>
         /// <exception cref="SessionExpiredException">The specified session has already expired</exception>
         Stream ObtainFile(string sessionId, string source, string fileName);

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/Revision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Revision.cs b/src/Lucene.Net.Replicator/Revision.cs
index 57d7ffb..7963241 100644
--- a/src/Lucene.Net.Replicator/Revision.cs
+++ b/src/Lucene.Net.Replicator/Revision.cs
@@ -33,13 +33,19 @@ namespace Lucene.Net.Replicator
     /// they match at the client side.
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public interface IRevision : IComparable<IRevision>
     {
         /// <summary>
+        /// Compares the revision to the given version string. Behaves like
+        /// <see cref="IComparable{T}.CompareTo(T)"/>
+        /// </summary>
+        int CompareTo(string version);
+
+        /// <summary>
         /// Returns a string representation of the version of this revision. The
-        /// version is used by <see cref="CompareTo"/> as well as to
+        /// version is used by <see cref="CompareTo(string)"/> as well as to
         /// serialize/deserialize revision information. Therefore it must be self
         /// descriptive as well as be able to identify one revision from another.
         /// </summary>
@@ -52,14 +58,8 @@ namespace Lucene.Net.Replicator
         IDictionary<string, IList<RevisionFile>> SourceFiles { get; }
 
         /// <summary>
-        /// Compares the revision to the given version string. Behaves like
-        /// <see cref="IComparable{T}.CompareTo"/>
-        /// </summary>
-        int CompareTo(string version);
-
-        /// <summary>
-        /// Returns a <see cref="Stream"/> for the given fileName and source. It is the
-        /// caller's respnsibility to close the <see cref="Stream"/> when it has been
+        /// Returns a <see cref="Stream"/> for the given <paramref name="fileName"/> and <paramref name="source"/>. It is the
+        /// caller's respnsibility to dispose the <see cref="Stream"/> when it has been
         /// consumed.
         /// </summary>
         /// <exception cref="IOException"></exception>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/RevisionFile.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/RevisionFile.cs b/src/Lucene.Net.Replicator/RevisionFile.cs
index 3d54719..c74f057 100644
--- a/src/Lucene.Net.Replicator/RevisionFile.cs
+++ b/src/Lucene.Net.Replicator/RevisionFile.cs
@@ -24,7 +24,7 @@ namespace Lucene.Net.Replicator
     /// single revision to contain files from multiple sources (e.g. multiple indexes).
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public class RevisionFile : IEquatable<RevisionFile>
     {
@@ -51,12 +51,15 @@ namespace Lucene.Net.Replicator
             Length = length;
         }
 
-        public override string ToString()
+        public override bool Equals(object obj)
         {
-            return string.Format("fileName={0} length={1}", FileName, Length);
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != this.GetType()) return false;
+            return Equals((RevisionFile)obj);
         }
 
-        #region Resharper Generated Code
+        // LUCENENET specific Equals overload
         public bool Equals(RevisionFile other)
         {
             if (ReferenceEquals(null, other)) return false;
@@ -64,21 +67,17 @@ namespace Lucene.Net.Replicator
             return string.Equals(FileName, other.FileName) && Length == other.Length;
         }
 
-        public override bool Equals(object obj)
-        {
-            if (ReferenceEquals(null, obj)) return false;
-            if (ReferenceEquals(this, obj)) return true;
-            if (obj.GetType() != this.GetType()) return false;
-            return Equals((RevisionFile)obj);
-        }
-
         public override int GetHashCode()
         {
-            unchecked
+            unchecked // LUCENENET TODO: Correct hash code logic
             {
                 return (FileName.GetHashCode() * 397) ^ Length.GetHashCode();
             }
         }
-        #endregion
+
+        public override string ToString()
+        {
+            return string.Format("fileName={0} length={1}", FileName, Length);
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/SessionExpiredException.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/SessionExpiredException.cs b/src/Lucene.Net.Replicator/SessionExpiredException.cs
index 7aeb426..45c16a1 100644
--- a/src/Lucene.Net.Replicator/SessionExpiredException.cs
+++ b/src/Lucene.Net.Replicator/SessionExpiredException.cs
@@ -1,5 +1,8 @@
 using System;
 using System.IO;
+#if FEATURE_SERIALIZABLE
+using System.Runtime.Serialization;
+#endif
 
 namespace Lucene.Net.Replicator
 {
@@ -24,11 +27,14 @@ namespace Lucene.Net.Replicator
     /// Exception indicating that a revision update session was expired due to lack of activity.
     /// </summary>
     /// <remarks>
-    /// <see cref="LocalReplicator.DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>
-    /// <see cref="LocalReplicator.ExpirationThreshold"/>
-    /// 
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
+    /// <seealso cref="LocalReplicator.DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>
+    /// <seealso cref="LocalReplicator.ExpirationThreshold"/>
+    // LUCENENET: All exeption classes should be marked serializable
+#if FEATURE_SERIALIZABLE
+    [Serializable]
+#endif
     public class SessionExpiredException : IOException
     {
         //
@@ -51,5 +57,17 @@ namespace Lucene.Net.Replicator
             : base(message, inner)
         {
         }
+
+#if FEATURE_SERIALIZABLE
+        /// <summary>
+        /// Initializes a new instance of this class with serialized data.
+        /// </summary>
+        /// <param name="info">The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.</param>
+        /// <param name="context">The <see cref="StreamingContext"/> that contains contextual information about the source or destination.</param>
+        public SessionExpiredException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+        {
+        }
+#endif
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/SessionToken.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/SessionToken.cs b/src/Lucene.Net.Replicator/SessionToken.cs
index c998137..305729b 100644
--- a/src/Lucene.Net.Replicator/SessionToken.cs
+++ b/src/Lucene.Net.Replicator/SessionToken.cs
@@ -1,7 +1,5 @@
-using System.Collections.Generic;
-using System.IO;
-using Lucene.Net.Store;
 using Lucene.Net.Support.IO;
+using System.Collections.Generic;
 
 namespace Lucene.Net.Replicator
 {
@@ -27,20 +25,19 @@ namespace Lucene.Net.Replicator
     /// files will be kept safe until the replication completes.
     /// </summary>
     /// <remarks>
-    /// <see cref="IReplicator.CheckForUpdate"/>
-    /// <see cref="IReplicator.Release"/>
-    /// <see cref="LocalReplicator.DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>
-    /// 
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
+    /// <seealso cref="IReplicator.CheckForUpdate"/>
+    /// <seealso cref="IReplicator.Release"/>
+    /// <seealso cref="LocalReplicator.DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>
     public sealed class SessionToken
     {
         /// <summary>
         /// Id of this session.
         /// Should be passed when releasing the session, thereby acknowledging the 
-        /// <see cref="IReplicator"/>  that this session is no longer in use.
-        /// <see cref="IReplicator.Release"/>
+        /// <see cref="IReplicator"/> that this session is no longer in use.
         /// </summary>
+        /// <seealso cref="IReplicator.Release"/>
         public string Id { get; private set; }
 
         /// <summary>
@@ -54,11 +51,10 @@ namespace Lucene.Net.Replicator
         public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
 
         /// <summary>
-        /// Constructor which deserializes from the given <see cref="DataInput"/>.
+        /// Constructor which deserializes from the given <see cref="IDataInput"/>.
         /// </summary>
-        /// <param name="reader"></param>
-        /// <exception cref="IOException"></exception>
-        public SessionToken(DataInputStream reader)
+        /// <exception cref="System.IO.IOException"></exception>
+        public SessionToken(DataInputStream reader) // LUCENENET TODO: API : IDataInput
         {
             Id = reader.ReadUTF();
             Version = reader.ReadUTF();
@@ -82,11 +78,9 @@ namespace Lucene.Net.Replicator
         }
 
         /// <summary>
-        /// Constructor with the given id and revision.
+        /// Constructor with the given <paramref name="id"/> and <paramref name="revision"/>.
         /// </summary>
-        /// <param name="id"></param>
-        /// <param name="revision"></param>
-        /// <exception cref="IOException"></exception>
+        /// <exception cref="System.IO.IOException"></exception>
         public SessionToken(string id, IRevision revision)
         {
             Id = id;
@@ -97,8 +91,7 @@ namespace Lucene.Net.Replicator
         /// <summary>
         /// Serialize the token data for communication between server and client.
         /// </summary>
-        /// <param name="writer"></param>
-        /// <exception cref="IOException"></exception>
+        /// <exception cref="System.IO.IOException"></exception>
         public void Serialize(DataOutputStream writer)
         {
             writer.WriteUTF(Id);


[09/20] lucenenet git commit: Lucene.Net.Replicator: Cleaned up documentation and reverted code order back to the same as Lucene.

Posted by ni...@apache.org.
Lucene.Net.Replicator: Cleaned up documentation and reverted code order back to the same as Lucene.


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

Branch: refs/heads/replicator
Commit: 678824651ae4dc02d9c51850b9f7ff6383dda78d
Parents: e330530
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 01:46:02 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 01:46:02 2017 +0700

----------------------------------------------------------------------
 .../AspNetCoreReplicationRequest.cs             |  26 +-
 .../AspNetCoreReplicationResponse.cs            |  22 +-
 .../AspNetCoreReplicationServiceExtentions.cs   |  19 +-
 .../Http/HttpClientBase.cs                      |  91 ++--
 .../Http/HttpReplicator.cs                      |  48 +--
 .../Http/ReplicationService.cs                  |  25 +-
 src/Lucene.Net.Replicator/Http/package.html     |  28 --
 .../IReplicationHandler.cs                      |  32 --
 .../ISourceDirectoryFactory.cs                  |  27 --
 .../IndexAndTaxonomyReplicationHandler.cs       |  19 +-
 .../IndexAndTaxonomyRevision.cs                 | 177 ++++----
 .../IndexInputInputStream.cs                    |   8 +-
 .../IndexReplicationHandler.cs                  | 243 ++++++-----
 src/Lucene.Net.Replicator/IndexRevision.cs      |  80 ++--
 src/Lucene.Net.Replicator/LocalReplicator.cs    | 326 +++++++-------
 .../Lucene.Net.Replicator.csproj                |   8 +-
 .../PerSessionDirectoryFactory.cs               |   4 +-
 src/Lucene.Net.Replicator/ReplicationClient.cs  | 431 ++++++++++---------
 src/Lucene.Net.Replicator/Replicator.cs         |  21 +-
 src/Lucene.Net.Replicator/Revision.cs           |  20 +-
 src/Lucene.Net.Replicator/RevisionFile.cs       |  27 +-
 .../SessionExpiredException.cs                  |  26 +-
 src/Lucene.Net.Replicator/SessionToken.cs       |  33 +-
 23 files changed, 875 insertions(+), 866 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/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
index 7a9fba2..4bcdba5 100644
--- a/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationRequest.cs
+++ b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationRequest.cs
@@ -1,14 +1,26 @@
-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 Lucene.Net.Replicator.Http.Abstractions;
 using Microsoft.AspNetCore.Http;
+using System.Linq;
 
 namespace Lucene.Net.Replicator.AspNetCore
 {
+    /*
+     * 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>
     /// Abstraction for remote replication requests, allows easy integration into any hosting frameworks.
     /// </summary>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/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
index e671101..8e73b28 100644
--- a/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationResponse.cs
+++ b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationResponse.cs
@@ -1,10 +1,26 @@
-using System.IO;
-using Lucene.Net.Replicator.Http;
-using Lucene.Net.Replicator.Http.Abstractions;
+using Lucene.Net.Replicator.Http.Abstractions;
 using Microsoft.AspNetCore.Http;
+using System.IO;
 
 namespace Lucene.Net.Replicator.AspNetCore
 {
+    /*
+     * 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>
     /// Implementation of the <see cref="IReplicationResponse"/> abstraction for the AspNetCore framework.
     /// </summary>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/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
index f772bfd..967ea0f 100644
--- a/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationServiceExtentions.cs
+++ b/src/Lucene.Net.Replicator.AspNetCore/AspNetCoreReplicationServiceExtentions.cs
@@ -3,11 +3,28 @@ using Microsoft.AspNetCore.Http;
 
 namespace Lucene.Net.Replicator.AspNetCore
 {
+    /*
+     * 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.
+     */
+
     //Note: LUCENENET specific
     public static class AspNetCoreReplicationServiceExtentions
     {
         /// <summary>
-        /// Extensiont method that mirrors the signature of <see cref="ReplicationService.Perform"/> using AspNetCore as implementation.
+        /// Extension 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)
         {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/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
index 139fffd..8f46b98 100644
--- a/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
+++ b/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
@@ -31,7 +31,7 @@ namespace Lucene.Net.Replicator.Http
     /// Base class for Http clients.
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public abstract class HttpClientBase : IDisposable
     {
@@ -49,49 +49,32 @@ namespace Lucene.Net.Replicator.Http
         protected string Url { get; private set; }
 
         private readonly HttpClient httpc;
-
-        /// <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); }
-        }
-
-        /// <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; }
+        private volatile bool isDisposed = false;
 
         /// <summary>
         /// Creates a new <see cref="HttpClientBase"/> with the given host, port and path.
         /// </summary>
         /// <remarks>
-        /// The host, port and path parameters are normalized to <code>http://{host}:{port}{path}</code>, 
-        /// if path is <code>null</code> or <code>empty</code> it defaults to <code>/</code>.
-        /// <p>
-        /// A <see cref="HttpMessageHandler"/> is taken as an optional parameter as well, if this is not provided it defaults to null.
+        /// The host, port and path parameters are normalized to <c>http://{host}:{port}{path}</c>, 
+        /// if path is <c>null</c> or <c>empty</c> it defaults to <c>/</c>.
+        /// <para/>
+        /// A <see cref="HttpMessageHandler"/> is taken as an optional parameter as well, if this is not provided it defaults to <c>null</c>.
         /// In this case the internal <see cref="HttpClient"/> will default to use a <see cref="HttpClientHandler"/>.
-        /// </p>
         /// </remarks>
         /// <param name="host">The host that the client should retrieve data from.</param>
         /// <param name="port">The port to be used to connect on.</param>
         /// <param name="path">The path to the replicator on the host.</param>
-        /// <param name="messageHandler">Optional, The HTTP handler stack to use for sending requests, defaults to null.</param>
+        /// <param name="messageHandler">Optional, The HTTP handler stack to use for sending requests, defaults to <c>null</c>.</param>
         protected HttpClientBase(string host, int port, string path, HttpMessageHandler messageHandler = null)
             : this(NormalizedUrl(host, port, path), messageHandler)
         {
         }
 
         /// <summary>
-        /// Creates a new <see cref="HttpClientBase"/> with the given url.
+        /// Creates a new <see cref="HttpClientBase"/> with the given <paramref name="url"/>.
         /// </summary>
         /// <remarks>
-        /// A <see cref="HttpMessageHandler"/> is taken as an optional parameter as well, if this is not provided it defaults to null.
+        /// A <see cref="HttpMessageHandler"/> is taken as an optional parameter as well, if this is not provided it defaults to <c>null</c>.
         /// In this case the internal <see cref="HttpClient"/> will default to use a <see cref="HttpClientHandler"/>.
         /// </remarks>
         /// <param name="url">The full url, including with host, port and path.</param>
@@ -103,11 +86,11 @@ namespace Lucene.Net.Replicator.Http
         }
 
         /// <summary>
-        /// Creates a new <see cref="HttpClientBase"/> with the given url and HttpClient.
+        /// Creates a new <see cref="HttpClientBase"/> with the given <paramref name="url"/> and <see cref="HttpClient"/>.
         /// </summary>
         /// <remarks>
-        /// This allows full controll over how the HttpClient is created, 
-        /// prefer the <see cref="HttpClientBase(string, HttpMessageHandler)"/> over this unless you know you need the control of the HttpClient.
+        /// This allows full controll over how the <see cref="HttpClient"/> is created, 
+        /// prefer the <see cref="HttpClientBase(string, HttpMessageHandler)"/> over this unless you know you need the control of the <see cref="HttpClient"/>.
         /// </remarks>
         /// <param name="url"></param>
         /// <param name="client">The <see cref="HttpClient"/> to use make remote http calls.</param>
@@ -116,21 +99,34 @@ namespace Lucene.Net.Replicator.Http
         {
             Url = url;
             httpc = client;
-            IsDisposed = false;
+            ConnectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
+        }
+
+        /// <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); }
         }
 
         /// <summary>
-        /// Throws <see cref="ObjectDisposedException"/> if this client is already closed. 
+        /// Throws <see cref="ObjectDisposedException"/> if this client is already disposed. 
         /// </summary>
-        /// <exception cref="ObjectDisposedException">client is already closed.</exception>
+        /// <exception cref="ObjectDisposedException">client is already disposed.</exception>
         protected void EnsureOpen()
         {
             if (IsDisposed)
             {
-                throw new ObjectDisposedException("HttpClient already closed");
+                throw new ObjectDisposedException("HttpClient already disposed");
             }
         }
 
+        /// <summary>
+        /// Create a URL out of the given parameters, translate an empty/null path to '/'
+        /// </summary>
         private static string NormalizedUrl(string host, int port, string path)
         {
             if (string.IsNullOrEmpty(path))
@@ -139,7 +135,7 @@ namespace Lucene.Net.Replicator.Http
         }
 
         /// <summary>
-        /// Verifies the response status and if not successfull throws an exception.
+        /// <b>Internal:</b> Verifies the response status and if not successful 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>
@@ -199,6 +195,10 @@ namespace Lucene.Net.Replicator.Http
             throw new HttpRequestException(string.Format("unknown exception: {0} {1}", response.StatusCode, response.ReasonPhrase), exception);
         }
 
+        /// <summary>
+        /// <b>Internal:</b> Execute a request and return its result.
+        /// The <paramref name="parameters"/> argument is treated as: name1,value1,name2,value2,...
+        /// </summary>
         protected HttpResponseMessage ExecutePost(string request, object entity, params string[] parameters)
         {
             EnsureOpen();
@@ -215,6 +215,10 @@ namespace Lucene.Net.Replicator.Http
             return response;
         }
 
+        /// <summary>
+        /// <b>Internal:</b> Execute a request and return its result.
+        /// The <paramref name="parameters"/> argument is treated as: name1,value1,name2,value2,...
+        /// </summary>
         protected HttpResponseMessage ExecuteGet(string request, params string[] parameters)
         {
             EnsureOpen();
@@ -236,7 +240,7 @@ namespace Lucene.Net.Replicator.Http
         }
 
         /// <summary>
-        /// Internal utility: input stream of the provided response
+        /// Internal utility: input stream of the provided response.
         /// </summary>
         /// <exception cref="IOException"></exception>
         public Stream ResponseInputStream(HttpResponseMessage response)
@@ -244,8 +248,10 @@ namespace Lucene.Net.Replicator.Http
             return ResponseInputStream(response, false);
         }
 
+        // TODO: can we simplify this Consuming !?!?!?
         /// <summary>
-        /// Internal utility: input stream of the provided response
+        /// Internal utility: input stream of the provided response, which optionally 
+        /// consumes the response's resources when the input stream is exhausted.
         /// </summary>
         /// <exception cref="IOException"></exception>
         public Stream ResponseInputStream(HttpResponseMessage response, bool consume)
@@ -254,7 +260,14 @@ namespace Lucene.Net.Replicator.Http
         }
 
         /// <summary>
-        /// Calls the overload <see cref="DoAction{T}(HttpResponseMessage, Boolean, Func{T})"/> passing <code>true</code> to consume.
+        /// Returns <c>true</c> if this instance was <see cref="Dispose(bool)"/>ed, otherwise
+        /// returns <c>false</c>. 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 { return isDisposed; } }
+
+        /// <summary>
+        /// Calls the overload <see cref="DoAction{T}(HttpResponseMessage, bool, Func{T})"/> passing <c>true</c> to consume.
         /// </summary>
         protected T DoAction<T>(HttpResponseMessage response, Func<T> call)
         {
@@ -264,7 +277,7 @@ namespace Lucene.Net.Replicator.Http
         /// <summary>
         /// Do a specific action and validate after the action that the status is still OK, 
         /// and if not, attempt to extract the actual server side exception. Optionally
-        /// release the response at exit, depending on <code>consume</code> parameter.
+        /// release the response at exit, depending on <paramref name="consume"/> parameter.
         /// </summary>
         protected T DoAction<T>(HttpResponseMessage response, bool consume, Func<T> call)
         {
@@ -302,7 +315,7 @@ namespace Lucene.Net.Replicator.Http
             {
                 httpc.Dispose();
             }
-            IsDisposed = true;
+            isDisposed = true;
         }
 
         /// <summary>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/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
index ab519c3..052450a 100644
--- a/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
+++ b/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
@@ -26,7 +26,7 @@ namespace Lucene.Net.Replicator.Http
     /// An HTTP implementation of <see cref="IReplicator"/>. Assumes the API supported by <see cref="ReplicationService"/>.
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public class HttpReplicator : HttpClientBase, IReplicator
     {
@@ -50,7 +50,7 @@ namespace Lucene.Net.Replicator.Http
         }
 
         /// <summary>
-        /// Creates a new <see cref="HttpReplicator"/> with the given url and HttpClient.
+        /// Creates a new <see cref="HttpReplicator"/> with the given <paramref name="url"/> and <see cref="HttpClient"/>.
         /// <see cref="HttpClientBase(string, HttpClient)"/> for more details.
         /// </summary>
         //Note: LUCENENET Specific
@@ -58,15 +58,6 @@ namespace Lucene.Net.Replicator.Http
             : base(url, client)
         {
         }
-        
-        /// <summary>
-        /// Not supported.
-        /// </summary>
-        /// <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");
-        }
 
         /// <summary>
         /// Checks for updates at the remote host.
@@ -75,9 +66,9 @@ namespace Lucene.Net.Replicator.Http
         {
             string[] parameters = null;
             if (currentVersion != null)
-                parameters = new [] { ReplicationService.REPLICATE_VERSION_PARAM, currentVersion };
+                parameters = new[] { ReplicationService.REPLICATE_VERSION_PARAM, currentVersion };
 
-            HttpResponseMessage response = base.ExecuteGet( ReplicationService.ReplicationAction.UPDATE.ToString(), parameters);
+            HttpResponseMessage response = base.ExecuteGet(ReplicationService.ReplicationAction.UPDATE.ToString(), parameters);
             return DoAction(response, () =>
             {
                 using (DataInputStream inputStream = new DataInputStream(ResponseInputStream(response)))
@@ -88,25 +79,34 @@ namespace Lucene.Net.Replicator.Http
         }
 
         /// <summary>
-        /// Releases a session obtained from the remote host.
-        /// </summary>
-        public void Release(string sessionId)
-        {
-            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);
-        }
-
-        /// <summary>
         /// Obtains the given file from it's source at the remote host.
         /// </summary>
         public Stream ObtainFile(string sessionId, string source, string fileName)
         {
-            HttpResponseMessage response = ExecuteGet(ReplicationService.ReplicationAction.OBTAIN.ToString(), 
+            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));
         }
+
+        /// <summary>
+        /// Not supported.
+        /// </summary>
+        /// <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");
+        }
+
+        /// <summary>
+        /// Releases a session obtained from the remote host.
+        /// </summary>
+        public void Release(string sessionId)
+        {
+            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);
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/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
index 090ca4d..95c8b50 100644
--- a/src/Lucene.Net.Replicator/Http/ReplicationService.cs
+++ b/src/Lucene.Net.Replicator/Http/ReplicationService.cs
@@ -26,24 +26,22 @@ namespace Lucene.Net.Replicator.Http
 
     /// <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>
+    /// requests are sent in the format <c>/&lt;context&gt;/&lt;shard&gt;/&lt;action&gt;</c> where
+    /// <list type="bullet">
+    ///   <item><description><c>context</c> is the servlet context, e.g. <see cref="REPLICATION_CONTEXT"/></description></item>
+    ///   <item><description><c>shard</c> is the ID of the shard, e.g. "s1"</description></item>
+    ///   <item><description><c>action</c> is one of <see cref="ReplicationAction"/> values</description></item>
+    /// </list>
     /// 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>.
+    /// should send the request: <c>http://host:port/replicate/s1/update</c>.
     /// </summary>
     /// <remarks>
     /// This service is written using abstractions over requests and responses which makes it easy
     /// to integrate into any hosting framework.
-    /// <p>
+    /// <para/>
     /// See the Lucene.Net.Replicator.AspNetCore for an example of an implementation for the AspNetCore Framework.
-    /// </p> 
-    /// </remarks>
-    /// <remarks>
-    /// Lucene.Experimental
+    /// <para/>
+    /// @lucene.experimental
     /// </remarks>
     public class ReplicationService
     {
@@ -83,6 +81,7 @@ namespace Lucene.Net.Replicator.Http
         /// <summary>
         /// Json Serializer Settings to use when serializing and deserializing errors.
         /// </summary>
+        // LUCENENET specific
         public static readonly JsonSerializerSettings JSON_SERIALIZER_SETTINGS = new JsonSerializerSettings()
         {
             TypeNameHandling = TypeNameHandling.All
@@ -125,6 +124,7 @@ namespace Lucene.Net.Replicator.Http
             return param;
         }
 
+        // LUCENENET specific - copy method not used
 
         /// <summary>
         /// Executes the replication task.
@@ -203,6 +203,5 @@ namespace Lucene.Net.Replicator.Http
                 response.Flush();
             }
         }
-
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/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
deleted file mode 100644
index fce050b..0000000
--- a/src/Lucene.Net.Replicator/Http/package.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<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/67882465/src/Lucene.Net.Replicator/IReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IReplicationHandler.cs b/src/Lucene.Net.Replicator/IReplicationHandler.cs
deleted file mode 100644
index d3e6504..0000000
--- a/src/Lucene.Net.Replicator/IReplicationHandler.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-//STATUS: DRAFT - 4.8.0
-
-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/67882465/src/Lucene.Net.Replicator/ISourceDirectoryFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/ISourceDirectoryFactory.cs b/src/Lucene.Net.Replicator/ISourceDirectoryFactory.cs
deleted file mode 100644
index 7942b91..0000000
--- a/src/Lucene.Net.Replicator/ISourceDirectoryFactory.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-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

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs b/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
index 36bf271..d6a3ce0 100644
--- a/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
+++ b/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
@@ -30,23 +30,22 @@ namespace Lucene.Net.Replicator
     /// A <see cref="IReplicationHandler"/> for replication of an index and taxonomy pair.
     /// See <see cref="IReplicationHandler"/> for more detail. This handler ensures
     /// that the search and taxonomy indexes are replicated in a consistent way.
-    /// 
-    /// <see cref="IndexReplicationHandler"/>
     /// </summary>
     /// <remarks>
-    /// If you intend to recreate a taxonomy index, you should make sure
+    /// <b>NOTE:</b> If you intend to recreate a taxonomy index, you should make sure
     /// to reopen an IndexSearcher and TaxonomyReader pair via the provided callback,
     /// to guarantee that both indexes are in sync. This handler does not prevent
     /// replicating such index and taxonomy pairs, and if they are reopened by a
     /// different thread, unexpected errors can occur, as well as inconsistency
     /// between the taxonomy and index readers.
-    /// 
-    /// Lucene.Experimental
+    /// <para/>
+    /// @lucene.experimental
     /// </remarks>
+    /// <seealso cref="IndexReplicationHandler"/>
     public class IndexAndTaxonomyReplicationHandler : IReplicationHandler
     {
         /// <summary>
-        /// The component used to log messages to the <see cref="InfoStream"/>.
+        /// The component used to log messages to the <see cref="Util.InfoStream.Default"/> <see cref="Util.InfoStream"/>.
         /// </summary>
         public const string INFO_STREAM_COMPONENT = "IndexAndTaxonomyReplicationHandler";
 
@@ -58,6 +57,10 @@ namespace Lucene.Net.Replicator
 
         public string CurrentVersion { get; private set; }
         public IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; private set; }
+
+        /// <summary>
+        /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages.
+        /// </summary>
         public InfoStream InfoStream
         {
             get { return infoStream; }
@@ -97,10 +100,6 @@ namespace Lucene.Net.Replicator
             }
         }
 
-        /// <summary>
-        /// TODO
-        /// </summary>
-        /// <exception cref=""></exception>
         public void RevisionReady(string version,
             IDictionary<string, IList<RevisionFile>> revisionFiles,
             IDictionary<string, IList<string>> copiedFiles,

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs b/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
index 890f995..63040b0 100644
--- a/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
+++ b/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
@@ -1,6 +1,4 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
+using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;
@@ -38,10 +36,58 @@ namespace Lucene.Net.Replicator
     /// guarantee consistency of both on the replicating (client) side.
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
+    /// <seealso cref="IndexRevision"/>
     public class IndexAndTaxonomyRevision : IRevision
     {
+        /// <summary>
+        /// A <see cref="DirectoryTaxonomyWriter"/> which sets the underlying
+        /// <see cref="Index.IndexWriter"/>'s <see cref="IndexDeletionPolicy"/> to
+        /// <see cref="SnapshotDeletionPolicy"/>.
+        /// </summary>
+        public class SnapshotDirectoryTaxonomyWriter : DirectoryTaxonomyWriter
+        {
+            /// <summary>
+            /// Gets the <see cref="SnapshotDeletionPolicy"/> used by the underlying <see cref="Index.IndexWriter"/>.
+            /// </summary>
+            public SnapshotDeletionPolicy DeletionPolicy { get; private set; }
+            /// <summary>
+            /// Gets the <see cref="Index.IndexWriter"/> used by this <see cref="DirectoryTaxonomyWriter"/>.
+            /// </summary>
+            public IndexWriter IndexWriter { get; private set; }
+
+            /// <summary>
+            /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode, ITaxonomyWriterCache)"/>
+            /// </summary>
+            /// <exception cref="IOException"></exception>
+            public SnapshotDirectoryTaxonomyWriter(Directory directory, OpenMode openMode, ITaxonomyWriterCache cache)
+                : base(directory, openMode, cache)
+            {
+            }
+
+            /// <summary>
+            /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode)"/>
+            /// </summary>
+            /// <exception cref="IOException"></exception>
+            public SnapshotDirectoryTaxonomyWriter(Directory directory, OpenMode openMode = OpenMode.CREATE_OR_APPEND)
+                : base(directory, openMode)
+            {
+            }
+
+            protected override IndexWriterConfig CreateIndexWriterConfig(OpenMode openMode)
+            {
+                IndexWriterConfig conf = base.CreateIndexWriterConfig(openMode);
+                conf.IndexDeletionPolicy = DeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+                return conf;
+            }
+
+            protected override IndexWriter OpenIndexWriter(Directory directory, IndexWriterConfig config)
+            {
+                return IndexWriter = base.OpenIndexWriter(directory, config);
+            }
+        }
+
         public const string INDEX_SOURCE = "index";
         public const string TAXONOMY_SOURCE = "taxonomy";
 
@@ -50,11 +96,33 @@ namespace Lucene.Net.Replicator
         private readonly IndexCommit indexCommit, taxonomyCommit;
         private readonly SnapshotDeletionPolicy indexSdp, taxonomySdp;
 
-        public string Version { get; private set; }
-        public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
+        /// <summary>
+        /// Returns a map of the revision files from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.
+        /// </summary>
+        /// <exception cref="IOException"></exception>
+        public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit indexCommit, IndexCommit taxonomyCommit)
+        {
+            return new Dictionary<string, IList<RevisionFile>>{
+                    { INDEX_SOURCE,  IndexRevision.RevisionFiles(indexCommit).Values.First() },
+                    { TAXONOMY_SOURCE,  IndexRevision.RevisionFiles(taxonomyCommit).Values.First() }
+                };
+        }
 
         /// <summary>
-        /// TODO
+        /// Returns a <see cref="string"/> representation of a revision's version from the given
+        /// <see cref="IndexCommit"/>s of the search and taxonomy indexes.
+        /// </summary>
+        /// <param name="commit"></param>
+        /// <returns>a <see cref="string"/> representation of a revision's version from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.</returns>
+        public static string RevisionVersion(IndexCommit indexCommit, IndexCommit taxonomyCommit)
+        {
+            return string.Format("{0:X}:{1:X}", indexCommit.Generation, taxonomyCommit.Generation);
+        }
+
+        /// <summary>
+        /// Constructor over the given <see cref="IndexWriter"/>. Uses the last
+        /// <see cref="IndexCommit"/> found in the <see cref="Directory"/> managed by the given
+        /// writer.
         /// </summary>
         /// <exception cref="IOException"></exception>
         public IndexAndTaxonomyRevision(IndexWriter indexWriter, SnapshotDirectoryTaxonomyWriter taxonomyWriter)
@@ -105,9 +173,10 @@ namespace Lucene.Net.Replicator
             return cmp != 0 ? cmp : taxonomyCommit.CompareTo(itr.taxonomyCommit);
         }
 
-        /// <summary>
-        /// TODO
-        /// </summary>
+        public string Version { get; private set; }
+
+        public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
+
         /// <exception cref="IOException"></exception>
         public Stream Open(string source, string fileName)
         {
@@ -116,9 +185,6 @@ namespace Lucene.Net.Replicator
             return new IndexInputStream(commit.Directory.OpenInput(fileName, IOContext.READ_ONCE));
         }
 
-        /// <summary>
-        /// TODO
-        /// </summary>
         /// <exception cref="IOException"></exception>
         public void Release()
         {
@@ -140,90 +206,5 @@ namespace Lucene.Net.Replicator
                 taxonomyWriter.IndexWriter.DeleteUnusedFiles();
             }
         }
-
-        /// <summary>
-        /// Returns a map of the revision files from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.
-        /// </summary>
-        /// <param name="indexCommit"></param>
-        /// <param name="taxonomyCommit"></param>
-        /// <returns></returns>
-        /// <exception cref="IOException"></exception>
-        public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit indexCommit, IndexCommit taxonomyCommit)
-        {
-            return new Dictionary<string, IList<RevisionFile>>{
-                    { INDEX_SOURCE,  IndexRevision.RevisionFiles(indexCommit).Values.First() },
-                    { TAXONOMY_SOURCE,  IndexRevision.RevisionFiles(taxonomyCommit).Values.First() }
-                };
-        }
-
-        /// <summary>
-        /// Returns a String representation of a revision's version from the given
-        /// <see cref="IndexCommit"/>s of the search and taxonomy indexes.
-        /// </summary>
-        /// <param name="commit"></param>
-        /// <returns>a String representation of a revision's version from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.</returns>
-        public static string RevisionVersion(IndexCommit indexCommit, IndexCommit taxonomyCommit)
-        {
-            return string.Format("{0:X}:{1:X}", indexCommit.Generation, taxonomyCommit.Generation);
-        }
-
-        /// <summary>
-        /// A <seealso cref="DirectoryTaxonomyWriter"/> which sets the underlying
-        /// <seealso cref="IndexWriter"/>'s <seealso cref="IndexDeletionPolicy"/> to
-        /// <seealso cref="SnapshotDeletionPolicy"/>.
-        /// </summary>
-        public class SnapshotDirectoryTaxonomyWriter : DirectoryTaxonomyWriter
-        {
-            /// <summary>
-            /// Gets the <see cref="SnapshotDeletionPolicy"/> used by the underlying <see cref="IndexWriter"/>.
-            /// </summary>
-            public SnapshotDeletionPolicy DeletionPolicy { get; private set; }
-            /// <summary>
-            /// Gets the <see cref="IndexWriter"/> used by this <see cref="DirectoryTaxonomyWriter"/>.
-            /// </summary>
-            public IndexWriter IndexWriter { get; private set; }
-
-            /// <summary>
-            /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode, ITaxonomyWriterCache)"/>
-            /// </summary>
-            /// <exception cref="IOException"></exception>
-            public SnapshotDirectoryTaxonomyWriter(Directory directory, OpenMode openMode, ITaxonomyWriterCache cache) 
-                : base(directory, openMode, cache)
-            {
-            }
-
-            /// <summary>
-            /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode)"/>
-            /// </summary>
-            /// <exception cref="IOException"></exception>
-            public SnapshotDirectoryTaxonomyWriter(Directory directory, OpenMode openMode = OpenMode.CREATE_OR_APPEND)
-                : base(directory, openMode)
-            {
-            }
-
-            /// <summary>
-            /// 
-            /// </summary>
-            /// <param name="openMode"></param>
-            /// <returns></returns>
-            protected override IndexWriterConfig CreateIndexWriterConfig(OpenMode openMode)
-            {
-                IndexWriterConfig conf = base.CreateIndexWriterConfig(openMode);
-                conf.IndexDeletionPolicy = DeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
-                return conf;
-            }
-
-            /// <summary>
-            /// TODO
-            /// </summary>
-            /// <param name="directory"></param>
-            /// <param name="config"></param>
-            /// <returns></returns>
-            protected override IndexWriter OpenIndexWriter(Directory directory, IndexWriterConfig config)
-            {
-                return IndexWriter = base.OpenIndexWriter(directory, config);
-            }
-        }
-
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/IndexInputInputStream.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexInputInputStream.cs b/src/Lucene.Net.Replicator/IndexInputInputStream.cs
index 95f6e1c..df72010 100644
--- a/src/Lucene.Net.Replicator/IndexInputInputStream.cs
+++ b/src/Lucene.Net.Replicator/IndexInputInputStream.cs
@@ -1,6 +1,4 @@
-//STATUS: INPROGRESS - 4.8.0
-
-using System;
+using System;
 using System.IO;
 using Lucene.Net.Store;
 
@@ -24,10 +22,10 @@ namespace Lucene.Net.Replicator
 	 */
 
     /// <summary>
-    /// 
+    /// A <see cref="Stream"/> which wraps an <see cref="IndexInput"/>.
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public class IndexInputStream : Stream
     {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexReplicationHandler.cs b/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
index 7edc95c..5189e44 100644
--- a/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
+++ b/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
@@ -34,26 +34,24 @@ namespace Lucene.Net.Replicator
     /// <see cref="IndexWriter"/> to make sure any unused files are deleted.
     /// </summary>
     /// <remarks>
-    /// <para>
-    /// This handler assumes that <see cref="IndexWriter"/> is not opened by
+    /// <b>NOTE:</b> This handler assumes that <see cref="IndexWriter"/> is not opened by
     /// another process on the index directory. In fact, opening an
     /// <see cref="IndexWriter"/> on the same directory to which files are copied can lead
     /// to undefined behavior, where some or all the files will be deleted, override
     /// other files or simply create a mess. When you replicate an index, it is best
     /// if the index is never modified by <see cref="IndexWriter"/>, except the one that is
     /// open on the source index, from which you replicate.
-    /// </para>
-    /// <para>
-    /// This handler notifies the application via a provided <see cref="Callable"/> when an
+    /// <para/>
+    /// This handler notifies the application via a provided <see cref="T:Func{bool?}"/> when an
     /// updated index commit was made available for it.
-    /// </para>
-    /// 
-    /// Lucene.Experimental
+    /// <para/>
+    /// @lucene.experimental
     /// </remarks>
     public class IndexReplicationHandler : IReplicationHandler
     {
         /// <summary>
-        /// The component used to log messages to the <see cref="InfoStream"/>.
+        /// The component used to log messages to the <see cref="Util.InfoStream.Default"/> 
+        /// <see cref="Util.InfoStream"/>.
         /// </summary>
         public const string INFO_STREAM_COMPONENT = "IndexReplicationHandler";
 
@@ -61,104 +59,6 @@ namespace Lucene.Net.Replicator
         private readonly Func<bool?> callback;
         private InfoStream infoStream;
 
-        public string CurrentVersion { get; private set; }
-        public IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; private set; }
-
-        public InfoStream InfoStream
-        {
-            get { return infoStream; }
-            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
-        }
-
-        /// <summary>
-        /// Constructor with the given index directory and callback to notify when the
-        /// indexes were updated.
-        /// </summary>
-        public IndexReplicationHandler(Directory indexDirectory, Func<bool?> callback)
-        {
-            this.InfoStream = InfoStream.Default;
-            this.callback = callback;
-            this.indexDirectory = indexDirectory;
-
-            CurrentVersion = null;
-            CurrentRevisionFiles = null;
-
-            if (DirectoryReader.IndexExists(indexDirectory))
-            {
-                IList<IndexCommit> commits = DirectoryReader.ListCommits(indexDirectory);
-                IndexCommit commit = commits.Last();
-
-                CurrentVersion = IndexRevision.RevisionVersion(commit);
-                CurrentRevisionFiles = IndexRevision.RevisionFiles(commit);
-
-                WriteToInfoStream(
-                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles),
-                    string.Format("constructor(): commit={0}", commit));
-            }
-        }
-
-        public void RevisionReady(string version, 
-            IDictionary<string, IList<RevisionFile>> revisionFiles, 
-            IDictionary<string, IList<string>> copiedFiles, 
-            IDictionary<string, Directory> sourceDirectory)
-        {
-            if (revisionFiles.Count > 1) throw new ArgumentException(string.Format("this handler handles only a single source; got {0}", revisionFiles.Keys));
-
-            Directory clientDirectory = sourceDirectory.Values.First();
-            IList<string> files = copiedFiles.Values.First();
-            string segmentsFile = GetSegmentsFile(files, false);
-
-            bool success = false;
-            try
-            {
-                // copy files from the client to index directory
-                 CopyFiles(clientDirectory, indexDirectory, files);
-
-                // fsync all copied files (except segmentsFile)
-                indexDirectory.Sync(files);
-
-                // now copy and fsync segmentsFile
-                clientDirectory.Copy(indexDirectory, segmentsFile, segmentsFile, IOContext.READ_ONCE);
-                indexDirectory.Sync(new[] { segmentsFile });
-                
-                success = true;
-            }
-            finally
-            {
-                if (!success)
-                {
-                    files.Add(segmentsFile); // add it back so it gets deleted too
-                    CleanupFilesOnFailure(indexDirectory, files);
-                }
-            }
-            
-            // all files have been successfully copied + sync'd. update the handler's state
-            CurrentRevisionFiles = revisionFiles;
-            CurrentVersion = version;
-            
-            WriteToInfoStream(string.Format("revisionReady(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles));
-
-            // update the segments.gen file
-            WriteSegmentsGen(segmentsFile, indexDirectory);
-
-            // Cleanup the index directory from old and unused index files.
-            // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
-            // side-effects, e.g. if it hits sudden IO errors while opening the index
-            // (and can end up deleting the entire index). It is not our job to protect
-            // against those errors, app will probably hit them elsewhere.
-            CleanupOldIndexFiles(indexDirectory, segmentsFile);
-            
-            // successfully updated the index, notify the callback that the index is
-            // ready.
-            if (callback != null) {
-              try {
-                callback.Invoke();
-              } catch (Exception e) {
-                throw new IOException(e.Message, e);
-              }
-            }           
-        }
-
         //Note: LUCENENET Specific Utility Method
         private void WriteToInfoStream(params string[] messages)
         {
@@ -171,7 +71,7 @@ namespace Lucene.Net.Replicator
 
         /// <summary>
         /// Returns the last <see cref="IndexCommit"/> found in the <see cref="Directory"/>, or
-        /// <code>null</code> if there are no commits.
+        /// <c>null</c> if there are no commits.
         /// </summary>
         /// <exception cref="IOException"></exception>
         public static IndexCommit GetLastCommit(Directory directory)
@@ -196,10 +96,9 @@ namespace Lucene.Net.Replicator
         /// last, after all files. This is important in order to guarantee that if a
         /// reader sees the new segments_N, all other segment files are already on
         /// stable storage.
-        /// <para>
+        /// <para/>
         /// The reason why the code fails instead of putting segments_N file last is
-        /// that this indicates an error in the Revision implementation.
-        /// </para>
+        /// that this indicates an error in the <see cref="IRevision"/> implementation.
         /// </summary>
         public static string GetSegmentsFile(IList<string> files, bool allowEmpty)
         {
@@ -241,6 +140,17 @@ namespace Lucene.Net.Replicator
             }
         }
 
+        /// <summary>
+        /// Cleans up the index directory from old index files. This method uses the
+        /// last commit found by <see cref="GetLastCommit(Directory)"/>. If it matches the
+        /// expected <paramref name="segmentsFile"/>, then all files not referenced by this commit point
+        /// are deleted.
+        /// </summary>
+        /// <remarks>
+        /// <b>NOTE:</b> This method does a best effort attempt to clean the index
+        /// directory. It suppresses any exceptions that occur, as this can be retried
+        /// the next time.
+        /// </remarks>
         public static void CleanupOldIndexFiles(Directory directory, string segmentsFile)
         {
             try
@@ -280,7 +190,8 @@ namespace Lucene.Net.Replicator
         }
 
         /// <summary>
-        /// Copies the provided list of files from the <see cref="source"/> <see cref="Directory"/> to the <see cref="target"/> <see cref="Directory"/>.
+        /// Copies the provided list of files from the <paramref name="source"/> <see cref="Directory"/> to the 
+        /// <paramref name="target"/> <see cref="Directory"/>, if they are not the same.
         /// </summary>
         /// <exception cref="IOException"></exception>
         public static void CopyFiles(Directory source, Directory target, IList<string> files)
@@ -294,7 +205,7 @@ namespace Lucene.Net.Replicator
 
         /// <summary>
         /// Writes <see cref="IndexFileNames.SEGMENTS_GEN"/> file to the directory, reading
-        /// the generation from the given <code>segmentsFile</code>. If it is <code>null</code>,
+        /// the generation from the given <paramref name="segmentsFile"/>. If it is <c>null</c>,
         /// this method deletes segments.gen from the directory.
         /// </summary>
         public static void WriteSegmentsGen(string segmentsFile, Directory directory)
@@ -314,5 +225,111 @@ namespace Lucene.Net.Replicator
                 // suppress any errors while deleting this file.
             }
         }
+
+        /// <summary>
+        /// Constructor with the given index directory and callback to notify when the
+        /// indexes were updated.
+        /// </summary>
+        public IndexReplicationHandler(Directory indexDirectory, Func<bool?> callback) // LUCENENET TODO: API - shouldn't this be Action ?
+        {
+            this.InfoStream = InfoStream.Default;
+            this.callback = callback;
+            this.indexDirectory = indexDirectory;
+
+            CurrentVersion = null;
+            CurrentRevisionFiles = null;
+
+            if (DirectoryReader.IndexExists(indexDirectory))
+            {
+                IList<IndexCommit> commits = DirectoryReader.ListCommits(indexDirectory);
+                IndexCommit commit = commits.Last();
+
+                CurrentVersion = IndexRevision.RevisionVersion(commit);
+                CurrentRevisionFiles = IndexRevision.RevisionFiles(commit);
+
+                WriteToInfoStream(
+                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles),
+                    string.Format("constructor(): commit={0}", commit));
+            }
+        }
+
+        public string CurrentVersion { get; private set; }
+
+        public IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; private set; }
+
+        public void RevisionReady(string version,
+            IDictionary<string, IList<RevisionFile>> revisionFiles,
+            IDictionary<string, IList<string>> copiedFiles,
+            IDictionary<string, Directory> sourceDirectory)
+        {
+            if (revisionFiles.Count > 1) throw new ArgumentException(string.Format("this handler handles only a single source; got {0}", revisionFiles.Keys));
+
+            Directory clientDirectory = sourceDirectory.Values.First();
+            IList<string> files = copiedFiles.Values.First();
+            string segmentsFile = GetSegmentsFile(files, false);
+
+            bool success = false;
+            try
+            {
+                // copy files from the client to index directory
+                CopyFiles(clientDirectory, indexDirectory, files);
+
+                // fsync all copied files (except segmentsFile)
+                indexDirectory.Sync(files);
+
+                // now copy and fsync segmentsFile
+                clientDirectory.Copy(indexDirectory, segmentsFile, segmentsFile, IOContext.READ_ONCE);
+                indexDirectory.Sync(new[] { segmentsFile });
+
+                success = true;
+            }
+            finally
+            {
+                if (!success)
+                {
+                    files.Add(segmentsFile); // add it back so it gets deleted too
+                    CleanupFilesOnFailure(indexDirectory, files);
+                }
+            }
+
+            // all files have been successfully copied + sync'd. update the handler's state
+            CurrentRevisionFiles = revisionFiles;
+            CurrentVersion = version;
+
+            WriteToInfoStream(string.Format("revisionReady(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles));
+
+            // update the segments.gen file
+            WriteSegmentsGen(segmentsFile, indexDirectory);
+
+            // Cleanup the index directory from old and unused index files.
+            // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
+            // side-effects, e.g. if it hits sudden IO errors while opening the index
+            // (and can end up deleting the entire index). It is not our job to protect
+            // against those errors, app will probably hit them elsewhere.
+            CleanupOldIndexFiles(indexDirectory, segmentsFile);
+
+            // successfully updated the index, notify the callback that the index is
+            // ready.
+            if (callback != null)
+            {
+                try
+                {
+                    callback.Invoke();
+                }
+                catch (Exception e)
+                {
+                    throw new IOException(e.ToString(), e);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages.
+        /// </summary>
+        public InfoStream InfoStream
+        {
+            get { return infoStream; }
+            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
+        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/IndexRevision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexRevision.cs b/src/Lucene.Net.Replicator/IndexRevision.cs
index 5708bf1..29ea77c 100644
--- a/src/Lucene.Net.Replicator/IndexRevision.cs
+++ b/src/Lucene.Net.Replicator/IndexRevision.cs
@@ -1,5 +1,3 @@
-//STATUS: DRAFT - 4.8.0
-
 using System;
 using System.IO;
 using System.Collections.Generic;
@@ -37,14 +35,13 @@ namespace Lucene.Net.Replicator
     /// <see cref="SnapshotDeletionPolicy"/> (this means that the given writer's
     /// <see cref="IndexWriterConfig.IndexDeletionPolicy"/> should return
     /// <see cref="SnapshotDeletionPolicy"/>).
-    /// <p>
-    /// When this revision is <see cref="Release"/>d, it releases the obtained
+    /// <para/>
+    /// When this revision is <see cref="Release()"/>d, it releases the obtained
     /// snapshot as well as calls <see cref="IndexWriter.DeleteUnusedFiles"/> so that the
     /// snapshotted files are deleted (if they are no longer needed).
-    /// </p>
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public class IndexRevision : IRevision
     {
@@ -54,9 +51,45 @@ namespace Lucene.Net.Replicator
         private readonly IndexCommit commit;
         private readonly SnapshotDeletionPolicy sdp;
 
-        public string Version { get; private set; }
         public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
 
+        // returns a RevisionFile with some metadata
+        private static RevisionFile CreateRevisionFile(string fileName, Directory directory)
+        {
+            return new RevisionFile(fileName, directory.FileLength(fileName));
+        }
+
+        /// <summary>
+        /// Returns a singleton map of the revision files from the given <see cref="IndexCommit"/>.
+        /// </summary>
+        public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit commit)
+        {
+            List<RevisionFile> revisionFiles = commit.FileNames
+                .Where(file => !string.Equals(file, commit.SegmentsFileName))
+                .Select(file => CreateRevisionFile(file, commit.Directory))
+                //Note: segments_N must be last
+                .Union(new[] {CreateRevisionFile(commit.SegmentsFileName, commit.Directory)})
+                .ToList();
+            return new Dictionary<string, IList<RevisionFile>>
+            {
+                { SOURCE, revisionFiles }
+            };
+        }
+   
+        /// <summary>
+        /// Returns a string representation of a revision's version from the given 
+        /// <see cref="IndexCommit"/>
+        /// </summary>
+        public static string RevisionVersion(IndexCommit commit)
+        {
+            return commit.Generation.ToString("X");
+        }
+
+        /// <summary>
+        /// Constructor over the given <see cref="IndexWriter"/>. Uses the last
+        /// <see cref="IndexCommit"/> found in the <see cref="Directory"/> managed by the given
+        /// writer.
+        /// </summary>
         public IndexRevision(IndexWriter writer)
         {
             sdp = writer.Config.IndexDeletionPolicy as SnapshotDeletionPolicy;
@@ -86,6 +119,8 @@ namespace Lucene.Net.Replicator
             return commit.CompareTo(or.commit);
         }
 
+        public string Version { get; private set; }
+
         public Stream Open(string source, string fileName)
         {
             Debug.Assert(source.Equals(SOURCE), string.Format("invalid source; expected={0} got={1}", SOURCE, source));
@@ -102,36 +137,5 @@ namespace Lucene.Net.Replicator
         {
             return "IndexRevision version=" + Version + " files=" + SourceFiles;
         }
-
-        // returns a RevisionFile with some metadata
-        private static RevisionFile CreateRevisionFile(string fileName, Directory directory)
-        {
-            return new RevisionFile(fileName, directory.FileLength(fileName));
-        }
-
-        /** Returns a singleton map of the revision files from the given {@link IndexCommit}. */
-        public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit commit)
-        {
-            List<RevisionFile> revisionFiles = commit.FileNames
-                .Where(file => !string.Equals(file, commit.SegmentsFileName))
-                .Select(file => CreateRevisionFile(file, commit.Directory))
-                //Note: segments_N must be last
-                .Union(new[] {CreateRevisionFile(commit.SegmentsFileName, commit.Directory)})
-                .ToList();
-            return new Dictionary<string, IList<RevisionFile>>
-            {
-                { SOURCE, revisionFiles }
-            };
-        }
-   
-        /// <summary>
-        /// Returns a String representation of a revision's version from the given <see cref="IndexCommit"/>
-        /// </summary>
-        /// <param name="commit"></param>
-        /// <returns></returns>
-        public static string RevisionVersion(IndexCommit commit)
-        {
-            return commit.Generation.ToString("X");
-        }
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/LocalReplicator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/LocalReplicator.cs b/src/Lucene.Net.Replicator/LocalReplicator.cs
index c32f8b7..981eecb 100644
--- a/src/Lucene.Net.Replicator/LocalReplicator.cs
+++ b/src/Lucene.Net.Replicator/LocalReplicator.cs
@@ -1,12 +1,9 @@
-//STATUS: DRAFT - 4.8.0
-
+using Lucene.Net.Support;
 using System;
 using System.Collections.Generic;
-using System.ComponentModel;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
-using Lucene.Net.Support;
 
 namespace Lucene.Net.Replicator
 {
@@ -34,159 +31,104 @@ namespace Lucene.Net.Replicator
     /// <see cref="SessionToken"/> through which it can
     /// <see cref="ObtainFile"/> the files of that
     /// revision. As long as a revision is being replicated, this replicator
-    /// guarantees that it will not be <seealso cref="IRevision.Release"/>.
-    /// <para>
+    /// guarantees that it will not be <see cref="IRevision.Release"/>.
+    /// <para/>
     /// Replication sessions expire by default after
-    /// <seealso cref="DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>, and the threshold can be
-    /// configured through <seealso cref="ExpirationThreshold"/>.
-    /// </para>
+    /// <seea cref="DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>, and the threshold can be
+    /// configured through <see cref="ExpirationThreshold"/>.
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public class LocalReplicator : IReplicator
     {
-        /// <summary>Threshold for expiring inactive sessions. Defaults to 30 minutes.</summary>
-        public const long DEFAULT_SESSION_EXPIRATION_THRESHOLD = 1000 * 60 * 30;
-
-        private long expirationThreshold = DEFAULT_SESSION_EXPIRATION_THRESHOLD;
-        private readonly object padlock = new object();
-        private volatile RefCountedRevision currentRevision;
-        private volatile bool disposed = false;
+        private class RefCountedRevision
+        {
+            private readonly AtomicInt32 refCount = new AtomicInt32(1);
 
-        private readonly AtomicInt32 sessionToken = new AtomicInt32(0);
-        private readonly Dictionary<string, ReplicationSession> sessions = new Dictionary<string, ReplicationSession>();
+            public IRevision Revision { get; private set; }
 
-        /// <summary>
-        /// Returns the expiration threshold.
-        /// </summary>
-        public long ExpirationThreshold
-        {
-            get { return expirationThreshold; }
-            set
+            public RefCountedRevision(IRevision revision)
             {
-                lock (padlock)
-                {
-                    EnsureOpen();
-                    expirationThreshold = value;
-                    CheckExpiredSessions();
-                }
+                Revision = revision;
             }
-        }
 
-        public void Publish(IRevision revision)
-        {
-            lock (padlock)
+            /// <summary/>
+            /// <exception cref="InvalidOperationException"></exception>
+            public void DecRef()
             {
-                EnsureOpen();
+                if (refCount.Get() <= 0)
+                {
+                    throw new InvalidOperationException("this revision is already released");
+                }
 
-                if (currentRevision != null)
+                var rc = refCount.DecrementAndGet();
+                if (rc == 0)
                 {
-                    int compare = revision.CompareTo(currentRevision.Revision);
-                    if (compare == 0)
+                    bool success = false;
+                    try
                     {
-                        // same revision published again, ignore but release it
-                        revision.Release();
-                        return;
+                        Revision.Release();
+                        success = true;
                     }
-
-                    if (compare < 0)
+                    finally
                     {
-                        revision.Release();
-                        throw new ArgumentException(string.Format("Cannot publish an older revision: rev={0} current={1}", revision, currentRevision), "revision");
+                        if (!success)
+                        {
+                            // Put reference back on failure
+                            refCount.IncrementAndGet();
+                        }
                     }
                 }
+                else if (rc < 0)
+                {
+                    throw new InvalidOperationException(string.Format("too many decRef calls: refCount is {0} after decrement", rc));
+                }
+            }
 
-                RefCountedRevision oldRevision = currentRevision;
-                currentRevision = new RefCountedRevision(revision);
-                if(oldRevision != null) 
-                    oldRevision.DecRef();
-
-                CheckExpiredSessions();
+            public void IncRef()
+            {
+                refCount.IncrementAndGet();
             }
         }
 
-        /// <summary>
-        /// TODO
-        /// </summary>
-        /// <returns></returns>
-        public SessionToken CheckForUpdate(string currentVersion)
+        private class ReplicationSession
         {
-            lock (padlock)
-            {
-                EnsureOpen();
-                if (currentRevision == null)
-                    return null; // no published revisions yet
-
-                if (currentVersion != null && currentRevision.Revision.CompareTo(currentVersion) <= 0)
-                    return null; // currentVersion is newer or equal to latest published revision
+            public SessionToken Session { get; private set; }
+            public RefCountedRevision Revision { get; private set; }
 
-                // currentVersion is either null or older than latest published revision
-                currentRevision.IncRef();
+            private long lastAccessTime;
 
-                string sessionID = sessionToken.IncrementAndGet().ToString();
-                SessionToken token = new SessionToken(sessionID, currentRevision.Revision);
-                sessions[sessionID] = new ReplicationSession(token, currentRevision);
-                return token;
+            public ReplicationSession(SessionToken session, RefCountedRevision revision)
+            {
+                Session = session;
+                Revision = revision;
+                lastAccessTime = Stopwatch.GetTimestamp();
             }
 
-        }
+            public bool IsExpired(long expirationThreshold)
+            {
+                return lastAccessTime < Stopwatch.GetTimestamp() - expirationThreshold * Stopwatch.Frequency / 1000; // LUCENENET TODO: CurrentTimeMilliseconds()
+            }
 
-        /// <summary>
-        /// TODO
-        /// </summary>
-        /// <exception cref="InvalidOperationException"></exception>
-        public void Release(string sessionId)
-        {
-            lock (padlock)
+            public void MarkAccessed()
             {
-                EnsureOpen();
-                ReleaseSession(sessionId);
+                lastAccessTime = Stopwatch.GetTimestamp(); // LUCENENET TODO: CurrentTimeMilliseconds()
             }
         }
 
-        /// <summary>
-        /// TODO
-        /// </summary>
-        public Stream ObtainFile(string sessionId, string source, string fileName)
-        {
-            lock (padlock)
-            {
-                EnsureOpen();
+        /// <summary>Threshold for expiring inactive sessions. Defaults to 30 minutes.</summary>
+        public const long DEFAULT_SESSION_EXPIRATION_THRESHOLD = 1000 * 60 * 30;
 
-                ReplicationSession session = sessions[sessionId];
-                if (session != null && session.IsExpired(ExpirationThreshold))
-                {
-                    ReleaseSession(sessionId);
-                    session = null;
-                }
-                // session either previously expired, or we just expired it
-                if (session == null)
-                {
-                    throw new SessionExpiredException(string.Format("session ({0}) expired while obtaining file: source={1} file={2}", sessionId, source, fileName));
-                }
-                sessions[sessionId].MarkAccessed();
-                return session.Revision.Revision.Open(source, fileName);
-            }
+        private long expirationThreshold = DEFAULT_SESSION_EXPIRATION_THRESHOLD;
 
-        }
+        private readonly object padlock = new object();
 
-        /// <summary>
-        /// TODO
-        /// </summary>
-        public void Dispose()
-        {
-            if (disposed)
-                return;
+        private volatile RefCountedRevision currentRevision;
+        private volatile bool disposed = false;
 
-            lock (padlock)
-            {
-                foreach (ReplicationSession session in sessions.Values)
-                    session.Revision.DecRef();
-                sessions.Clear();
-            }
-            disposed = true;
-        }
+        private readonly AtomicInt32 sessionToken = new AtomicInt32(0);
+        private readonly IDictionary<string, ReplicationSession> sessions = new Dictionary<string, ReplicationSession>();
 
         /// <exception cref="InvalidOperationException"></exception>
         private void CheckExpiredSessions()
@@ -215,7 +157,7 @@ namespace Lucene.Net.Replicator
         /// <summary>
         /// Ensure that replicator is still open, or throw <see cref="ObjectDisposedException"/> otherwise.
         /// </summary>
-        /// <exception cref="ObjectDisposedException">This replicator has already been closed</exception>
+        /// <exception cref="ObjectDisposedException">This replicator has already been disposed.</exception>
         protected void EnsureOpen()
         {
             lock (padlock)
@@ -227,80 +169,124 @@ namespace Lucene.Net.Replicator
             }
         }
 
-        private class RefCountedRevision
+        public SessionToken CheckForUpdate(string currentVersion)
         {
-            private readonly AtomicInt32 refCount = new AtomicInt32(1);
+            lock (padlock)
+            {
+                EnsureOpen();
+                if (currentRevision == null)
+                    return null; // no published revisions yet
 
-            public IRevision Revision { get; private set; }
+                if (currentVersion != null && currentRevision.Revision.CompareTo(currentVersion) <= 0)
+                    return null; // currentVersion is newer or equal to latest published revision
 
-            public RefCountedRevision(IRevision revision)
+                // currentVersion is either null or older than latest published revision
+                currentRevision.IncRef();
+
+                string sessionID = sessionToken.IncrementAndGet().ToString();
+                SessionToken token = new SessionToken(sessionID, currentRevision.Revision);
+                sessions[sessionID] = new ReplicationSession(token, currentRevision);
+                return token;
+            }
+        }
+
+        public void Dispose() // LUCENENET TODO: API Dispose pattern
+        {
+            if (disposed)
+                return;
+
+            lock (padlock)
             {
-                Revision = revision;
+                foreach (ReplicationSession session in sessions.Values)
+                    session.Revision.DecRef();
+                sessions.Clear();
             }
+            disposed = true;
+        }
 
-            /// <summary/>
-            /// <exception cref="InvalidOperationException"></exception>
-            public void DecRef()
+        /// <summary>
+        /// Gets or sets the expiration threshold.
+        /// <para/>
+        /// If a replication session is inactive this
+        /// long it is automatically expired, and further attempts to operate within
+        /// this session will throw a <see cref="SessionExpiredException"/>.
+        /// </summary>
+        public long ExpirationThreshold
+        {
+            get { return expirationThreshold; }
+            set
             {
-                if (refCount.Get() <= 0)
+                lock (padlock)
                 {
-                    throw new InvalidOperationException("this revision is already released");
+                    EnsureOpen();
+                    expirationThreshold = value;
+                    CheckExpiredSessions();
                 }
+            }
+        }
 
-                var rc = refCount.DecrementAndGet();
-                if (rc == 0)
+        public Stream ObtainFile(string sessionId, string source, string fileName)
+        {
+            lock (padlock)
+            {
+                EnsureOpen();
+
+                ReplicationSession session = sessions[sessionId];
+                if (session != null && session.IsExpired(ExpirationThreshold))
                 {
-                    bool success = false;
-                    try
-                    {
-                        Revision.Release();
-                        success = true;
-                    }
-                    finally
-                    {
-                        if (!success)
-                        {
-                            // Put reference back on failure
-                            refCount.IncrementAndGet();
-                        }
-                    }
+                    ReleaseSession(sessionId);
+                    session = null;
                 }
-                else if (rc < 0)
+                // session either previously expired, or we just expired it
+                if (session == null)
                 {
-                    throw new InvalidOperationException(string.Format("too many decRef calls: refCount is {0} after decrement", rc));
+                    throw new SessionExpiredException(string.Format("session ({0}) expired while obtaining file: source={1} file={2}", sessionId, source, fileName));
                 }
+                sessions[sessionId].MarkAccessed();
+                return session.Revision.Revision.Open(source, fileName);
             }
-
-            public void IncRef()
-            {
-                refCount.IncrementAndGet();
-            }       
         }
 
-        private class ReplicationSession
+        public void Publish(IRevision revision)
         {
-            public SessionToken Session { get; private set; }
-            public RefCountedRevision Revision { get; private set; }
+            lock (padlock)
+            {
+                EnsureOpen();
 
-            private long lastAccessTime;
+                if (currentRevision != null)
+                {
+                    int compare = revision.CompareTo(currentRevision.Revision);
+                    if (compare == 0)
+                    {
+                        // same revision published again, ignore but release it
+                        revision.Release();
+                        return;
+                    }
 
-            public ReplicationSession(SessionToken session, RefCountedRevision revision)
-            {
-                Session = session;
-                Revision = revision;
-                lastAccessTime = Stopwatch.GetTimestamp();
-            }
+                    if (compare < 0)
+                    {
+                        revision.Release();
+                        throw new ArgumentException(string.Format("Cannot publish an older revision: rev={0} current={1}", revision, currentRevision), "revision");
+                    }
+                }
 
-            public bool IsExpired(long expirationThreshold)
-            {
-                return lastAccessTime < Stopwatch.GetTimestamp() - expirationThreshold * Stopwatch.Frequency / 1000;
+                RefCountedRevision oldRevision = currentRevision;
+                currentRevision = new RefCountedRevision(revision);
+                if (oldRevision != null)
+                    oldRevision.DecRef();
+
+                CheckExpiredSessions();
             }
+        }
 
-            public void MarkAccessed()
+        /// <exception cref="InvalidOperationException"></exception>
+        public void Release(string sessionId)
+        {
+            lock (padlock)
             {
-                lastAccessTime = Stopwatch.GetTimestamp();
+                EnsureOpen();
+                ReleaseSession(sessionId);
             }
         }
-
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
index 1b0b90f..5efeb74 100644
--- a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
+++ b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
@@ -49,6 +49,9 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup>
+    <DefineConstants>$(DefineConstants);FEATURE_SERIALIZABLE</DefineConstants>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
       <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
@@ -74,8 +77,6 @@
     <Compile Include="IndexInputInputStream.cs" />
     <Compile Include="IndexReplicationHandler.cs" />
     <Compile Include="IndexRevision.cs" />
-    <Compile Include="IReplicationHandler.cs" />
-    <Compile Include="ISourceDirectoryFactory.cs" />
     <Compile Include="LocalReplicator.cs" />
     <Compile Include="PerSessionDirectoryFactory.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
@@ -87,9 +88,6 @@
     <Compile Include="SessionToken.cs" />
   </ItemGroup>
   <ItemGroup>
-    <Content Include="Http\package.html" />
-  </ItemGroup>
-  <ItemGroup>
     <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
       <Project>{48f7884a-9454-4e88-8413-9d35992cb440}</Project>
       <Name>Lucene.Net.Facet</Name>

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/67882465/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs b/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
index e65c8cb..3661f71 100644
--- a/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
+++ b/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
@@ -28,13 +28,13 @@ namespace Lucene.Net.Replicator
     /// deleted.
     /// </summary>
     /// <remarks>
-    /// Lucene.Experimental
+    /// @lucene.experimental
     /// </remarks>
     public class PerSessionDirectoryFactory : ISourceDirectoryFactory
     {
         private readonly string workingDirectory;
 
-        /** Constructor with the given sources mapping. */
+        /// <summary>Constructor with the given sources mapping.</summary>
         public PerSessionDirectoryFactory(string workingDirectory)
         {
             this.workingDirectory = workingDirectory;


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

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
new file mode 100644
index 0000000..9481bd4
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+
+ 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.
+
+-->
+<Project ToolsVersion="12.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>{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Replicator</RootNamespace>
+    <AssemblyName>Lucene.Net.Replicator</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="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <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="ComponentWrapperInfoStream.cs" />
+    <Compile Include="Http\EnumerableExtensions.cs" />
+    <Compile Include="Http\HttpClientBase.cs" />
+    <Compile Include="Http\HttpReplicator.cs" />
+    <Compile Include="Http\Abstractions\IReplicationRequest.cs" />
+    <Compile Include="Http\Abstractions\IReplicationResponse.cs" />
+    <Compile Include="Http\ReplicationService.cs" />
+    <Compile Include="IndexAndTaxonomyReplicationHandler.cs" />
+    <Compile Include="IndexAndTaxonomyRevision.cs" />
+    <Compile Include="IndexInputInputStream.cs" />
+    <Compile Include="IndexReplicationHandler.cs" />
+    <Compile Include="IndexRevision.cs" />
+    <Compile Include="IReplicationHandler.cs" />
+    <Compile Include="ISourceDirectoryFactory.cs" />
+    <Compile Include="LocalReplicator.cs" />
+    <Compile Include="PerSessionDirectoryFactory.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ReplicationClient.cs" />
+    <Compile Include="Replicator.cs" />
+    <Compile Include="Revision.cs" />
+    <Compile Include="RevisionFile.cs" />
+    <Compile Include="SessionExpiredException.cs" />
+    <Compile Include="SessionToken.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Http\package.html" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
+      <Project>{48f7884a-9454-4e88-8413-9d35992cb440}</Project>
+      <Name>Lucene.Net.Facet</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net\Lucene.Net.csproj">
+      <Project>{5d4ad9be-1ffb-41ab-9943-25737971bf57}</Project>
+      <Name>Lucene.Net</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs b/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
new file mode 100644
index 0000000..e7f1d80
--- /dev/null
+++ b/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
@@ -0,0 +1,96 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.IO;
+using Lucene.Net.Store;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 <see cref="ISourceDirectoryFactory"/> which returns <see cref="FSDirectory"/> under a
+    /// dedicated session directory. When a session is over, the entire directory is
+    /// deleted.
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public class PerSessionDirectoryFactory : ISourceDirectoryFactory
+    {
+        #region Java
+        //JAVA: private final File workDir;
+        #endregion
+        private readonly string workingDirectory;
+
+        /** Constructor with the given sources mapping. */
+        public PerSessionDirectoryFactory(string workingDirectory)
+        {
+            this.workingDirectory = workingDirectory;
+        }
+
+        public Directory GetDirectory(string sessionId, string source)
+        {
+            #region Java
+            //JAVA: public Directory getDirectory(String sessionID, String source) throws IOException {
+            //JAVA:   File sessionDir = new File(workDir, sessionID);
+            //JAVA:   if (!sessionDir.exists() && !sessionDir.mkdirs()) {
+            //JAVA:     throw new IOException("failed to create session directory " + sessionDir);
+            //JAVA:   }
+            //JAVA:   File sourceDir = new File(sessionDir, source);
+            //JAVA:   if (!sourceDir.mkdirs()) {
+            //JAVA:     throw new IOException("failed to create source directory " + sourceDir);
+            //JAVA:   }
+            //JAVA:   return FSDirectory.open(sourceDir);
+            //JAVA: }
+            #endregion
+
+            string sourceDirectory = Path.Combine(workingDirectory, sessionId, source);
+            System.IO.Directory.CreateDirectory(sourceDirectory);
+            return FSDirectory.Open(sourceDirectory);
+        }
+
+        public void CleanupSession(string sessionId)
+        {
+            if (string.IsNullOrEmpty(sessionId)) throw new ArgumentException("sessionID cannot be empty", "sessionId");
+
+            #region Java
+            //JAVA: rm(new File(workDir, sessionID));
+            #endregion
+
+            string sessionDirectory = Path.Combine(workingDirectory, sessionId);
+            System.IO.Directory.Delete(sessionDirectory, true);
+        }
+
+        #region Java
+        //JAVA: private void rm(File file) throws IOException {
+        //JAVA:   if (file.isDirectory()) {
+        //JAVA:     for (File f : file.listFiles()) {
+        //JAVA:       rm(f);
+        //JAVA:     }
+        //JAVA:   }
+        //JAVA:   
+        //JAVA:   // This should be either an empty directory, or a file
+        //JAVA:   if (!file.delete() && file.exists()) {
+        //JAVA:     throw new IOException("failed to delete " + file);
+        //JAVA:   }
+        //JAVA: }
+        #endregion
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs b/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..898ca18
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
@@ -0,0 +1,24 @@
+using System;
+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")]
+[assembly: AssemblyDescription("Replicator that allows replication of Lucene.Net files between a server and client(s) " +
+                               "for the Lucene.Net full - text search engine library from The Apache Software Foundation.")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyDefaultAlias("Lucene.Net.Replicator")]
+[assembly: AssemblyCulture("")]
+
+[assembly: CLSCompliant(true)]
+
+// 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("1f70d2db-c1b3-4f78-9598-3e04e0c7eb06")]

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/ReplicationClient.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/ReplicationClient.cs b/src/Lucene.Net.Replicator/ReplicationClient.cs
new file mode 100644
index 0000000..63837c9
--- /dev/null
+++ b/src/Lucene.Net.Replicator/ReplicationClient.cs
@@ -0,0 +1,673 @@
+//STATUS: DRAFT - 4.8.0
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using Lucene.Net.Store;
+using Lucene.Net.Support;
+using Lucene.Net.Support.Threading;
+using Lucene.Net.Util;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 client which monitors and obtains new revisions from a <see cref="IReplicator"/>.
+    /// It can be used to either periodically check for updates by invoking
+    /// <see cref="StartUpdateThread"/>, or manually by calling <see cref="UpdateNow"/>.
+    /// <para>
+    /// Whenever a new revision is available, the <see cref="RequiredFiles"/> are
+    /// copied to the <see cref="Directory"/> specified by <see cref="PerSessionDirectoryFactory"/> and
+    /// a handler is notified.
+    /// </para>
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public partial class ReplicationClient : IDisposable
+    {
+        /// <summary>
+        /// The component name to use with <see cref="Util.InfoStream.IsEnabled"/>
+        /// </summary>
+        public const string INFO_STREAM_COMPONENT = "ReplicationThread";
+
+        /// <summary> Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages. </summary>
+        public InfoStream InfoStream
+        {
+            get { return infoStream; }
+            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
+        }
+
+        private readonly IReplicator replicator;
+        private readonly IReplicationHandler handler;
+        private readonly ISourceDirectoryFactory factory;
+
+        private readonly byte[] copyBuffer = new byte[16384];
+        private readonly ReentrantLock updateLock = new ReentrantLock();
+
+        private ReplicationThread updateThread;
+        private bool disposed = false;
+        private InfoStream infoStream = InfoStream.Default;
+
+        /// <summary>
+        /// Constructor.
+        /// </summary>
+        /// <param name="replicator">The <see cref="IReplicator"/> used for checking for updates</param>
+        /// <param name="handler">The <see cref="IReplicationHandler"/> notified when new revisions are ready</param>
+        /// <param name="factory">The <see cref="ISourceDirectoryFactory"/> for returning a <see cref="Directory"/> for a given source and session</param>
+        public ReplicationClient(IReplicator replicator, IReplicationHandler handler, ISourceDirectoryFactory factory)
+        {
+            this.replicator = replicator;
+            this.handler = handler;
+            this.factory = factory;
+        }
+
+        /// <exception cref="IOException"></exception>
+        private void DoUpdate()
+        {
+            #region Java
+            //JAVA: private void doUpdate() throws IOException {
+            //JAVA:   SessionToken session = null;
+            //JAVA:   final Map<String,Directory> sourceDirectory = new HashMap<>();
+            //JAVA:   final Map<String,List<String>> copiedFiles = new HashMap<>();
+            //JAVA:   boolean notify = false;
+            //JAVA:   try {
+            //JAVA:     final String version = handler.currentVersion();
+            //JAVA:     session = replicator.checkForUpdate(version);
+            //JAVA:     if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
+            //JAVA:       infoStream.message(INFO_STREAM_COMPONENT, "doUpdate(): handlerVersion=" + version + " session=" + session);
+            //JAVA:     }
+            //JAVA:     if (session == null) {
+            //JAVA:       // already up to date
+            //JAVA:       return;
+            //JAVA:     }
+            //JAVA:     Map<String,List<RevisionFile>> requiredFiles = requiredFiles(session.sourceFiles);
+            //JAVA:     if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
+            //JAVA:       infoStream.message(INFO_STREAM_COMPONENT, "doUpdate(): requiredFiles=" + requiredFiles);
+            //JAVA:     }
+            //JAVA:     for (Entry<String,List<RevisionFile>> e : requiredFiles.entrySet()) {
+            //JAVA:       String source = e.getKey();
+            //JAVA:       Directory dir = factory.getDirectory(session.id, source);
+            //JAVA:       sourceDirectory.put(source, dir);
+            //JAVA:       List<String> cpFiles = new ArrayList<>();
+            //JAVA:       copiedFiles.put(source, cpFiles);
+            //JAVA:       for (RevisionFile file : e.getValue()) {
+            //JAVA:         if (closed) {
+            //JAVA:           // if we're closed, abort file copy
+            //JAVA:           if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
+            //JAVA:             infoStream.message(INFO_STREAM_COMPONENT, "doUpdate(): detected client was closed); abort file copy");
+            //JAVA:           }
+            //JAVA:           return;
+            //JAVA:         }
+            //JAVA:         InputStream in = null;
+            //JAVA:         IndexOutput out = null;
+            //JAVA:         try {
+            //JAVA:           in = replicator.obtainFile(session.id, source, file.fileName);
+            //JAVA:           out = dir.createOutput(file.fileName, IOContext.DEFAULT);
+            //JAVA:           copyBytes(out, in);
+            //JAVA:           cpFiles.add(file.fileName);
+            //JAVA:           // TODO add some validation, on size / checksum
+            //JAVA:         } finally {
+            //JAVA:           IOUtils.close(in, out);
+            //JAVA:         }
+            //JAVA:       }
+            //JAVA:     }
+            //JAVA:     // only notify if all required files were successfully obtained.
+            //JAVA:     notify = true;
+            //JAVA:   } finally {
+            //JAVA:     if (session != null) {
+            //JAVA:       try {
+            //JAVA:         replicator.release(session.id);
+            //JAVA:       } finally {
+            //JAVA:         if (!notify) { // cleanup after ourselves
+            //JAVA:           IOUtils.close(sourceDirectory.values());
+            //JAVA:           factory.cleanupSession(session.id);
+            //JAVA:         }
+            //JAVA:       }
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA:   
+            //JAVA:   // notify outside the try-finally above, so the session is released sooner.
+            //JAVA:   // the handler may take time to finish acting on the copied files, but the
+            //JAVA:   // session itself is no longer needed.
+            //JAVA:   try {
+            //JAVA:     if (notify && !closed ) { // no use to notify if we are closed already
+            //JAVA:       handler.revisionReady(session.version, session.sourceFiles, copiedFiles, sourceDirectory);
+            //JAVA:     }
+            //JAVA:   } finally {
+            //JAVA:     IOUtils.close(sourceDirectory.values());
+            //JAVA:     if (session != null) {
+            //JAVA:       factory.cleanupSession(session.id);
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            SessionToken session = null;
+            Dictionary<string, Directory> sourceDirectory = new Dictionary<string, Directory>();
+            Dictionary<string, IList<string>> copiedFiles = new Dictionary<string, IList<string>>();
+            bool notify = false;
+            try
+            {
+                string version = handler.CurrentVersion;
+                session = replicator.CheckForUpdate(version);
+
+                WriteToInfoStream(string.Format("doUpdate(): handlerVersion={0} session={1}", version, session));
+
+                if (session == null)
+                    return;
+
+                IDictionary<string, IList<RevisionFile>> requiredFiles = RequiredFiles(session.SourceFiles);
+                WriteToInfoStream(string.Format("doUpdate(): handlerVersion={0} session={1}", version, session));
+
+                foreach (KeyValuePair<string, IList<RevisionFile>> pair in requiredFiles)
+                {
+                    string source = pair.Key;
+                    Directory directory = factory.GetDirectory(session.Id, source);
+
+                    sourceDirectory.Add(source, directory);
+                    List<string> cpFiles = new List<string>();
+                    copiedFiles.Add(source, cpFiles);
+                    foreach (RevisionFile file in pair.Value)
+                    {
+                        if (disposed)
+                        {
+                            // if we're closed, abort file copy
+                            WriteToInfoStream("doUpdate(): detected client was closed); abort file copy");
+                            return;
+                        }
+
+                        Stream input = null;
+                        IndexOutput output = null;
+                        try
+                        {
+                            input = replicator.ObtainFile(session.Id, source, file.FileName);
+                            output = directory.CreateOutput(file.FileName, IOContext.DEFAULT);
+
+                            CopyBytes(output, input);
+                            
+                            cpFiles.Add(file.FileName);
+                            // TODO add some validation, on size / checksum
+                        }
+                        finally
+                        {
+                            IOUtils.Dispose(input, output);
+                        }
+                    }
+                    // only notify if all required files were successfully obtained.
+                    notify = true;
+                }
+            }
+            finally
+            {
+                if (session != null)
+                {
+                    try
+                    {
+                        replicator.Release(session.Id);
+                    }
+                    finally
+                    {
+                        if (!notify)
+                        { 
+                            // cleanup after ourselves
+                            IOUtils.Dispose(sourceDirectory.Values);
+                            factory.CleanupSession(session.Id);
+                        }
+                    }
+                }
+            }
+
+            // notify outside the try-finally above, so the session is released sooner.
+            // the handler may take time to finish acting on the copied files, but the
+            // session itself is no longer needed.
+            try
+            {
+                if (notify && !disposed)
+                { // no use to notify if we are closed already
+                    handler.RevisionReady(session.Version, session.SourceFiles, new ReadOnlyDictionary<string, IList<string>>(copiedFiles), sourceDirectory);
+                }
+            }
+            finally
+            {
+                IOUtils.Dispose(sourceDirectory.Values);
+                //TODO: Resharper Message, Expression is always true -> Verify and if so then we can remove the null check.
+                if (session != null)
+                {
+                    factory.CleanupSession(session.Id);
+                }
+            }
+
+        }
+
+        /// <exception cref="IOException"></exception>
+        private void CopyBytes(IndexOutput output, Stream input)
+        {
+            int numBytes;
+            while ((numBytes = input.Read(copyBuffer, 0, copyBuffer.Length)) > 0) {
+                output.WriteBytes(copyBuffer, 0, numBytes);
+            }
+        }
+
+        //.NET Note: Utility Method
+        private void WriteToInfoStream(string message)
+        {
+            if (infoStream.IsEnabled(INFO_STREAM_COMPONENT))
+                infoStream.Message(INFO_STREAM_COMPONENT, message);
+        }
+
+        /// <summary>
+        /// Returns the files required for replication. By default, this method returns
+        /// all files that exist in the new revision, but not in the handler.
+        /// </summary>
+        /// <param name="newRevisionFiles"></param>
+        /// <returns></returns>
+        private IDictionary<string, IList<RevisionFile>> RequiredFiles(IDictionary<string, IList<RevisionFile>> newRevisionFiles)
+        {
+            #region Java
+            //JAVA: protected Map<String,List<RevisionFile>> requiredFiles(Map<String,List<RevisionFile>> newRevisionFiles) {
+            //JAVA:   Map<String,List<RevisionFile>> handlerRevisionFiles = handler.currentRevisionFiles();
+            //JAVA:   if (handlerRevisionFiles == null) {
+            //JAVA:     return newRevisionFiles;
+            //JAVA:   }
+            //JAVA:   
+            //JAVA:   Map<String,List<RevisionFile>> requiredFiles = new HashMap<>();
+            //JAVA:   for (Entry<String,List<RevisionFile>> e : handlerRevisionFiles.entrySet()) {
+            //JAVA:     // put the handler files in a Set, for faster contains() checks later
+            //JAVA:     Set<String> handlerFiles = new HashSet<>();
+            //JAVA:     for (RevisionFile file : e.getValue()) {
+            //JAVA:       handlerFiles.add(file.fileName);
+            //JAVA:     }
+            //JAVA:     
+            //JAVA:     // make sure to preserve revisionFiles order
+            //JAVA:     ArrayList<RevisionFile> res = new ArrayList<>();
+            //JAVA:     String source = e.getKey();
+            //JAVA:     assert newRevisionFiles.containsKey(source) : "source not found in newRevisionFiles: " + newRevisionFiles;
+            //JAVA:     for (RevisionFile file : newRevisionFiles.get(source)) {
+            //JAVA:       if (!handlerFiles.contains(file.fileName)) {
+            //JAVA:         res.add(file);
+            //JAVA:       }
+            //JAVA:     }
+            //JAVA:     requiredFiles.put(source, res);
+            //JAVA:   }
+            //JAVA:   
+            //JAVA:   return requiredFiles;
+            //JAVA: }
+            #endregion
+
+            IDictionary<string, IList<RevisionFile>> handlerRevisionFiles = handler.CurrentRevisionFiles;
+            if (handlerRevisionFiles == null)
+                return newRevisionFiles;
+
+            Dictionary<string, IList<RevisionFile>> requiredFiles = new Dictionary<string, IList<RevisionFile>>();
+            foreach (KeyValuePair<string, IList<RevisionFile>> pair in handlerRevisionFiles)
+            {
+                // put the handler files in a Set, for faster contains() checks later
+                HashSet<string> handlerFiles = new HashSet<string>(pair.Value.Select(v => v.FileName));
+
+                // make sure to preserve revisionFiles order
+                string source = pair.Key;
+                Debug.Assert(newRevisionFiles.ContainsKey(source), string.Format("source not found in newRevisionFiles: {0}", newRevisionFiles));
+                List<RevisionFile> res = newRevisionFiles[source]
+                    .Where(file => !handlerFiles.Contains(file.FileName))
+                    .ToList();
+                requiredFiles.Add(source, res);
+            }
+            return requiredFiles;
+        }
+
+        /// <summary>
+        /// Start the update thread with the specified interval in milliseconds. For
+        /// debugging purposes, you can optionally set the name to set on
+        /// <see cref="ReplicationThread.Name"/>. If you pass <code>null</code>, a default name
+        /// will be set.
+        /// </summary>
+        /// <exception cref="InvalidOperationException"> if the thread has already been started </exception>
+        public void StartUpdateThread(long intervalMillis, string threadName)
+        {
+            #region Java
+            //JAVA: public synchronized void startUpdateThread(long intervalMillis, String threadName) {
+            //JAVA:   ensureOpen();
+            //JAVA:   if (updateThread != null && updateThread.isAlive()) {
+            //JAVA:     throw new IllegalStateException(
+            //JAVA:         "cannot start an update thread when one is running, must first call 'stopUpdateThread()'");
+            //JAVA:   }
+            //JAVA:   threadName = threadName == null ? INFO_STREAM_COMPONENT : "ReplicationThread-" + threadName;
+            //JAVA:   updateThread = new ReplicationThread(intervalMillis);
+            //JAVA:   updateThread.setName(threadName);
+            //JAVA:   updateThread.start();
+            //JAVA:   // we rely on isAlive to return true in isUpdateThreadAlive, assert to be on the safe side
+            //JAVA:   assert updateThread.isAlive() : "updateThread started but not alive?";
+            //JAVA: }
+            #endregion
+
+            EnsureOpen();
+            if (updateThread != null && updateThread.IsAlive)
+                throw new InvalidOperationException("cannot start an update thread when one is running, must first call 'stopUpdateThread()'");
+
+            threadName = threadName == null ? INFO_STREAM_COMPONENT : "ReplicationThread-" + threadName;
+            updateThread = new ReplicationThread(intervalMillis, threadName, DoUpdate, HandleUpdateException, updateLock);
+            updateThread.Start();
+            // we rely on isAlive to return true in isUpdateThreadAlive, assert to be on the safe side
+            Debug.Assert(updateThread.IsAlive, "updateThread started but not alive?");
+        }
+
+        /// <summary>
+        /// Stop the update thread. If the update thread is not running, silently does
+        /// nothing. This method returns after the update thread has stopped.
+        /// </summary>
+        public void StopUpdateThread()
+        {
+            #region Java
+            //JAVA: public synchronized void stopUpdateThread() {
+            //JAVA:   if (updateThread != null) {
+            //JAVA:     // this will trigger the thread to terminate if it awaits the lock.
+            //JAVA:     // otherwise, if it's in the middle of replication, we wait for it to
+            //JAVA:     // stop.
+            //JAVA:     updateThread.stop.countDown();
+            //JAVA:     try {
+            //JAVA:       updateThread.join();
+            //JAVA:     } catch (InterruptedException e) {
+            //JAVA:       Thread.currentThread().interrupt();
+            //JAVA:       throw new ThreadInterruptedException(e);
+            //JAVA:     }
+            //JAVA:     updateThread = null;
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            // this will trigger the thread to terminate if it awaits the lock.
+            // otherwise, if it's in the middle of replication, we wait for it to
+            // stop.
+            if (updateThread != null)
+                updateThread.Stop();
+            updateThread = null;
+        }
+
+        /// <summary>
+        /// Returns true if the update thread is alive. The update thread is alive if
+        /// it has been <see cref="StartUpdateThread"/> and not
+        /// <see cref="StopUpdateThread"/>, as well as didn't hit an error which
+        /// caused it to terminate (i.e. <see cref="HandleUpdateException"/>
+        /// threw the exception further).
+        /// </summary>
+        public bool IsUpdateThreadAlive
+        {
+            get { return updateThread != null && updateThread.IsAlive; }
+        }
+
+        /// <summary>Throws <see cref="ObjectDisposedException"/> if the client has already been disposed.</summary>
+        protected virtual void EnsureOpen()
+        {
+            if (!disposed)
+                return;
+
+            throw new ObjectDisposedException("this update client has already been closed");
+        }
+
+        /// <summary>
+        /// Called when an exception is hit by the replication thread. The default
+        /// implementation prints the full stacktrace to the <seealso cref="InfoStream"/> set in
+        /// <seealso cref="InfoStream"/>, or the <see cref="Util.InfoStream.Default"/>
+        /// one. You can override to log the exception elswhere.
+        /// </summary>
+        /// <remarks>
+        /// If you override this method to throw the exception further,
+        /// the replication thread will be terminated. The only way to restart it is to
+        /// call <seealso cref="StopUpdateThread"/> followed by
+        /// <seealso cref="StartUpdateThread"/>.
+        /// </remarks>
+        protected virtual void HandleUpdateException(Exception exception)
+        {
+            WriteToInfoStream(string.Format("an error occurred during revision update: {0}", exception));
+        }
+
+        /// <summary>
+        /// Executes the update operation immediately, irregardess if an update thread
+        /// is running or not.
+        /// </summary>
+        /// <exception cref="IOException"></exception>
+        public void UpdateNow() 
+        {
+            EnsureOpen();
+            if (updateThread != null)
+            {
+                //NOTE: We have a worker running, we use that to perform the work instead by requesting it to run
+                //      it's cycle immidiately.
+                updateThread.ExecuteImmediately();
+                return;
+            }
+
+            //NOTE: We don't have a worker running, so we just do the work.
+            updateLock.Lock();
+            try
+            {
+                DoUpdate();
+            }
+            finally
+            {
+                updateLock.Unlock();
+            }
+        }
+
+        protected virtual void Dispose(bool disposing)
+        {
+            if (disposed)
+                return;
+
+            StopUpdateThread();
+            disposed = true;
+        }
+
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        public override string ToString()
+        {
+            if (updateThread == null)
+                return "ReplicationClient";
+            return string.Format("ReplicationClient ({0})", updateThread.Name);
+        }
+
+        //Note: LUCENENET specific, .NET does not work with Threads in the same way as Java does, so we mimic the same behavior using the ThreadPool instead.
+        private class ReplicationThread
+        {
+            #region Java
+            //JAVA: private class ReplicationThread extends Thread {
+            //JAVA:   private final long interval;
+            //JAVA:   // client uses this to stop us
+            //JAVA:   final CountDownLatch stop = new CountDownLatch(1);
+            //JAVA:   
+            //JAVA:   public ReplicationThread(long interval) {
+            //JAVA:     this.interval = interval;
+            //JAVA:   }
+            //JAVA:   
+            //JAVA:   @SuppressWarnings("synthetic-access")
+            //JAVA:   @Override
+            //JAVA:   public void run() {
+            //JAVA:     while (true) {
+            //JAVA:       long time = System.currentTimeMillis();
+            //JAVA:       updateLock.lock();
+            //JAVA:       try {
+            //JAVA:         doUpdate();
+            //JAVA:       } catch (Throwable t) {
+            //JAVA:         handleUpdateException(t);
+            //JAVA:       } finally {
+            //JAVA:         updateLock.unlock();
+            //JAVA:       }
+            //JAVA:       time = System.currentTimeMillis() - time;
+            //JAVA:       
+            //JAVA:       // adjust timeout to compensate the time spent doing the replication.
+            //JAVA:       final long timeout = interval - time;
+            //JAVA:       if (timeout > 0) {
+            //JAVA:         try {
+            //JAVA:           // this will return immediately if we were ordered to stop (count=0)
+            //JAVA:           // or the timeout has elapsed. if it returns true, it means count=0,
+            //JAVA:           // so terminate.
+            //JAVA:           if (stop.await(timeout, TimeUnit.MILLISECONDS)) {
+            //JAVA:             return;
+            //JAVA:           }
+            //JAVA:         } catch (InterruptedException e) {
+            //JAVA:           // if we were interruted, somebody wants to terminate us, so just
+            //JAVA:           // throw the exception further.
+            //JAVA:           Thread.currentThread().interrupt();
+            //JAVA:           throw new ThreadInterruptedException(e);
+            //JAVA:         }
+            //JAVA:       }
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            private readonly Action doUpdate;
+            private readonly Action<Exception> handleException;
+            private readonly ReentrantLock @lock;
+            private readonly object controlLock = new object();
+            
+            private readonly long interval;
+            private readonly AutoResetEvent handle = new AutoResetEvent(false);
+
+            private AutoResetEvent stopHandle;
+
+            /// <summary>
+            /// Gets or sets the name
+            /// </summary>
+            public string Name { get; private set; }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            /// <param name="intervalMillis"></param>
+            /// <param name="threadName"></param>
+            /// <param name="doUpdate"></param>
+            /// <param name="handleException"></param>
+            /// <param name="lock"></param>
+            public ReplicationThread(long intervalMillis, string threadName, Action doUpdate, Action<Exception> handleException, ReentrantLock @lock)
+            {
+                this.doUpdate = doUpdate;
+                this.handleException = handleException;
+                this.@lock = @lock;
+                Name = threadName;
+                this.interval = intervalMillis;
+            }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            public bool IsAlive { get; private set; }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            public void Start()
+            {
+                lock (controlLock)
+                {
+                    if (IsAlive)
+                        return;
+                    IsAlive = true;
+                }
+                RegisterWait(interval);
+            }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            public void Stop()
+            {
+                lock (controlLock)
+                {
+                    if (!IsAlive)
+                        return;
+                    IsAlive = false;
+                }
+                stopHandle = new AutoResetEvent(false);
+
+                //NOTE: Execute any outstanding, this execution will terminate almost instantaniously if it's not already running.
+                ExecuteImmediately();
+
+                stopHandle.WaitOne();
+                stopHandle = null;
+            }
+
+            /// <summary>
+            /// Executes the next cycle of work immediately
+            /// </summary>
+            public void ExecuteImmediately()
+            {
+                handle.Set();
+            }
+
+            private void RegisterWait(long timeout)
+            {
+                //NOTE: We don't care about timedout as it can either be because we was requested to run immidiately or stop.
+                if (IsAlive)
+                    ThreadPool.RegisterWaitForSingleObject(handle, (state, timedout) => Run(), null, timeout, true);
+                else
+                    SignalStop();
+            }
+
+            private void SignalStop()
+            {
+                if (stopHandle != null)
+                    stopHandle.Set();
+            }
+
+            private void Run()
+            {
+                if (!IsAlive)
+                {
+                    SignalStop();
+                    return;
+                }
+
+                Stopwatch timer = Stopwatch.StartNew();
+                @lock.Lock();
+                try
+                {
+                    doUpdate();
+                }
+                catch (Exception exception)
+                {
+                    handleException(exception);
+                }
+                finally
+                {
+                    @lock.Unlock();
+
+                    timer.Stop();
+                    long driftAdjusted = Math.Max(interval - timer.ElapsedMilliseconds, 0);
+                    if (IsAlive)
+                        RegisterWait(driftAdjusted);
+                    else
+                        SignalStop();
+                }
+            }
+        }
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Replicator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Replicator.cs b/src/Lucene.Net.Replicator/Replicator.cs
new file mode 100644
index 0000000..af7ef51
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Replicator.cs
@@ -0,0 +1,91 @@
+//STATUS: DRAFT - 4.8.0
+using System;
+using System.IO;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 interface for replicating files. Allows a producer to 
+    /// <see cref="Publish"/> <see cref="IRevision"/>s and consumers to
+    /// <see cref="CheckForUpdate"/>. When a client needs to be
+    /// updated, it is given a <see cref="SessionToken"/> through which it can
+    /// <see cref="ObtainFile"/> the files of that
+    /// revision. After the client has finished obtaining all the files, it should
+    /// <see cref="Release"/> the given session, so that the files can be
+    /// reclaimed if they are not needed anymore.
+    /// <p>
+    /// A client is always updated to the newest revision available. That is, if a
+    /// client is on revision <em>r1</em> and revisions <em>r2</em> and <em>r3</em>
+    /// were published, then when the cllient will next check for update, it will
+    /// receive <em>r3</em>.
+    /// </p>
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public interface IReplicator : IDisposable
+    {
+        /// <summary>
+        /// Publish a new <see cref="IRevision"/> for consumption by clients. It is the
+        /// caller's responsibility to verify that the revision files exist and can be
+        /// read by clients. When the revision is no longer needed, it will be
+        /// <see cref="Release"/>d by the replicator.
+        /// </summary>
+        /// <param name="revision">The <see cref="IRevision"/> to publish.</param>
+        /// <exception cref="IOException"></exception>
+        void Publish(IRevision revision);
+
+        /// <summary>
+        /// Check whether the given version is up-to-date and returns a
+        /// <see cref="SessionToken"/> which can be used for fetching the revision files,
+        /// otherwise returns <code>null</code>.
+        /// </summary>
+        /// <remarks>
+        /// When the returned session token is no longer needed, you
+        /// should call <see cref="Release"/> so that the session resources can be
+        /// reclaimed, including the revision files.
+        /// </remarks>
+        /// <param name="currentVersion"></param>
+        /// <returns></returns>
+        /// <exception cref="IOException"></exception>
+        SessionToken CheckForUpdate(string currentVersion);// throws IOException;
+
+        /// <summary>
+        /// Notify that the specified <see cref="SessionToken"/> is no longer needed by the caller.
+        /// </summary>
+        /// <param name="sessionId"></param>
+        /// <exception cref="IOException"></exception>
+        void Release(string sessionId);
+
+        /// <summary>
+        /// Returns an <see cref="Stream"/> for the requested file and source in the
+        /// context of the given <see cref="SessionToken.Id"/>.
+        /// </summary>
+        /// <remarks>
+        /// It is the caller's responsibility to call <see cref="IDisposable.Dispose"/> on the returned stream.
+        /// </remarks>
+        /// <param name="sessionId"></param>
+        /// <param name="source"></param>
+        /// <param name="fileName"></param>
+        /// <returns></returns>
+        /// <exception cref="SessionExpiredException">The specified session has already expired</exception>
+        Stream ObtainFile(string sessionId, string source, string fileName);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/Revision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Revision.cs b/src/Lucene.Net.Replicator/Revision.cs
new file mode 100644
index 0000000..3d6fe19
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Revision.cs
@@ -0,0 +1,81 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 revision comprises lists of files that come from different sources and need
+    /// to be replicated together to e.g. guarantee that all resources are in sync.
+    /// In most cases an application will replicate a single index, and so the
+    /// revision will contain files from a single source. However, some applications
+    /// may require to treat a collection of indexes as a single entity so that the
+    /// files from all sources are replicated together, to guarantee consistency
+    /// beween them. For example, an application which indexes facets will need to
+    /// replicate both the search and taxonomy indexes together, to guarantee that
+    /// they match at the client side.
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public interface IRevision : IComparable<IRevision>
+    {
+        /// <summary>
+        /// Returns a string representation of the version of this revision. The
+        /// version is used by <see cref="CompareTo"/> as well as to
+        /// serialize/deserialize revision information. Therefore it must be self
+        /// descriptive as well as be able to identify one revision from another.
+        /// </summary>
+        string Version { get; }
+
+        /// <summary>
+        /// Returns the files that comprise this revision, as a mapping from a source
+        /// to a list of files.
+        /// </summary>
+        IDictionary<string, IList<RevisionFile>> SourceFiles { get; }
+
+        /// <summary>
+        /// Compares the revision to the given version string. Behaves like
+        /// <see cref="IComparable{T}.CompareTo"/>
+        /// </summary>
+        int CompareTo(string version);
+
+        /// <summary>
+        /// Returns an {@link IndexInput} for the given fileName and source. It is the
+        /// caller's respnsibility to close the {@link IndexInput} when it has been
+        /// consumed.
+        /// </summary>
+        /// <param name="source"></param>
+        /// <param name="fileName"></param>
+        /// <returns></returns>
+        /// <exception cref="IOException"></exception>
+        //TODO: Stream or IndexInput?
+        Stream Open(string source, string fileName);
+
+        /// <summary>
+        /// Called when this revision can be safely released, i.e. where there are no
+        /// more references to it.
+        /// </summary>
+        /// <exception cref="IOException"></exception>
+        void Release();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/RevisionFile.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/RevisionFile.cs b/src/Lucene.Net.Replicator/RevisionFile.cs
new file mode 100644
index 0000000..abd7aff
--- /dev/null
+++ b/src/Lucene.Net.Replicator/RevisionFile.cs
@@ -0,0 +1,87 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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>
+    /// Describes a file in a <see cref="IRevision"/>. A file has a source, which allows a
+    /// single revision to contain files from multiple sources (e.g. multiple indexes).
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public class RevisionFile : IEquatable<RevisionFile>
+    {
+        /// <summary>
+        /// Gets the name of the file.
+        /// </summary>
+        public string FileName { get; private set; }
+        
+        //TODO: can this be readonly?
+        /// <summary>
+        /// Gets or sets the length of the file denoted by <see cref="FileName"/>.
+        /// </summary>
+        public long Length { get; set; }
+
+        /// <summary>
+        /// Constructor with the given file name and optionally length. 
+        /// </summary>
+        /// <param name="fileName"></param>
+        /// <param name="length">Optional, the length of the file.</param>
+        public RevisionFile(string fileName, long length = -1)
+        {
+            if (string.IsNullOrEmpty(fileName)) throw new ArgumentException("fileName must not be null or empty", "fileName");
+
+            FileName = fileName;
+            Length = length;
+        }
+
+        public override string ToString()
+        {
+            return string.Format("fileName={0} length={1}", FileName, Length);
+        }
+
+        #region Resharper Generated Code
+        public bool Equals(RevisionFile other)
+        {
+            if (ReferenceEquals(null, other)) return false;
+            if (ReferenceEquals(this, other)) return true;
+            return string.Equals(FileName, other.FileName) && Length == other.Length;
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != this.GetType()) return false;
+            return Equals((RevisionFile)obj);
+        }
+
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                return (FileName.GetHashCode() * 397) ^ Length.GetHashCode();
+            }
+        }
+        #endregion
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/SessionExpiredException.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/SessionExpiredException.cs b/src/Lucene.Net.Replicator/SessionExpiredException.cs
new file mode 100644
index 0000000..38eed6c
--- /dev/null
+++ b/src/Lucene.Net.Replicator/SessionExpiredException.cs
@@ -0,0 +1,58 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.IO;
+using System.Runtime.Serialization;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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>
+    /// Exception indicating that a revision update session was expired due to lack of activity.
+    /// </summary>
+    /// <remarks>
+    /// <see cref="LocalReplicator.DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>
+    /// <see cref="LocalReplicator.ExpirationThreshold"/>
+    /// 
+    /// Lucene.Experimental
+    /// </remarks>
+    public class SessionExpiredException : IOException
+    {
+        //
+        // For guidelines regarding the creation of new exception types, see
+        //    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconerrorraisinghandlingguidelines.asp
+        // and
+        //    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp07192001.asp
+        //
+
+        public SessionExpiredException()
+        {
+        }
+
+        public SessionExpiredException(string message) 
+            : base(message)
+        {
+        }
+
+        public SessionExpiredException(string message, Exception inner) 
+            : base(message, inner)
+        {
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/SessionToken.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/SessionToken.cs b/src/Lucene.Net.Replicator/SessionToken.cs
new file mode 100644
index 0000000..a9440d7
--- /dev/null
+++ b/src/Lucene.Net.Replicator/SessionToken.cs
@@ -0,0 +1,129 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using Lucene.Net.Store;
+using Lucene.Net.Support.IO;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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>
+    /// Token for a replication session, for guaranteeing that source replicated
+    /// files will be kept safe until the replication completes.
+    /// </summary>
+    /// <remarks>
+    /// <see cref="IReplicator.CheckForUpdate"/>
+    /// <see cref="IReplicator.Release"/>
+    /// <see cref="LocalReplicator.DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>
+    /// 
+    /// Lucene.Experimental
+    /// </remarks>
+    public sealed class SessionToken
+    {
+        /// <summary>
+        /// Id of this session.
+        /// Should be passed when releasing the session, thereby acknowledging the 
+        /// <see cref="IReplicator"/>  that this session is no longer in use.
+        /// <see cref="IReplicator.Release"/>
+        /// </summary>
+        public string Id { get; private set; }
+
+        /// <summary>
+        /// <see cref="IRevision.Version"/>
+        /// </summary>
+        public string Version { get; private set; }
+
+        /// <summary>
+        /// <see cref="IRevision.SourceFiles"/>
+        /// </summary>
+        public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
+
+        /// <summary>
+        /// Constructor which deserializes from the given <see cref="DataInput"/>.
+        /// </summary>
+        /// <param name="reader"></param>
+        /// <exception cref="IOException"></exception>
+        public SessionToken(DataInputStream reader)
+        {
+            Id = reader.ReadUTF();
+            Version = reader.ReadUTF();
+
+            var sourceFiles = new Dictionary<string, IList<RevisionFile>>();
+            int numSources = reader.ReadInt32();
+            while (numSources > 0)
+            {
+                string source = reader.ReadUTF();
+                int numFiles = reader.ReadInt32();
+
+                List<RevisionFile> files = new List<RevisionFile>(numFiles);
+                for (int i = 0; i < numFiles; i++)
+                {
+                    files.Add(new RevisionFile(reader.ReadUTF(), reader.ReadInt64()));
+                }
+                sourceFiles.Add(source, files);
+                --numSources;
+            }
+            SourceFiles = sourceFiles;
+        }
+
+        /// <summary>
+        /// Constructor with the given id and revision.
+        /// </summary>
+        /// <param name="id"></param>
+        /// <param name="revision"></param>
+        /// <exception cref="IOException"></exception>
+        public SessionToken(string id, IRevision revision)
+        {
+            Id = id;
+            Version = revision.Version;
+            SourceFiles = revision.SourceFiles;
+        }
+
+        /// <summary>
+        /// Serialize the token data for communication between server and client.
+        /// </summary>
+        /// <param name="writer"></param>
+        /// <exception cref="IOException"></exception>
+        public void Serialize(DataOutputStream writer)
+        {
+            writer.WriteUTF(Id);
+            writer.WriteUTF(Version);
+            writer.WriteInt32(SourceFiles.Count);
+
+            foreach (KeyValuePair<string, IList<RevisionFile>> pair in SourceFiles)
+            {
+                writer.WriteUTF(pair.Key);
+                writer.WriteInt32(pair.Value.Count);
+                foreach (RevisionFile file in pair.Value)
+                {
+                    writer.WriteUTF(file.FileName);
+                    writer.WriteInt64(file.Length);
+                }
+            }
+        }
+
+        public override string ToString()
+        {
+            return string.Format("id={0} version={1} files={2}", Id, Version, SourceFiles);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/packages.config
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/packages.config b/src/Lucene.Net.Replicator/packages.config
new file mode 100644
index 0000000..3e14be6
--- /dev/null
+++ b/src/Lucene.Net.Replicator/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Newtonsoft.Json" version="9.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.Tests.Replicator/Http/HttpReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
new file mode 100644
index 0000000..3d116f9
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
@@ -0,0 +1,104 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Replicator.Http;
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.TestHost;
+using Microsoft.Extensions.DependencyInjection;
+using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Tests.Replicator.Http
+{
+    public class HttpReplicatorTest : ReplicatorTestCase
+    {
+        private DirectoryInfo clientWorkDir;
+        private IReplicator serverReplicator;
+        private IndexWriter writer;
+        private DirectoryReader reader;
+
+        private int port;
+        private string host;
+        private TestServer server;
+
+        private Directory serverIndexDir;
+        private Directory handlerIndexDir;
+
+        private void StartServer()
+        {
+            ReplicationService service = new ReplicationService(new Dictionary<string, IReplicator> { { "s1", serverReplicator } });
+
+            server = NewHttpServer<ReplicationServlet>(service);
+            port = ServerPort(server);
+            host = ServerHost(server);
+        }
+
+        public override void SetUp()
+        {
+            base.SetUp();
+            //JAVA:    System.setProperty("org.eclipse.jetty.LEVEL", "DEBUG"); // sets stderr logging to DEBUG level
+            clientWorkDir = CreateTempDir("httpReplicatorTest");
+            handlerIndexDir = NewDirectory();
+            serverIndexDir = NewDirectory();
+            serverReplicator = new LocalReplicator();
+            StartServer();
+
+            IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            writer = new IndexWriter(serverIndexDir, conf);
+            reader = DirectoryReader.Open(writer, false);
+        }
+
+        public override void TearDown()
+        {
+            StopHttpServer(server);
+            IOUtils.Dispose(reader, writer, handlerIndexDir, serverIndexDir);
+            //JAVA:    System.clearProperty("org.eclipse.jetty.LEVEL");
+            base.TearDown();
+        }
+
+        private void PublishRevision(int id)
+        {
+            Document doc = new Document();
+            writer.AddDocument(doc);
+            writer.SetCommitData(Collections.SingletonMap("ID", id.ToString("X")));
+            writer.Commit();
+            serverReplicator.Publish(new IndexRevision(writer));
+        }
+
+        private void ReopenReader()
+        {
+            DirectoryReader newReader = DirectoryReader.OpenIfChanged(reader);
+            assertNotNull(newReader);
+            reader.Dispose();
+            reader = newReader;
+        }
+
+
+        [Test]
+        public void TestBasic()
+        {
+            IReplicator replicator = new HttpReplicator(host, port, ReplicationService.REPLICATION_CONTEXT + "/s1", server.CreateHandler());
+            ReplicationClient client = new ReplicationClient(replicator, new IndexReplicationHandler(handlerIndexDir, null), 
+                new PerSessionDirectoryFactory(clientWorkDir.FullName));
+
+            PublishRevision(1);
+            client.UpdateNow();
+            ReopenReader();
+            assertEquals(1, int.Parse(reader.IndexCommit.UserData["ID"], NumberStyles.HexNumber));
+
+            PublishRevision(2);
+            client.UpdateNow();
+            ReopenReader();
+            assertEquals(2, int.Parse(reader.IndexCommit.UserData["ID"], NumberStyles.HexNumber));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs b/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs
new file mode 100644
index 0000000..63420a6
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs
@@ -0,0 +1,22 @@
+//STATUS: DRAFT - 4.8.0
+
+using System.Threading.Tasks;
+using Lucene.Net.Replicator.AspNetCore;
+using Lucene.Net.Replicator.Http;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+
+namespace Lucene.Net.Tests.Replicator.Http
+{
+    public class ReplicationServlet
+    {
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ReplicationService service)
+        {
+            app.Run(async context =>
+            {
+                await Task.Yield();
+                service.Perform(context.Request, context.Response);
+            });
+        }
+    }
+}
\ No newline at end of file


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

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs b/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
new file mode 100644
index 0000000..a9629b8
--- /dev/null
+++ b/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
@@ -0,0 +1,276 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Lucene.Net.Index;
+using Lucene.Net.Store;
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 {@link ReplicationHandler} for replication of an index and taxonomy pair.
+    /// See {@link IndexReplicationHandler} for more detail. This handler ensures
+    /// that the search and taxonomy indexes are replicated in a consistent way.
+    /// 
+    /// <see cref="IndexReplicationHandler"/>
+    /// </summary>
+    /// <remarks>
+    /// If you intend to recreate a taxonomy index, you should make sure
+    /// to reopen an IndexSearcher and TaxonomyReader pair via the provided callback,
+    /// to guarantee that both indexes are in sync. This handler does not prevent
+    /// replicating such index and taxonomy pairs, and if they are reopened by a
+    /// different thread, unexpected errors can occur, as well as inconsistency
+    /// between the taxonomy and index readers.
+    /// 
+    /// Lucene.Experimental
+    /// </remarks>
+    public class IndexAndTaxonomyReplicationHandler : IReplicationHandler
+    {
+        /// <summary>
+        /// The component used to log messages to the {@link InfoStream#getDefault()default} {@link InfoStream}.
+        /// </summary>
+        public const string INFO_STREAM_COMPONENT = "IndexAndTaxonomyReplicationHandler";
+
+        private readonly Directory indexDirectory;
+        private readonly Directory taxonomyDirectory;
+        private readonly Func<bool?> callback;
+
+        private InfoStream infoStream = InfoStream.Default;
+
+        public string CurrentVersion { get; private set; }
+        public IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; private set; }
+        public InfoStream InfoStream
+        {
+            get { return infoStream; }
+            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
+        }
+
+        /// <summary>
+        /// Constructor with the given index directory and callback to notify when the indexes were updated.
+        /// </summary>
+        /// <param name="indexDirectory"></param>
+        /// <param name="taxonomyDirectory"></param>
+        /// <param name="callback"></param>
+        /// <exception cref="System.IO.IOException"></exception>
+        public IndexAndTaxonomyReplicationHandler(Directory indexDirectory, Directory taxonomyDirectory, Func<bool?> callback)
+        {
+            this.indexDirectory = indexDirectory;
+            this.taxonomyDirectory = taxonomyDirectory;
+            this.callback = callback;
+
+            CurrentVersion = null;
+            CurrentRevisionFiles = null;
+
+            bool indexExists = DirectoryReader.IndexExists(indexDirectory);
+            bool taxonomyExists = DirectoryReader.IndexExists(taxonomyDirectory);
+
+            //JAVA: IllegalStateException
+            if (indexExists != taxonomyExists)
+                throw new InvalidOperationException(string.Format("search and taxonomy indexes must either both exist or not: index={0} taxo={1}", indexExists, taxonomyExists));
+
+            if (indexExists)
+            {
+                IndexCommit indexCommit = IndexReplicationHandler.GetLastCommit(indexDirectory);
+                IndexCommit taxonomyCommit = IndexReplicationHandler.GetLastCommit(taxonomyDirectory);
+
+                CurrentRevisionFiles = IndexAndTaxonomyRevision.RevisionFiles(indexCommit, taxonomyCommit);
+                CurrentVersion = IndexAndTaxonomyRevision.RevisionVersion(indexCommit, taxonomyCommit);
+
+                WriteToInfoStream(
+                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles),
+                    string.Format("constructor(): indexCommit={0} taxoCommit={1}", indexCommit, taxonomyCommit));
+            }
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="version"></param>
+        /// <param name="revisionFiles"></param>
+        /// <param name="copiedFiles"></param>
+        /// <param name="sourceDirectory"></param>
+        /// <exception cref=""></exception>
+        public void RevisionReady(string version,
+            IDictionary<string, IList<RevisionFile>> revisionFiles,
+            IDictionary<string, IList<string>> copiedFiles,
+            IDictionary<string, Directory> sourceDirectory)
+        {
+            #region Java
+            //JAVA: Directory taxoClientDir = sourceDirectory.get(IndexAndTaxonomyRevision.TAXONOMY_SOURCE);
+            //JAVA: Directory indexClientDir = sourceDirectory.get(IndexAndTaxonomyRevision.INDEX_SOURCE);
+            //JAVA: List<String> taxoFiles = copiedFiles.get(IndexAndTaxonomyRevision.TAXONOMY_SOURCE);
+            //JAVA: List<String> indexFiles = copiedFiles.get(IndexAndTaxonomyRevision.INDEX_SOURCE);
+            //JAVA: String taxoSegmentsFile = IndexReplicationHandler.getSegmentsFile(taxoFiles, true);
+            //JAVA: String indexSegmentsFile = IndexReplicationHandler.getSegmentsFile(indexFiles, false);
+            //JAVA:
+            //JAVA: boolean success = false;
+            //JAVA: try {
+            //JAVA:   // copy taxonomy files before index files
+            //JAVA:   IndexReplicationHandler.copyFiles(taxoClientDir, taxoDir, taxoFiles);
+            //JAVA:   IndexReplicationHandler.copyFiles(indexClientDir, indexDir, indexFiles);
+            //JAVA:
+            //JAVA:   // fsync all copied files (except segmentsFile)
+            //JAVA:   if (!taxoFiles.isEmpty()) {
+            //JAVA:     taxoDir.sync(taxoFiles);
+            //JAVA:   }
+            //JAVA:   indexDir.sync(indexFiles);
+            //JAVA:
+            //JAVA:   // now copy and fsync segmentsFile, taxonomy first because it is ok if a
+            //JAVA:   // reader sees a more advanced taxonomy than the index.
+            //JAVA:   if (taxoSegmentsFile != null) {
+            //JAVA:     taxoClientDir.copy(taxoDir, taxoSegmentsFile, taxoSegmentsFile, IOContext.READONCE);
+            //JAVA:   }
+            //JAVA:   indexClientDir.copy(indexDir, indexSegmentsFile, indexSegmentsFile, IOContext.READONCE);
+            //JAVA:
+            //JAVA:   if (taxoSegmentsFile != null) {
+            //JAVA:     taxoDir.sync(Collections.singletonList(taxoSegmentsFile));
+            //JAVA:   }
+            //JAVA:   indexDir.sync(Collections.singletonList(indexSegmentsFile));
+            //JAVA:
+            //JAVA:   success = true;
+            //JAVA: } finally {
+            //JAVA:   if (!success) {
+            //JAVA:     taxoFiles.add(taxoSegmentsFile); // add it back so it gets deleted too
+            //JAVA:     IndexReplicationHandler.cleanupFilesOnFailure(taxoDir, taxoFiles);
+            //JAVA:     indexFiles.add(indexSegmentsFile); // add it back so it gets deleted too
+            //JAVA:     IndexReplicationHandler.cleanupFilesOnFailure(indexDir, indexFiles);
+            //JAVA:   }
+            //JAVA: }
+            //JAVA:
+            //JAVA: // all files have been successfully copied + sync'd. update the handler's state
+            //JAVA: currentRevisionFiles = revisionFiles;
+            //JAVA: currentVersion = version;
+            //JAVA:
+            //JAVA: if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
+            //JAVA:   infoStream.message(INFO_STREAM_COMPONENT, "revisionReady(): currentVersion=" + currentVersion
+            //JAVA:       + " currentRevisionFiles=" + currentRevisionFiles);
+            //JAVA: }
+            //JAVA:
+            //JAVA: // update the segments.gen file
+            //JAVA: IndexReplicationHandler.writeSegmentsGen(taxoSegmentsFile, taxoDir);
+            //JAVA: IndexReplicationHandler.writeSegmentsGen(indexSegmentsFile, indexDir);
+            //JAVA:
+            //JAVA: // Cleanup the index directory from old and unused index files.
+            //JAVA: // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
+            //JAVA: // side-effects, e.g. if it hits sudden IO errors while opening the index
+            //JAVA: // (and can end up deleting the entire index). It is not our job to protect
+            //JAVA: // against those errors, app will probably hit them elsewhere.
+            //JAVA: IndexReplicationHandler.cleanupOldIndexFiles(indexDir, indexSegmentsFile);
+            //JAVA: IndexReplicationHandler.cleanupOldIndexFiles(taxoDir, taxoSegmentsFile);
+            //JAVA:
+            //JAVA: // successfully updated the index, notify the callback that the index is
+            //JAVA: // ready.
+            //JAVA: if (callback != null) {
+            //JAVA:   try {
+            //JAVA:     callback.call();
+            //JAVA:   } catch (Exception e) {
+            //JAVA:     throw new IOException(e);
+            //JAVA:   }
+            //JAVA: } 
+            #endregion
+
+            Directory taxonomyClientDirectory = sourceDirectory[IndexAndTaxonomyRevision.TAXONOMY_SOURCE];
+            Directory indexClientDirectory = sourceDirectory[IndexAndTaxonomyRevision.INDEX_SOURCE];
+            IList<string> taxonomyFiles = copiedFiles[IndexAndTaxonomyRevision.TAXONOMY_SOURCE];
+            IList<string> indexFiles = copiedFiles[IndexAndTaxonomyRevision.INDEX_SOURCE];
+            string taxonomySegmentsFile = IndexReplicationHandler.GetSegmentsFile(taxonomyFiles, true);
+            string indexSegmentsFile = IndexReplicationHandler.GetSegmentsFile(indexFiles, false);
+
+            bool success = false;
+            try
+            {
+                // copy taxonomy files before index files
+                IndexReplicationHandler.CopyFiles(taxonomyClientDirectory, taxonomyDirectory, taxonomyFiles);
+                IndexReplicationHandler.CopyFiles(indexClientDirectory, indexDirectory, indexFiles);
+
+                // fsync all copied files (except segmentsFile)
+                if (taxonomyFiles.Any())
+                    taxonomyDirectory.Sync(taxonomyFiles);
+                indexDirectory.Sync(indexFiles);
+
+                // now copy and fsync segmentsFile, taxonomy first because it is ok if a
+                // reader sees a more advanced taxonomy than the index.
+                if (taxonomySegmentsFile != null)
+                    taxonomyClientDirectory.Copy(taxonomyDirectory, taxonomySegmentsFile, taxonomySegmentsFile, IOContext.READ_ONCE);
+                indexClientDirectory.Copy(indexDirectory, indexSegmentsFile, indexSegmentsFile, IOContext.READ_ONCE);
+
+                if (taxonomySegmentsFile != null)
+                    taxonomyDirectory.Sync(new[] { taxonomySegmentsFile });
+                indexDirectory.Sync(new[] { indexSegmentsFile });
+
+                success = true;
+            }
+            finally
+            {
+                if (!success)
+                {
+                    taxonomyFiles.Add(taxonomySegmentsFile); // add it back so it gets deleted too
+                    IndexReplicationHandler.CleanupFilesOnFailure(taxonomyDirectory, taxonomyFiles);
+                    indexFiles.Add(indexSegmentsFile); // add it back so it gets deleted too
+                    IndexReplicationHandler.CleanupFilesOnFailure(indexDirectory, indexFiles);
+                }
+            }
+
+            // all files have been successfully copied + sync'd. update the handler's state
+            CurrentRevisionFiles = revisionFiles;
+            CurrentVersion = version;
+            
+            WriteToInfoStream("revisionReady(): currentVersion=" + CurrentVersion + " currentRevisionFiles=" + CurrentRevisionFiles);
+            
+            // update the segments.gen file
+            IndexReplicationHandler.WriteSegmentsGen(taxonomySegmentsFile, taxonomyDirectory);
+            IndexReplicationHandler.WriteSegmentsGen(indexSegmentsFile, indexDirectory);
+            
+            // Cleanup the index directory from old and unused index files.
+            // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
+            // side-effects, e.g. if it hits sudden IO errors while opening the index
+            // (and can end up deleting the entire index). It is not our job to protect
+            // against those errors, app will probably hit them elsewhere.
+            IndexReplicationHandler.CleanupOldIndexFiles(indexDirectory, indexSegmentsFile);
+            IndexReplicationHandler.CleanupOldIndexFiles(taxonomyDirectory, taxonomySegmentsFile);
+            
+            // successfully updated the index, notify the callback that the index is
+            // ready.
+            if (callback != null) {
+              try {
+                callback.Invoke();
+              } catch (Exception e) {
+                throw new IOException(e.Message, e);
+              }
+            } 
+        }
+
+        private void WriteToInfoStream(params string[] messages)
+        {
+            if (!InfoStream.IsEnabled(INFO_STREAM_COMPONENT))
+                return;
+
+            foreach (string message in messages)
+                InfoStream.Message(INFO_STREAM_COMPONENT, message);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs b/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
new file mode 100644
index 0000000..8d32fac
--- /dev/null
+++ b/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
@@ -0,0 +1,334 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using Lucene.Net.Facet.Taxonomy.Directory;
+using Lucene.Net.Facet.Taxonomy.WriterCache;
+using Lucene.Net.Index;
+using Lucene.Net.Store;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 <see cref="IRevision"/> of a single index and taxonomy index files which comprises
+    /// the list of files from both indexes. This revision should be used whenever a
+    /// pair of search and taxonomy indexes need to be replicated together to
+    /// guarantee consistency of both on the replicating (client) side.
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public class IndexAndTaxonomyRevision : IRevision
+    {
+        #region Java
+        //JAVA: private final IndexWriter indexWriter;
+        //JAVA: private final SnapshotDirectoryTaxonomyWriter taxoWriter;
+        //JAVA: private final IndexCommit indexCommit, taxoCommit;
+        //JAVA: private final SnapshotDeletionPolicy indexSDP, taxoSDP;
+        //JAVA: private final String version;
+        //JAVA: private final Map<String, List<RevisionFile>> sourceFiles;
+        #endregion
+
+        public const string INDEX_SOURCE = "index";
+        public const string TAXONOMY_SOURCE = "taxonomy";
+
+        private readonly IndexWriter indexWriter;
+        private readonly SnapshotDirectoryTaxonomyWriter taxonomyWriter;
+        private readonly IndexCommit indexCommit, taxonomyCommit;
+        private readonly SnapshotDeletionPolicy indexSdp, taxonomySdp;
+
+        public string Version { get; private set; }
+        public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="indexWriter"></param>
+        /// <param name="taxonomyWriter"></param>
+        /// <exception cref="IOException"></exception>
+        public IndexAndTaxonomyRevision(IndexWriter indexWriter, SnapshotDirectoryTaxonomyWriter taxonomyWriter)
+        {
+            #region Java
+            //JAVA: /**
+            //JAVA:  * Constructor over the given {@link IndexWriter}. Uses the last
+            //JAVA:  * {@link IndexCommit} found in the {@link Directory} managed by the given
+            //JAVA:  * writer.
+            //JAVA:  */
+            //JAVA: public IndexAndTaxonomyRevision(IndexWriter indexWriter, SnapshotDirectoryTaxonomyWriter taxoWriter)
+            //JAVA:     throws IOException {
+            //JAVA:   IndexDeletionPolicy delPolicy = indexWriter.getConfig().getIndexDeletionPolicy();
+            //JAVA:   if (!(delPolicy instanceof SnapshotDeletionPolicy)) {
+            //JAVA:     throw new IllegalArgumentException("IndexWriter must be created with SnapshotDeletionPolicy");
+            //JAVA:   }
+            //JAVA:   this.indexWriter = indexWriter;
+            //JAVA:   this.taxoWriter = taxoWriter;
+            //JAVA:   this.indexSDP = (SnapshotDeletionPolicy) delPolicy;
+            //JAVA:   this.taxoSDP = taxoWriter.getDeletionPolicy();
+            //JAVA:   this.indexCommit = indexSDP.snapshot();
+            //JAVA:   this.taxoCommit = taxoSDP.snapshot();
+            //JAVA:   this.version = revisionVersion(indexCommit, taxoCommit);
+            //JAVA:   this.sourceFiles = revisionFiles(indexCommit, taxoCommit);
+            //JAVA: }
+            #endregion
+
+            this.indexSdp = indexWriter.Config.IndexDeletionPolicy as SnapshotDeletionPolicy;
+            if (indexSdp == null)
+                throw new ArgumentException("IndexWriter must be created with SnapshotDeletionPolicy", "indexWriter");
+
+            this.indexWriter = indexWriter;
+            this.taxonomyWriter = taxonomyWriter;
+            this.taxonomySdp = taxonomyWriter.DeletionPolicy;
+            this.indexCommit = indexSdp.Snapshot();
+            this.taxonomyCommit = taxonomySdp.Snapshot();
+            this.Version = RevisionVersion(indexCommit, taxonomyCommit);
+            this.SourceFiles = RevisionFiles(indexCommit, taxonomyCommit);
+        }
+
+        public int CompareTo(string version)
+        {
+            #region Java
+            //JAVA: public int compareTo(String version) {
+            //JAVA:   final String[] parts = version.split(":");
+            //JAVA:   final long indexGen = Long.parseLong(parts[0], RADIX);
+            //JAVA:   final long taxoGen = Long.parseLong(parts[1], RADIX);
+            //JAVA:   final long indexCommitGen = indexCommit.getGeneration();
+            //JAVA:   final long taxoCommitGen = taxoCommit.getGeneration();
+            //JAVA:   
+            //JAVA:   // if the index generation is not the same as this commit's generation,
+            //JAVA:   // compare by it. Otherwise, compare by the taxonomy generation.
+            //JAVA:   if (indexCommitGen < indexGen) {
+            //JAVA:     return -1;
+            //JAVA:   } else if (indexCommitGen > indexGen) {
+            //JAVA:     return 1;
+            //JAVA:   } else {
+            //JAVA:     return taxoCommitGen < taxoGen ? -1 : (taxoCommitGen > taxoGen ? 1 : 0);
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            string[] parts = version.Split(':');
+            long indexGen = long.Parse(parts[0], NumberStyles.HexNumber);
+            long taxonomyGen = long.Parse(parts[1], NumberStyles.HexNumber);
+            long indexCommitGen = indexCommit.Generation;
+            long taxonomyCommitGen = taxonomyCommit.Generation;
+
+            //TODO: long.CompareTo(); but which goes where.
+            if (indexCommitGen < indexGen)
+                return -1;
+
+            if (indexCommitGen > indexGen)
+                return 1;
+
+            return taxonomyCommitGen < taxonomyGen ? -1 : (taxonomyCommitGen > taxonomyGen ? 1 : 0);
+        }
+
+        public int CompareTo(IRevision other)
+        {
+            #region Java
+            //JAVA: public int compareTo(Revision o) {
+            //JAVA:   IndexAndTaxonomyRevision other = (IndexAndTaxonomyRevision) o;
+            //JAVA:   int cmp = indexCommit.compareTo(other.indexCommit);
+            //JAVA:   return cmp != 0 ? cmp : taxoCommit.compareTo(other.taxoCommit);
+            //JAVA: }
+            #endregion
+
+            //TODO: This breaks the contract and will fail if called with a different implementation
+            //      This is a flaw inherited from the original source...
+            //      It should at least provide a better description to the InvalidCastException
+            IndexAndTaxonomyRevision or = (IndexAndTaxonomyRevision)other;
+            int cmp = indexCommit.CompareTo(or.indexCommit);
+            return cmp != 0 ? cmp : taxonomyCommit.CompareTo(or.taxonomyCommit);
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="source"></param>
+        /// <param name="fileName"></param>
+        /// <returns></returns>
+        /// <exception cref="IOException"></exception>
+        public Stream Open(string source, string fileName)
+        {
+            #region Java
+            //JAVA: public InputStream open(String source, String fileName) throws IOException {
+            //JAVA:   assert source.equals(INDEX_SOURCE) || source.equals(TAXONOMY_SOURCE) : "invalid source; expected=(" + INDEX_SOURCE
+            //JAVA:   + " or " + TAXONOMY_SOURCE + ") got=" + source;
+            //JAVA:   IndexCommit ic = source.equals(INDEX_SOURCE) ? indexCommit : taxoCommit;
+            //JAVA:   return new IndexInputStream(ic.getDirectory().openInput(fileName, IOContext.READONCE));
+            //JAVA: }
+            #endregion
+
+            Debug.Assert(source.Equals(INDEX_SOURCE) || source.Equals(TAXONOMY_SOURCE), 
+                string.Format("invalid source; expected=({0} or {1}) got={2}", INDEX_SOURCE, TAXONOMY_SOURCE, source));
+            IndexCommit commit = source.Equals(INDEX_SOURCE) ? indexCommit : taxonomyCommit;
+            return new IndexInputStream(commit.Directory.OpenInput(fileName, IOContext.READ_ONCE));
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <exception cref="IOException"></exception>
+        public void Release()
+        {
+            #region Java
+            //JAVA: public void release() throws IOException {
+            //JAVA:   try {
+            //JAVA:     indexSDP.release(indexCommit);
+            //JAVA:   } finally {
+            //JAVA:     taxoSDP.release(taxoCommit);
+            //JAVA:   }
+            //JAVA:   
+            //JAVA:   try {
+            //JAVA:     indexWriter.deleteUnusedFiles();
+            //JAVA:   } finally {
+            //JAVA:     taxoWriter.getIndexWriter().deleteUnusedFiles();
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            try
+            {
+                indexSdp.Release(indexCommit);
+            }
+            finally 
+            {
+                taxonomySdp.Release(taxonomyCommit);
+            }
+
+            try
+            {
+                indexWriter.DeleteUnusedFiles();
+            }
+            finally
+            {
+                taxonomyWriter.IndexWriter.DeleteUnusedFiles();
+            }
+        }
+
+        //.NET NOTE: Changed doc comment as the JAVA one seems to be a bit too much copy/paste
+        /// <summary>
+        /// Returns a map of the revision files from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.
+        /// </summary>
+        /// <param name="indexCommit"></param>
+        /// <param name="taxonomyCommit"></param>
+        /// <returns></returns>
+        /// <exception cref="IOException"></exception>
+        public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit indexCommit, IndexCommit taxonomyCommit)
+        {
+            #region Java
+            //JAVA: /** Returns a singleton map of the revision files from the given {@link IndexCommit}. */
+            //JAVA: public static Map<String, List<RevisionFile>> revisionFiles(IndexCommit indexCommit, IndexCommit taxoCommit)
+            //JAVA:     throws IOException {
+            //JAVA:   HashMap<String,List<RevisionFile>> files = new HashMap<>();
+            //JAVA:   files.put(INDEX_SOURCE, IndexRevision.revisionFiles(indexCommit).values().iterator().next());
+            //JAVA:   files.put(TAXONOMY_SOURCE, IndexRevision.revisionFiles(taxoCommit).values().iterator().next());
+            //JAVA:   return files;
+            //JAVA: }
+            #endregion
+
+            return new Dictionary<string, IList<RevisionFile>>{
+                    { INDEX_SOURCE,  IndexRevision.RevisionFiles(indexCommit).Values.First() },
+                    { TAXONOMY_SOURCE,  IndexRevision.RevisionFiles(taxonomyCommit).Values.First() }
+                };
+        }
+
+        /// <summary>
+        /// Returns a String representation of a revision's version from the given
+        /// <see cref="IndexCommit"/>s of the search and taxonomy indexes.
+        /// </summary>
+        /// <param name="commit"></param>
+        /// <returns>a String representation of a revision's version from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.</returns>
+        public static string RevisionVersion(IndexCommit indexCommit, IndexCommit taxonomyCommit)
+        {
+            #region Java
+            //JAVA: public static String revisionVersion(IndexCommit indexCommit, IndexCommit taxoCommit) {
+            //JAVA:   return Long.toString(indexCommit.getGeneration(), RADIX) + ":" + Long.toString(taxoCommit.getGeneration(), RADIX);
+            //JAVA: }   
+            #endregion
+
+            return string.Format("{0:X}:{1:X}", indexCommit.Generation, taxonomyCommit.Generation);
+        }
+
+        /// <summary>
+        /// A <seealso cref="DirectoryTaxonomyWriter"/> which sets the underlying
+        /// <seealso cref="IndexWriter"/>'s <seealso cref="IndexDeletionPolicy"/> to
+        /// <seealso cref="SnapshotDeletionPolicy"/>.
+        /// </summary>
+        public class SnapshotDirectoryTaxonomyWriter : DirectoryTaxonomyWriter
+        {
+            /// <summary>
+            /// Gets the <see cref="SnapshotDeletionPolicy"/> used by the underlying <see cref="IndexWriter"/>.
+            /// </summary>
+            public SnapshotDeletionPolicy DeletionPolicy { get; private set; }
+            /// <summary>
+            /// Gets the <see cref="IndexWriter"/> used by this <see cref="DirectoryTaxonomyWriter"/>.
+            /// </summary>
+            public IndexWriter IndexWriter { get; private set; }
+
+            /// <summary>
+            /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode, ITaxonomyWriterCache)"/>
+            /// </summary>
+            /// <exception cref="IOException"></exception>
+            public SnapshotDirectoryTaxonomyWriter(Directory directory, OpenMode openMode, ITaxonomyWriterCache cache) 
+                : base(directory, openMode, cache)
+            {
+            }
+
+            /// <summary>
+            /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode)"/>
+            /// </summary>
+            /// <exception cref="IOException"></exception>
+            public SnapshotDirectoryTaxonomyWriter(Directory directory, OpenMode openMode = OpenMode.CREATE_OR_APPEND)
+                : base(directory, openMode)
+            {
+            }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            /// <param name="openMode"></param>
+            /// <returns></returns>
+            protected override IndexWriterConfig CreateIndexWriterConfig(OpenMode openMode)
+            {
+                IndexWriterConfig conf = base.CreateIndexWriterConfig(openMode);
+                conf.IndexDeletionPolicy = DeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+                return conf;
+            }
+
+            /// <summary>
+            /// 
+            /// </summary>
+            /// <param name="directory"></param>
+            /// <param name="config"></param>
+            /// <returns></returns>
+            protected override IndexWriter OpenIndexWriter(Directory directory, IndexWriterConfig config)
+            {
+                return IndexWriter = base.OpenIndexWriter(directory, config);
+            }
+        }
+
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/IndexInputInputStream.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexInputInputStream.cs b/src/Lucene.Net.Replicator/IndexInputInputStream.cs
new file mode 100644
index 0000000..95f6e1c
--- /dev/null
+++ b/src/Lucene.Net.Replicator/IndexInputInputStream.cs
@@ -0,0 +1,102 @@
+//STATUS: INPROGRESS - 4.8.0
+
+using System;
+using System.IO;
+using Lucene.Net.Store;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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>
+    /// 
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public class IndexInputStream : Stream
+    {
+        private readonly IndexInput input;
+        private long remaining;
+
+        public IndexInputStream(IndexInput input)
+        {
+            this.input = input;
+            remaining = input.Length;
+        }
+
+        public override void Flush()
+        {
+            throw new InvalidOperationException("Cannot flush a readonly stream.");
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            switch (origin)
+            {
+                case SeekOrigin.Begin:
+                    Position = offset;
+                    break;
+                case SeekOrigin.Current:
+                    Position += offset;
+                    break;
+                case SeekOrigin.End:
+                    Position = Length - offset;
+                    break;
+            }
+            return Position;
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new InvalidOperationException("Cannot change length of a readonly stream.");
+        }
+
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            int remaining = (int) (input.Length - input.GetFilePointer());
+            input.ReadBytes(buffer, offset, Math.Min(remaining, count));
+            return remaining;
+        }
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            throw new InvalidCastException("Cannot write to a readonly stream.");
+        }
+
+        public override bool CanRead { get { return true; } }
+        public override bool CanSeek { get { return true; } }
+        public override bool CanWrite { get { return false; } }
+        public override long Length { get { return input.Length; } }
+
+        public override long Position
+        {
+            get { return input.GetFilePointer(); }
+            set { input.Seek(value); }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                input.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/IndexReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexReplicationHandler.cs b/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
new file mode 100644
index 0000000..474361a
--- /dev/null
+++ b/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
@@ -0,0 +1,510 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using Lucene.Net.Index;
+using Lucene.Net.Store;
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 <see cref="IReplicationHandler"/> for replication of an index. Implements
+    /// <see cref="RevisionReady"/> by copying the files pointed by the client resolver to
+    /// the index <see cref="Store.Directory"/> and then touches the index with
+    /// <see cref="IndexWriter"/> to make sure any unused files are deleted.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This handler assumes that <see cref="IndexWriter"/> is not opened by
+    /// another process on the index directory. In fact, opening an
+    /// <see cref="IndexWriter"/> on the same directory to which files are copied can lead
+    /// to undefined behavior, where some or all the files will be deleted, override
+    /// other files or simply create a mess. When you replicate an index, it is best
+    /// if the index is never modified by <see cref="IndexWriter"/>, except the one that is
+    /// open on the source index, from which you replicate.
+    /// </para>
+    /// <para>
+    /// This handler notifies the application via a provided <see cref="Callable"/> when an
+    /// updated index commit was made available for it.
+    /// </para>
+    /// 
+    /// Lucene.Experimental
+    /// </remarks>
+    public class IndexReplicationHandler : IReplicationHandler
+    {
+        /// <summary>
+        /// The component used to log messages to the {@link InfoStream#getDefault()
+        /// default} <seealso cref="InfoStream"/>.
+        /// </summary>
+        public const string INFO_STREAM_COMPONENT = "IndexReplicationHandler";
+
+        private readonly Directory indexDirectory;
+        private readonly Func<bool?> callback;
+        private InfoStream infoStream;
+
+        public string CurrentVersion { get; private set; }
+        public IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; private set; }
+
+        public InfoStream InfoStream
+        {
+            get { return infoStream; }
+            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
+        }
+
+        /// <summary>
+        /// Constructor with the given index directory and callback to notify when the
+        /// indexes were updated.
+        /// </summary>
+        /// <param name="indexDirectory"></param>
+        /// <param name="callback"></param>
+        // .NET NOTE: Java uses a Callable<Boolean>, however it is never uses the returned value?
+        public IndexReplicationHandler(Directory indexDirectory, Func<bool?> callback)
+        {
+            #region JAVA
+            //JAVA: this.callback = callback;
+            //JAVA: this.indexDir = indexDir;
+            //JAVA: currentRevisionFiles = null;
+            //JAVA: currentVersion = null;
+            //JAVA: if (DirectoryReader.indexExists(indexDir))
+            //JAVA: {
+            //JAVA:     final List<IndexCommit> commits = DirectoryReader.listCommits(indexDir);
+            //JAVA:     final IndexCommit commit = commits.get(commits.size() - 1);
+            //JAVA:     currentRevisionFiles = IndexRevision.revisionFiles(commit);
+            //JAVA:     currentVersion = IndexRevision.revisionVersion(commit);
+            //JAVA:     final InfoStream infoStream = InfoStream.getDefault();
+            //JAVA:     if (infoStream.isEnabled(INFO_STREAM_COMPONENT))
+            //JAVA:     {
+            //JAVA:         infoStream.message(INFO_STREAM_COMPONENT, "constructor(): currentVersion=" + currentVersion
+            //JAVA:                                                   + " currentRevisionFiles=" + currentRevisionFiles);
+            //JAVA:         infoStream.message(INFO_STREAM_COMPONENT, "constructor(): commit=" + commit);
+            //JAVA:     }
+            //JAVA: }
+            #endregion
+
+            this.InfoStream = InfoStream.Default;
+            this.callback = callback;
+            this.indexDirectory = indexDirectory;
+
+            CurrentVersion = null;
+            CurrentRevisionFiles = null;
+
+            if (DirectoryReader.IndexExists(indexDirectory))
+            {
+                IList<IndexCommit> commits = DirectoryReader.ListCommits(indexDirectory);
+                IndexCommit commit = commits.Last();
+
+                CurrentVersion = IndexRevision.RevisionVersion(commit);
+                CurrentRevisionFiles = IndexRevision.RevisionFiles(commit);
+
+                WriteToInfoStream(
+                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles),
+                    string.Format("constructor(): commit={0}", commit));
+            }
+        }
+
+        public void RevisionReady(string version, 
+            IDictionary<string, IList<RevisionFile>> revisionFiles, 
+            IDictionary<string, IList<string>> copiedFiles, 
+            IDictionary<string, Directory> sourceDirectory)
+        {
+            #region Java
+            //JAVA: if (revisionFiles.size() > 1) {
+            //JAVA:   throw new IllegalArgumentException("this handler handles only a single source; got " + revisionFiles.keySet());
+            //JAVA: }
+            //JAVA: 
+            //JAVA: Directory clientDir = sourceDirectory.values().iterator().next();
+            //JAVA: List<String> files = copiedFiles.values().iterator().next();
+            //JAVA: String segmentsFile = getSegmentsFile(files, false);
+            //JAVA: 
+            //JAVA: boolean success = false;
+            //JAVA: try {
+            //JAVA:   // copy files from the client to index directory
+            //JAVA:   copyFiles(clientDir, indexDir, files);
+            //JAVA:   
+            //JAVA:   // fsync all copied files (except segmentsFile)
+            //JAVA:   indexDir.sync(files);
+            //JAVA:   
+            //JAVA:   // now copy and fsync segmentsFile
+            //JAVA:   clientDir.copy(indexDir, segmentsFile, segmentsFile, IOContext.READONCE);
+            //JAVA:   indexDir.sync(Collections.singletonList(segmentsFile));
+            //JAVA:   
+            //JAVA:   success = true;
+            //JAVA: } finally {
+            //JAVA:   if (!success) {
+            //JAVA:     files.add(segmentsFile); // add it back so it gets deleted too
+            //JAVA:     cleanupFilesOnFailure(indexDir, files);
+            //JAVA:   }
+            //JAVA: }
+            //JAVA:
+            //JAVA: // all files have been successfully copied + sync'd. update the handler's state
+            //JAVA: currentRevisionFiles = revisionFiles;
+            //JAVA: currentVersion = version;
+            //JAVA: 
+            //JAVA: if (infoStream.isEnabled(INFO_STREAM_COMPONENT)) {
+            //JAVA:   infoStream.message(INFO_STREAM_COMPONENT, "revisionReady(): currentVersion=" + currentVersion
+            //JAVA:       + " currentRevisionFiles=" + currentRevisionFiles);
+            //JAVA: }
+            //JAVA:
+            //JAVA: // update the segments.gen file
+            //JAVA: writeSegmentsGen(segmentsFile, indexDir);
+            //JAVA: 
+            //JAVA: // Cleanup the index directory from old and unused index files.
+            //JAVA: // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
+            //JAVA: // side-effects, e.g. if it hits sudden IO errors while opening the index
+            //JAVA: // (and can end up deleting the entire index). It is not our job to protect
+            //JAVA: // against those errors, app will probably hit them elsewhere.
+            //JAVA: cleanupOldIndexFiles(indexDir, segmentsFile);
+            //JAVA:
+            //JAVA: // successfully updated the index, notify the callback that the index is
+            //JAVA: // ready.
+            //JAVA: if (callback != null) {
+            //JAVA:   try {
+            //JAVA:     callback.call();
+            //JAVA:   } catch (Exception e) {
+            //JAVA:     throw new IOException(e);
+            //JAVA:   }
+            //JAVA: }             
+            #endregion
+            //TODO: ArgumentOutOfRangeException more suited?
+            if (revisionFiles.Count > 1) throw new ArgumentException(string.Format("this handler handles only a single source; got {0}", revisionFiles.Keys));
+
+            Directory clientDirectory = sourceDirectory.Values.First();
+            IList<string> files = copiedFiles.Values.First();
+            string segmentsFile = GetSegmentsFile(files, false);
+
+            bool success = false;
+            try
+            {
+                // copy files from the client to index directory
+                 CopyFiles(clientDirectory, indexDirectory, files);
+
+                // fsync all copied files (except segmentsFile)
+                indexDirectory.Sync(files);
+
+                // now copy and fsync segmentsFile
+                clientDirectory.Copy(indexDirectory, segmentsFile, segmentsFile, IOContext.READ_ONCE);
+                indexDirectory.Sync(new[] { segmentsFile });
+                
+                success = true;
+            }
+            finally
+            {
+                if (!success)
+                {
+                    files.Add(segmentsFile); // add it back so it gets deleted too
+                    CleanupFilesOnFailure(indexDirectory, files);
+                }
+            }
+            
+            // all files have been successfully copied + sync'd. update the handler's state
+            CurrentRevisionFiles = revisionFiles;
+            CurrentVersion = version;
+            
+            WriteToInfoStream(string.Format("revisionReady(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles));
+
+            // update the segments.gen file
+            WriteSegmentsGen(segmentsFile, indexDirectory);
+
+            // Cleanup the index directory from old and unused index files.
+            // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
+            // side-effects, e.g. if it hits sudden IO errors while opening the index
+            // (and can end up deleting the entire index). It is not our job to protect
+            // against those errors, app will probably hit them elsewhere.
+            CleanupOldIndexFiles(indexDirectory, segmentsFile);
+            
+            // successfully updated the index, notify the callback that the index is
+            // ready.
+            if (callback != null) {
+              try {
+                callback.Invoke();
+              } catch (Exception e) {
+                throw new IOException(e.Message, e);
+              }
+            }           
+        }
+
+        // .NET NOTE: Utility Method
+        private void WriteToInfoStream(params string[] messages)
+        {
+            if (!InfoStream.IsEnabled(INFO_STREAM_COMPONENT))
+                return;
+
+            foreach (string message in messages)
+                InfoStream.Message(INFO_STREAM_COMPONENT, message);
+        }
+
+        /// <summary>
+        /// Returns the last <see cref="IndexCommit"/> found in the <see cref="Directory"/>, or
+        /// <code>null</code> if there are no commits.
+        /// </summary>
+        /// <param name="directory"></param>
+        /// <returns></returns>
+        /// <exception cref="System.IO.IOException"></exception>
+        public static IndexCommit GetLastCommit(Directory directory)
+        {
+            #region Java
+            //JAVA: try {
+            //JAVA:   if (DirectoryReader.indexExists(dir)) {
+            //JAVA:     List<IndexCommit> commits = DirectoryReader.listCommits(dir);
+            //JAVA:     // listCommits guarantees that we get at least one commit back, or
+            //JAVA:     // IndexNotFoundException which we handle below
+            //JAVA:     return commits.get(commits.size() - 1);
+            //JAVA:   }
+            //JAVA: } catch (IndexNotFoundException e) {
+            //JAVA:   // ignore the exception and return null
+            //JAVA: }
+            //JAVA: return null;       
+            #endregion
+
+            try
+            {
+                // IndexNotFoundException which we handle below
+                return DirectoryReader.IndexExists(directory) 
+                    ? DirectoryReader.ListCommits(directory).Last() 
+                    : null;
+            }
+            catch (IndexNotFoundException)
+            {
+                // ignore the exception and return null
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Verifies that the last file is segments_N and fails otherwise. It also
+        /// removes and returns the file from the list, because it needs to be handled
+        /// last, after all files. This is important in order to guarantee that if a
+        /// reader sees the new segments_N, all other segment files are already on
+        /// stable storage.
+        /// <para>
+        /// The reason why the code fails instead of putting segments_N file last is
+        /// that this indicates an error in the Revision implementation.
+        /// </para>
+        /// </summary>
+        /// <param name="files"></param>
+        /// <param name="allowEmpty"></param>
+        /// <returns></returns>
+        public static string GetSegmentsFile(IList<string> files, bool allowEmpty)
+        {
+            #region Java
+            //JAVA: if (files.isEmpty()) {
+            //JAVA:   if (allowEmpty) {
+            //JAVA:     return null;
+            //JAVA:   } else {
+            //JAVA:     throw new IllegalStateException("empty list of files not allowed");
+            //JAVA:   }
+            //JAVA: }
+            //JAVA: 
+            //JAVA: String segmentsFile = files.remove(files.size() - 1);
+            //JAVA: if (!segmentsFile.startsWith(IndexFileNames.SEGMENTS) || segmentsFile.equals(IndexFileNames.SEGMENTS_GEN)) {
+            //JAVA:   throw new IllegalStateException("last file to copy+sync must be segments_N but got " + segmentsFile
+            //JAVA:       + "; check your Revision implementation!");
+            //JAVA: }
+            //JAVA: return segmentsFile;    
+            #endregion
+
+            if (!files.Any())
+            {
+                if (allowEmpty)
+                    return null;
+                throw new InvalidOperationException("empty list of files not allowed");
+            }
+
+            string segmentsFile = files.Last();
+            //NOTE: Relying on side-effects outside?
+            files.RemoveAt(files.Count - 1);
+            if (!segmentsFile.StartsWith(IndexFileNames.SEGMENTS) || segmentsFile.Equals(IndexFileNames.SEGMENTS_GEN))
+            {
+                throw new InvalidOperationException(
+                    string.Format("last file to copy+sync must be segments_N but got {0}; check your Revision implementation!", segmentsFile));
+            }
+            return segmentsFile;
+        }
+
+        /// <summary>
+        /// Cleanup the index directory by deleting all given files. Called when file
+        /// copy or sync failed.
+        /// </summary>
+        /// <param name="directory"></param>
+        /// <param name="files"></param>
+        public static void CleanupFilesOnFailure(Directory directory, IList<string> files)
+        {
+            #region Java
+            //JAVA: for (String file : files) {
+            //JAVA:     try {
+            //JAVA:         dir.deleteFile(file);
+            //JAVA:     } catch (Throwable t) {
+            //JAVA:         // suppress any exception because if we're here, it means copy
+            //JAVA:         // failed, and we must cleanup after ourselves.
+            //JAVA:     }
+            //JAVA: }
+            #endregion
+
+            foreach (string file in files)
+            {
+                try
+                {
+                    directory.DeleteFile(file);
+                }
+                catch
+                {
+                    // suppress any exception because if we're here, it means copy
+                    // failed, and we must cleanup after ourselves.
+                }
+            }
+        }
+
+        public static void CleanupOldIndexFiles(Directory directory, string segmentsFile)
+        {
+            #region Java
+            //JAVA: try {
+            //JAVA:   IndexCommit commit = getLastCommit(dir);
+            //JAVA:   // commit == null means weird IO errors occurred, ignore them
+            //JAVA:   // if there were any IO errors reading the expected commit point (i.e.
+            //JAVA:   // segments files mismatch), then ignore that commit either.
+            //JAVA:   if (commit != null && commit.getSegmentsFileName().equals(segmentsFile)) {
+            //JAVA:     Set<String> commitFiles = new HashSet<>();
+            //JAVA:     commitFiles.addAll(commit.getFileNames());
+            //JAVA:     commitFiles.add(IndexFileNames.SEGMENTS_GEN);
+            //JAVA:     Matcher matcher = IndexFileNames.CODEC_FILE_PATTERN.matcher("");
+            //JAVA:     for (String file : dir.listAll()) {
+            //JAVA:       if (!commitFiles.contains(file)
+            //JAVA:           && (matcher.reset(file).matches() || file.startsWith(IndexFileNames.SEGMENTS))) {
+            //JAVA:         try {
+            //JAVA:           dir.deleteFile(file);
+            //JAVA:         } catch (Throwable t) {
+            //JAVA:           // suppress, it's just a best effort
+            //JAVA:         }
+            //JAVA:       }
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA: } catch (Throwable t) {
+            //JAVA:   // ignore any errors that happens during this state and only log it. this
+            //JAVA:   // cleanup will have a chance to succeed the next time we get a new
+            //JAVA:   // revision.
+            //JAVA: }             
+            #endregion
+
+            try
+            {
+                IndexCommit commit = GetLastCommit(directory);
+                // commit == null means weird IO errors occurred, ignore them
+                // if there were any IO errors reading the expected commit point (i.e.
+                // segments files mismatch), then ignore that commit either.
+
+                if (commit != null && commit.SegmentsFileName.Equals(segmentsFile))
+                {
+                    HashSet<string> commitFiles = new HashSet<string>( commit.FileNames
+                        .Union(new[] {IndexFileNames.SEGMENTS_GEN}));
+
+                    Regex matcher = IndexFileNames.CODEC_FILE_PATTERN;
+                    foreach (string file in directory.ListAll()
+                        .Where(file => !commitFiles.Contains(file) && (matcher.IsMatch(file) || file.StartsWith(IndexFileNames.SEGMENTS))))
+                    {
+                        try
+                        {
+                            directory.DeleteFile(file);
+                        }
+                        catch
+                        {
+                            // suppress, it's just a best effort
+                        }
+                    }
+
+                }
+            }
+            catch 
+            {
+                // ignore any errors that happens during this state and only log it. this
+                // cleanup will have a chance to succeed the next time we get a new
+                // revision.
+            }
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="source"></param>
+        /// <param name="target"></param>
+        /// <param name="files"></param>
+        /// <exception cref="System.IO.IOException"></exception>
+        public static void CopyFiles(Directory source, Directory target, IList<string> files)
+        {
+            #region Java
+            //JAVA: if (!source.equals(target)) {
+            //JAVA:     for (String file : files) {
+            //JAVA:         source.copy(target, file, file, IOContext.READONCE);
+            //JAVA:     }
+            //JAVA: }
+            #endregion
+
+            if (source.Equals(target))
+                return;
+
+            foreach (string file in files)
+                source.Copy(target, file, file, IOContext.READ_ONCE);
+        }
+
+        /// <summary>
+        /// Writes <see cref="IndexFileNames.SEGMENTS_GEN"/> file to the directory, reading
+        /// the generation from the given <code>segmentsFile</code>. If it is <code>null</code>,
+        /// this method deletes segments.gen from the directory.
+        /// </summary>
+        /// <param name="segmentsFile"></param>
+        /// <param name="directory"></param>
+        public static void WriteSegmentsGen(string segmentsFile, Directory directory)
+        {
+            #region Java
+            //JAVA: public static void writeSegmentsGen(String segmentsFile, Directory dir) {
+            //JAVA:   if (segmentsFile != null) {
+            //JAVA:     SegmentInfos.writeSegmentsGen(dir, SegmentInfos.generationFromSegmentsFileName(segmentsFile));
+            //JAVA:   } else {
+            //JAVA:     try {
+            //JAVA:       dir.deleteFile(IndexFileNames.SEGMENTS_GEN);
+            //JAVA:     } catch (Throwable t) {
+            //JAVA:       // suppress any errors while deleting this file.
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            if (segmentsFile != null)
+            {
+                SegmentInfos.WriteSegmentsGen(directory, SegmentInfos.GenerationFromSegmentsFileName(segmentsFile));
+                return;
+            }
+
+            try
+            {
+                directory.DeleteFile(IndexFileNames.SEGMENTS_GEN);
+            }
+            catch
+            {
+                // suppress any errors while deleting this file.
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/IndexRevision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexRevision.cs b/src/Lucene.Net.Replicator/IndexRevision.cs
new file mode 100644
index 0000000..930b120
--- /dev/null
+++ b/src/Lucene.Net.Replicator/IndexRevision.cs
@@ -0,0 +1,200 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using Lucene.Net.Index;
+using Lucene.Net.Store;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 <see cref="IRevision"/> of a single index files which comprises the list of files
+    /// that are part of the current <see cref="IndexCommit"/>. To ensure the files are not
+    /// deleted by <see cref="IndexWriter"/> for as long as this revision stays alive (i.e.
+    /// until <see cref="Release"/>, the current commit point is snapshotted, using
+    /// <see cref="SnapshotDeletionPolicy"/> (this means that the given writer's
+    /// <see cref="IndexWriterConfig.IndexDeletionPolicy"/> should return
+    /// <see cref="SnapshotDeletionPolicy"/>).
+    /// <p>
+    /// When this revision is <see cref="Release"/>d, it releases the obtained
+    /// snapshot as well as calls <see cref="IndexWriter.DeleteUnusedFiles"/> so that the
+    /// snapshotted files are deleted (if they are no longer needed).
+    /// </p>
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public class IndexRevision : IRevision
+    {
+        #region Java
+        //JAVA: private static final int RADIX = 16;
+        //JAVA: private static final String SOURCE = "index";
+        //JAVA: private final IndexWriter writer;
+        //JAVA: private final IndexCommit commit;
+        //JAVA: private final SnapshotDeletionPolicy sdp;
+        //JAVA: private final String version;
+        //JAVA: private final Map<String, List<RevisionFile>> sourceFiles;
+        #endregion
+
+        private const string SOURCE = "index";
+
+        private readonly IndexWriter writer;
+        private readonly IndexCommit commit;
+        private readonly SnapshotDeletionPolicy sdp;
+
+        public string Version { get; private set; }
+        public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
+
+        public IndexRevision(IndexWriter writer)
+        {
+            #region Java
+            //JAVA: public IndexRevision(IndexWriter writer) throws IOException {
+            //JAVA:   IndexDeletionPolicy delPolicy = writer.getConfig().getIndexDeletionPolicy();
+            //JAVA:   if (!(delPolicy instanceof SnapshotDeletionPolicy)) {
+            //JAVA:     throw new IllegalArgumentException("IndexWriter must be created with SnapshotDeletionPolicy");
+            //JAVA:   }
+            //JAVA:   this.writer = writer;
+            //JAVA:   this.sdp = (SnapshotDeletionPolicy) delPolicy;
+            //JAVA:   this.commit = sdp.snapshot();
+            //JAVA:   this.version = revisionVersion(commit);
+            //JAVA:   this.sourceFiles = revisionFiles(commit);
+            //JAVA: }              
+            #endregion
+
+            sdp = writer.Config.IndexDeletionPolicy as SnapshotDeletionPolicy;
+            if (sdp == null)
+                throw new ArgumentException("IndexWriter must be created with SnapshotDeletionPolicy", "writer");
+
+            this.writer = writer;
+            this.commit = sdp.Snapshot();
+            this.Version = RevisionVersion(commit);
+            this.SourceFiles = RevisionFiles(commit);
+        }
+
+        public int CompareTo(string version)
+        {
+            #region Java
+            //JAVA: long gen = Long.parseLong(version, RADIX);
+            //JAVA: long commitGen = commit.getGeneration();
+            //JAVA: return commitGen < gen ? -1 : (commitGen > gen ? 1 : 0);
+            #endregion
+            long gen = long.Parse(version, NumberStyles.HexNumber);
+            long commitGen = commit.Generation;
+            //TODO: long.CompareTo(); but which goes where.
+            return commitGen < gen ? -1 : (commitGen > gen ? 1 : 0);
+        }
+
+        public int CompareTo(IRevision other)
+        {
+            #region Java
+            //JAVA: IndexRevision other = (IndexRevision)o;
+            //JAVA: return commit.compareTo(other.commit);
+            #endregion
+            //TODO: This breaks the contract and will fail if called with a different implementation
+            //      This is a flaw inherited from the original source...
+            //      It should at least provide a better description to the InvalidCastException
+            IndexRevision or = (IndexRevision)other;
+            return commit.CompareTo(or.commit);
+        }
+
+        public Stream Open(string source, string fileName)
+        {
+            Debug.Assert(source.Equals(SOURCE), string.Format("invalid source; expected={0} got={1}", SOURCE, source));
+            return new IndexInputStream(commit.Directory.OpenInput(fileName, IOContext.READ_ONCE));
+        }
+
+        public void Release()
+        {
+            sdp.Release(commit);
+            writer.DeleteUnusedFiles();
+        }
+
+        public override string ToString()
+        {
+            return "IndexRevision version=" + Version + " files=" + SourceFiles;
+        }
+
+        // returns a RevisionFile with some metadata
+        private static RevisionFile CreateRevisionFile(string fileName, Directory directory)
+        {
+            #region Java
+            //JAVA: private static RevisionFile newRevisionFile(String file, Directory dir) throws IOException {
+            //JAVA:   RevisionFile revFile = new RevisionFile(file);
+            //JAVA:   revFile.size = dir.fileLength(file);
+            //JAVA:   return revFile;
+            //JAVA: }             
+            #endregion
+            return new RevisionFile(fileName, directory.FileLength(fileName));
+        }
+
+        /** Returns a singleton map of the revision files from the given {@link IndexCommit}. */
+        public static IDictionary<string, IList<RevisionFile>> RevisionFiles(IndexCommit commit)
+        {
+            #region Java
+            //JAVA: public static Map<String,List<RevisionFile>> revisionFiles(IndexCommit commit) throws IOException {
+            //JAVA:   Collection<String> commitFiles = commit.getFileNames();
+            //JAVA:   List<RevisionFile> revisionFiles = new ArrayList<>(commitFiles.size());
+            //JAVA:   String segmentsFile = commit.getSegmentsFileName();
+            //JAVA:   Directory dir = commit.getDirectory();
+            //JAVA:   
+            //JAVA:   for (String file : commitFiles) {
+            //JAVA:     if (!file.equals(segmentsFile)) {
+            //JAVA:       revisionFiles.add(newRevisionFile(file, dir));
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA:   revisionFiles.add(newRevisionFile(segmentsFile, dir)); // segments_N must be last
+            //JAVA:   return Collections.singletonMap(SOURCE, revisionFiles);
+            //JAVA: }
+            #endregion
+
+            List<RevisionFile> revisionFiles = commit.FileNames
+                .Where(file => !string.Equals(file, commit.SegmentsFileName))
+                .Select(file => CreateRevisionFile(file, commit.Directory))
+                //Note: segments_N must be last
+                .Union(new[] {CreateRevisionFile(commit.SegmentsFileName, commit.Directory)})
+                .ToList();
+            return new Dictionary<string, IList<RevisionFile>>
+            {
+                { SOURCE, revisionFiles }
+            };
+        }
+   
+        /// <summary>
+        /// Returns a String representation of a revision's version from the given <see cref="IndexCommit"/>
+        /// </summary>
+        /// <param name="commit"></param>
+        /// <returns></returns>
+        public static string RevisionVersion(IndexCommit commit)
+        {
+            #region Java
+            //JAVA: public static String revisionVersion(IndexCommit commit) {
+            //JAVA:   return Long.toString(commit.getGeneration(), RADIX);
+            //JAVA: }  
+            #endregion           
+            return commit.Generation.ToString("X");
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Replicator/LocalReplicator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/LocalReplicator.cs b/src/Lucene.Net.Replicator/LocalReplicator.cs
new file mode 100644
index 0000000..ae3a3a9
--- /dev/null
+++ b/src/Lucene.Net.Replicator/LocalReplicator.cs
@@ -0,0 +1,416 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using Lucene.Net.Search;
+using Lucene.Net.Support;
+
+namespace Lucene.Net.Replicator
+{
+    /*
+	 * 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 <see cref="IReplicator"/> implementation for use by the side that publishes
+    /// <see cref="IRevision"/>s, as well for clients to <see cref="CheckForUpdate"/>
+    /// check for updates}. When a client needs to be updated, it is returned a
+    /// <see cref="SessionToken"/> through which it can
+    /// <see cref="ObtainFile"/> the files of that
+    /// revision. As long as a revision is being replicated, this replicator
+    /// guarantees that it will not be <seealso cref="IRevision.Release"/>.
+    /// <para>
+    /// Replication sessions expire by default after
+    /// <seealso cref="DEFAULT_SESSION_EXPIRATION_THRESHOLD"/>, and the threshold can be
+    /// configured through <seealso cref="ExpirationThreshold"/>.
+    /// </para>
+    /// </summary>
+    /// <remarks>
+    /// Lucene.Experimental
+    /// </remarks>
+    public class LocalReplicator : IReplicator
+    {
+        /// <summary>Threshold for expiring inactive sessions. Defaults to 30 minutes.</summary>
+        public const long DEFAULT_SESSION_EXPIRATION_THRESHOLD = 1000 * 60 * 30;
+
+        private long expirationThreshold = DEFAULT_SESSION_EXPIRATION_THRESHOLD;
+        private readonly object padlock = new object();
+        private volatile RefCountedRevision currentRevision;
+        private volatile bool disposed = false;
+
+        private readonly AtomicInt32 sessionToken = new AtomicInt32(0);
+        private readonly Dictionary<string, ReplicationSession> sessions = new Dictionary<string, ReplicationSession>();
+
+        /// <summary>
+        /// Returns the expiration threshold.
+        /// </summary>
+        public long ExpirationThreshold
+        {
+            get { return expirationThreshold; }
+            set
+            {
+                lock (padlock)
+                {
+                    EnsureOpen();
+                    expirationThreshold = value;
+                    CheckExpiredSessions();
+                }
+            }
+        }
+
+        public void Publish(IRevision revision)
+        {
+            #region Java
+            //JAVA: public synchronized void publish(Revision revision) throws IOException {
+            //JAVA:   ensureOpen();
+            //JAVA:   if (currentRevision != null) {
+            //JAVA:     int compare = revision.compareTo(currentRevision.revision);
+            //JAVA:     if (compare == 0) {
+            //JAVA:       // same revision published again, ignore but release it
+            //JAVA:       revision.release();
+            //JAVA:       return;
+            //JAVA:     }
+            //JAVA:
+            //JAVA:     if (compare < 0) {
+            //JAVA:       revision.release();
+            //JAVA:       throw new IllegalArgumentException("Cannot publish an older revision: rev=" + revision + " current="
+            //JAVA:           + currentRevision);
+            //JAVA:     } 
+            //JAVA:   }
+            //JAVA:
+            //JAVA:   // swap revisions
+            //JAVA:   final RefCountedRevision oldRevision = currentRevision;
+            //JAVA:   currentRevision = new RefCountedRevision(revision);
+            //JAVA:   if (oldRevision != null) {
+            //JAVA:     oldRevision.decRef();
+            //JAVA:   }
+            //JAVA:
+            //JAVA:   // check for expired sessions
+            //JAVA:   checkExpiredSessions();
+            //JAVA: } 
+            #endregion
+
+            lock (padlock)
+            {
+                EnsureOpen();
+
+                if (currentRevision != null)
+                {
+                    int compare = revision.CompareTo(currentRevision.Revision);
+                    if (compare == 0)
+                    {
+                        // same revision published again, ignore but release it
+                        revision.Release();
+                        return;
+                    }
+
+                    if (compare < 0)
+                    {
+                        revision.Release();
+                        throw new ArgumentException(string.Format("Cannot publish an older revision: rev={0} current={1}", revision, currentRevision), "revision");
+                    }
+                }
+
+                RefCountedRevision oldRevision = currentRevision;
+                currentRevision = new RefCountedRevision(revision);
+                if(oldRevision != null) 
+                    oldRevision.DecRef();
+
+                CheckExpiredSessions();
+            }
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="currentVersion"></param>
+        /// <returns></returns>
+        public SessionToken CheckForUpdate(string currentVersion)
+        {
+            #region Java
+            //JAVA: public synchronized SessionToken checkForUpdate(String currentVersion) {
+            //JAVA:   ensureOpen();
+            //JAVA:   if (currentRevision == null) { // no published revisions yet
+            //JAVA:     return null;
+            //JAVA:   }
+            //JAVA:
+            //JAVA:   if (currentVersion != null && currentRevision.revision.compareTo(currentVersion) <= 0) {
+            //JAVA:     // currentVersion is newer or equal to latest published revision
+            //JAVA:     return null;
+            //JAVA:   }
+            //JAVA:
+            //JAVA:   // currentVersion is either null or older than latest published revision
+            //JAVA:   currentRevision.incRef();
+            //JAVA:   final String sessionID = Integer.toString(sessionToken.incrementAndGet());
+            //JAVA:   final SessionToken sessionToken = new SessionToken(sessionID, currentRevision.revision);
+            //JAVA:   final ReplicationSession timedSessionToken = new ReplicationSession(sessionToken, currentRevision);
+            //JAVA:   sessions.put(sessionID, timedSessionToken);
+            //JAVA:   return sessionToken;
+            //JAVA: } 
+            #endregion
+
+            lock (padlock)
+            {
+                EnsureOpen();
+                if (currentRevision == null)
+                    return null; // no published revisions yet
+
+                if (currentVersion != null && currentRevision.Revision.CompareTo(currentVersion) <= 0)
+                    return null; // currentVersion is newer or equal to latest published revision
+
+                // currentVersion is either null or older than latest published revision
+                currentRevision.IncRef();
+
+                string sessionID = sessionToken.IncrementAndGet().ToString();
+                SessionToken token = new SessionToken(sessionID, currentRevision.Revision);
+                sessions[sessionID] = new ReplicationSession(token, currentRevision);
+                return token;
+            }
+
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="sessionId"></param>
+        /// <exception cref="InvalidOperationException"></exception>
+        public void Release(string sessionId)
+        {
+            lock (padlock)
+            {
+                EnsureOpen();
+                ReleaseSession(sessionId);
+            }
+        }
+
+        public Stream ObtainFile(string sessionId, string source, string fileName)
+        {
+            #region Java
+            //JAVA: public synchronized InputStream obtainFile(String sessionID, String source, String fileName) throws IOException {
+            //JAVA:   ensureOpen();
+            //JAVA:   ReplicationSession session = sessions.get(sessionID);
+            //JAVA:   if (session != null && session.isExpired(expirationThresholdMilllis)) {
+            //JAVA:     releaseSession(sessionID);
+            //JAVA:     session = null;
+            //JAVA:   }
+            //JAVA:   // session either previously expired, or we just expired it
+            //JAVA:   if (session == null) {
+            //JAVA:     throw new SessionExpiredException("session (" + sessionID + ") expired while obtaining file: source=" + source
+            //JAVA:         + " file=" + fileName);
+            //JAVA:   }
+            //JAVA:   sessions.get(sessionID).markAccessed();
+            //JAVA:   return session.revision.revision.open(source, fileName);
+            //JAVA: }
+            #endregion
+
+            lock (padlock)
+            {
+                EnsureOpen();
+
+                ReplicationSession session = sessions[sessionId];
+                if (session != null && session.IsExpired(ExpirationThreshold))
+                {
+                    ReleaseSession(sessionId);
+                    session = null;
+                }
+                // session either previously expired, or we just expired it
+                if (session == null)
+                {
+                    throw new SessionExpiredException(string.Format("session ({0}) expired while obtaining file: source={1} file={2}", sessionId, source, fileName));
+                }
+                sessions[sessionId].MarkAccessed();
+                return session.Revision.Revision.Open(source, fileName);
+            }
+
+        }
+
+        public void Dispose()
+        {
+            #region Java
+            //JAVA: public synchronized void close() throws IOException {
+            //JAVA:   if (!closed) {
+            //JAVA:     // release all managed revisions
+            //JAVA:     for (ReplicationSession session : sessions.values()) {
+            //JAVA:       session.revision.decRef();
+            //JAVA:     }
+            //JAVA:     sessions.clear();
+            //JAVA:     closed = true;
+            //JAVA:   }
+            //JAVA: }
+            #endregion
+
+            if (disposed)
+                return;
+
+            lock (padlock)
+            {
+                foreach (ReplicationSession session in sessions.Values)
+                    session.Revision.DecRef();
+                sessions.Clear();
+            }
+            disposed = true;
+        }
+
+        /// <exception cref="InvalidOperationException"></exception>
+        private void CheckExpiredSessions()
+        {
+            #region Java
+            //JAVA: private void checkExpiredSessions() throws IOException {
+            //JAVA:   // make a "to-delete" list so we don't risk deleting from the map while iterating it
+            //JAVA:   final ArrayList<ReplicationSession> toExpire = new ArrayList<>();
+            //JAVA:   for (ReplicationSession token : sessions.values()) {
+            //JAVA:     if (token.isExpired(expirationThresholdMilllis)) {
+            //JAVA:       toExpire.add(token);
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA:   for (ReplicationSession token : toExpire) {
+            //JAVA:     releaseSession(token.session.id);
+            //JAVA:   }
+            //JAVA: }  
+            #endregion
+            
+            // .NET NOTE: .ToArray() so we don't modify a collection we are enumerating...
+            //            I am wondering if it would be overall more practical to switch to a concurrent dictionary...
+            foreach (ReplicationSession token in sessions.Values.Where(token => token.IsExpired(ExpirationThreshold)).ToArray())
+            {
+                ReleaseSession(token.Session.Id);
+            }
+        }
+
+        /// <exception cref="InvalidOperationException"></exception>
+        private void ReleaseSession(string sessionId)
+        {
+            #region Java
+            //JAVA: private void releaseSession(String sessionID) throws IOException {
+            //JAVA:   ReplicationSession session = sessions.remove(sessionID);
+            //JAVA:   // if we're called concurrently by close() and release(), could be that one
+            //JAVA:   // thread beats the other to release the session.
+            //JAVA:   if (session != null) {
+            //JAVA:     session.revision.decRef();
+            //JAVA:   }
+            //JAVA: }          
+            #endregion
+
+            ReplicationSession session;
+            // if we're called concurrently by close() and release(), could be that one
+            // thread beats the other to release the session.
+            if (sessions.TryGetValue(sessionId, out session))
+            {
+                sessions.Remove(sessionId);
+                session.Revision.DecRef();
+            }
+        }
+
+        /// <summary>
+        /// Ensure that replicator is still open, or throw <see cref="ObjectDisposedException"/> otherwise.
+        /// </summary>
+        /// <exception cref="ObjectDisposedException">This replicator has already been closed</exception>
+        protected void EnsureOpen()
+        {
+            lock (padlock)
+            {
+                if (!disposed)
+                    return;
+
+                throw new ObjectDisposedException("This replicator has already been disposed");
+            }
+        }
+
+        private class RefCountedRevision
+        {
+            private readonly AtomicInt32 refCount = new AtomicInt32(1);
+
+            public IRevision Revision { get; private set; }
+
+            public RefCountedRevision(IRevision revision)
+            {
+                Revision = revision;
+            }
+
+            /// <summary/>
+            /// <exception cref="InvalidOperationException"></exception>
+            public void DecRef()
+            {
+                if (refCount.Get() <= 0)
+                {
+                    //JAVA: throw new IllegalStateException("this revision is already released");
+                    throw new InvalidOperationException("this revision is already released");
+                }
+
+                var rc = refCount.DecrementAndGet();
+                if (rc == 0)
+                {
+                    bool success = false;
+                    try
+                    {
+                        Revision.Release();
+                        success = true;
+                    }
+                    finally
+                    {
+                        if (!success)
+                        {
+                            // Put reference back on failure
+                            refCount.IncrementAndGet();
+                        }
+                    }
+                }
+                else if (rc < 0)
+                {
+                    //JAVA: throw new IllegalStateException("too many decRef calls: refCount is " + rc + " after decrement");
+                    throw new InvalidOperationException(string.Format("too many decRef calls: refCount is {0} after decrement", rc));
+                }
+            }
+
+            public void IncRef()
+            {
+                refCount.IncrementAndGet();
+            }       
+        }
+
+        private class ReplicationSession
+        {
+            public SessionToken Session { get; private set; }
+            public RefCountedRevision Revision { get; private set; }
+
+            private long lastAccessTime;
+
+            public ReplicationSession(SessionToken session, RefCountedRevision revision)
+            {
+                Session = session;
+                Revision = revision;
+                //JAVA: lastAccessTime = System.currentTimeMillis();
+                lastAccessTime = Stopwatch.GetTimestamp();
+            }
+
+            public bool IsExpired(long expirationThreshold)
+            {
+                //JAVA: return lastAccessTime < (System.currentTimeMillis() - expirationThreshold);
+                return lastAccessTime < Stopwatch.GetTimestamp() - expirationThreshold * Stopwatch.Frequency / 1000;
+            }
+
+            public void MarkAccessed()
+            {
+                //JAVA: lastAccessTime = System.currentTimeMillis();
+                lastAccessTime = Stopwatch.GetTimestamp();
+            }
+        }
+
+    }
+}
\ No newline at end of file


[10/20] lucenenet git commit: Lucene.Net.Replicator: Fixed member accessibility

Posted by ni...@apache.org.
Lucene.Net.Replicator: Fixed member accessibility


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

Branch: refs/heads/replicator
Commit: 73f6a4e2891a42371125fe40e7bb6c9b18176456
Parents: 6788246
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 02:42:27 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 02:42:27 2017 +0700

----------------------------------------------------------------------
 .../Http/HttpClientBase.cs                      | 28 +++++-----
 .../Http/HttpReplicator.cs                      | 12 ++---
 .../Http/ReplicationService.cs                  | 10 ++--
 .../IndexAndTaxonomyReplicationHandler.cs       | 55 +++++++++++---------
 .../IndexAndTaxonomyRevision.cs                 | 52 ++++++++++--------
 .../IndexInputInputStream.cs                    |  4 +-
 .../IndexReplicationHandler.cs                  | 35 +++++++------
 src/Lucene.Net.Replicator/IndexRevision.cs      | 26 ++++-----
 src/Lucene.Net.Replicator/LocalReplicator.cs    | 30 ++++++-----
 .../PerSessionDirectoryFactory.cs               |  6 +--
 src/Lucene.Net.Replicator/ReplicationClient.cs  | 22 ++++----
 src/Lucene.Net.Replicator/RevisionFile.cs       |  2 +-
 12 files changed, 151 insertions(+), 131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/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
index 8f46b98..361d0b9 100644
--- a/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
+++ b/src/Lucene.Net.Replicator/Http/HttpClientBase.cs
@@ -1,12 +1,12 @@
-using System;
+using Lucene.Net.Support;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
 using System.IO;
 using System.Linq;
 using System.Net;
 using System.Net.Http;
 using System.Text;
-using Lucene.Net.Support;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
 
 namespace Lucene.Net.Replicator.Http
 {
@@ -48,8 +48,8 @@ namespace Lucene.Net.Replicator.Http
         /// </summary>
         protected string Url { get; private set; }
 
-        private readonly HttpClient httpc;
         private volatile bool isDisposed = false;
+        private readonly HttpClient httpc;
 
         /// <summary>
         /// Creates a new <see cref="HttpClientBase"/> with the given host, port and path.
@@ -106,7 +106,7 @@ namespace Lucene.Net.Replicator.Http
         /// 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
+        public virtual int ConnectionTimeout
         {
             get { return (int)httpc.Timeout.TotalMilliseconds; }
             set { httpc.Timeout = TimeSpan.FromMilliseconds(value); }
@@ -139,7 +139,7 @@ namespace Lucene.Net.Replicator.Http
         /// </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)
+        protected virtual void VerifyStatus(HttpResponseMessage response)
         {
             if (!response.IsSuccessStatusCode)
             {
@@ -152,7 +152,7 @@ namespace Lucene.Net.Replicator.Http
         /// </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)
+        protected virtual void ThrowKnownError(HttpResponseMessage response)
         {
             Stream input;
             try
@@ -199,7 +199,7 @@ namespace Lucene.Net.Replicator.Http
         /// <b>Internal:</b> Execute a request and return its result.
         /// The <paramref name="parameters"/> argument is treated as: name1,value1,name2,value2,...
         /// </summary>
-        protected HttpResponseMessage ExecutePost(string request, object entity, params string[] parameters)
+        protected virtual HttpResponseMessage ExecutePost(string request, object entity, params string[] parameters)
         {
             EnsureOpen();
             //.NET Note: No headers? No ContentType?... Bad use of Http?
@@ -219,7 +219,7 @@ namespace Lucene.Net.Replicator.Http
         /// <b>Internal:</b> Execute a request and return its result.
         /// The <paramref name="parameters"/> argument is treated as: name1,value1,name2,value2,...
         /// </summary>
-        protected HttpResponseMessage ExecuteGet(string request, params string[] parameters)
+        protected virtual HttpResponseMessage ExecuteGet(string request, params string[] parameters)
         {
             EnsureOpen();
             //Note: No headers? No ContentType?... Bad use of Http?
@@ -243,7 +243,7 @@ namespace Lucene.Net.Replicator.Http
         /// Internal utility: input stream of the provided response.
         /// </summary>
         /// <exception cref="IOException"></exception>
-        public Stream ResponseInputStream(HttpResponseMessage response)
+        public virtual Stream ResponseInputStream(HttpResponseMessage response)
         {
             return ResponseInputStream(response, false);
         }
@@ -254,7 +254,7 @@ namespace Lucene.Net.Replicator.Http
         /// consumes the response's resources when the input stream is exhausted.
         /// </summary>
         /// <exception cref="IOException"></exception>
-        public Stream ResponseInputStream(HttpResponseMessage response, bool consume)
+        public virtual Stream ResponseInputStream(HttpResponseMessage response, bool consume)
         {
             return response.Content.ReadAsStreamAsync().ConfigureAwait(false).GetAwaiter().GetResult();
         }
@@ -269,7 +269,7 @@ namespace Lucene.Net.Replicator.Http
         /// <summary>
         /// Calls the overload <see cref="DoAction{T}(HttpResponseMessage, bool, Func{T})"/> passing <c>true</c> to consume.
         /// </summary>
-        protected T DoAction<T>(HttpResponseMessage response, Func<T> call)
+        protected virtual T DoAction<T>(HttpResponseMessage response, Func<T> call)
         {
             return DoAction(response, true, call);
         }
@@ -279,7 +279,7 @@ namespace Lucene.Net.Replicator.Http
         /// and if not, attempt to extract the actual server side exception. Optionally
         /// release the response at exit, depending on <paramref name="consume"/> parameter.
         /// </summary>
-        protected T DoAction<T>(HttpResponseMessage response, bool consume, Func<T> call)
+        protected virtual T DoAction<T>(HttpResponseMessage response, bool consume, Func<T> call)
         {
             Exception error = new NotImplementedException();
             try

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/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
index 052450a..860ef54 100644
--- a/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
+++ b/src/Lucene.Net.Replicator/Http/HttpReplicator.cs
@@ -1,7 +1,7 @@
-using System;
+using Lucene.Net.Support.IO;
+using System;
 using System.IO;
 using System.Net.Http;
-using Lucene.Net.Support.IO;
 
 namespace Lucene.Net.Replicator.Http
 {
@@ -62,7 +62,7 @@ namespace Lucene.Net.Replicator.Http
         /// <summary>
         /// Checks for updates at the remote host.
         /// </summary>
-        public SessionToken CheckForUpdate(string currentVersion)
+        public virtual SessionToken CheckForUpdate(string currentVersion)
         {
             string[] parameters = null;
             if (currentVersion != null)
@@ -81,7 +81,7 @@ namespace Lucene.Net.Replicator.Http
         /// <summary>
         /// Obtains the given file from it's source at the remote host.
         /// </summary>
-        public Stream ObtainFile(string sessionId, string source, string fileName)
+        public virtual Stream ObtainFile(string sessionId, string source, string fileName)
         {
             HttpResponseMessage response = ExecuteGet(ReplicationService.ReplicationAction.OBTAIN.ToString(),
                 ReplicationService.REPLICATE_SESSION_ID_PARAM, sessionId,
@@ -94,7 +94,7 @@ namespace Lucene.Net.Replicator.Http
         /// Not supported.
         /// </summary>
         /// <exception cref="NotSupportedException">this replicator implementation does not support remote publishing of revisions</exception>
-        public void Publish(IRevision revision)
+        public virtual void Publish(IRevision revision)
         {
             throw new NotSupportedException("this replicator implementation does not support remote publishing of revisions");
         }
@@ -102,7 +102,7 @@ namespace Lucene.Net.Replicator.Http
         /// <summary>
         /// Releases a session obtained from the remote host.
         /// </summary>
-        public void Release(string sessionId)
+        public virtual void Release(string sessionId)
         {
             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!

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/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
index 95c8b50..9290683 100644
--- a/src/Lucene.Net.Replicator/Http/ReplicationService.cs
+++ b/src/Lucene.Net.Replicator/Http/ReplicationService.cs
@@ -1,9 +1,9 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using Lucene.Net.Replicator.Http.Abstractions;
+using Lucene.Net.Replicator.Http.Abstractions;
 using Lucene.Net.Support.IO;
 using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
 
 namespace Lucene.Net.Replicator.Http
 {
@@ -130,7 +130,7 @@ namespace Lucene.Net.Replicator.Http
         /// Executes the replication task.
         /// </summary>
         /// <exception cref="InvalidOperationException">required parameters are missing</exception>
-        public void Perform(IReplicationRequest request, IReplicationResponse response)
+        public virtual void Perform(IReplicationRequest request, IReplicationResponse response)
         {
             string[] pathElements = GetPathElements(request);
             if (pathElements.Length != 2)

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs b/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
index d6a3ce0..80d6432 100644
--- a/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
+++ b/src/Lucene.Net.Replicator/IndexAndTaxonomyReplicationHandler.cs
@@ -1,10 +1,10 @@
-using System;
+using Lucene.Net.Index;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
-using Lucene.Net.Index;
-using Lucene.Net.Store;
-using Lucene.Net.Util;
 using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Replicator
@@ -53,19 +53,9 @@ namespace Lucene.Net.Replicator
         private readonly Directory taxonomyDirectory;
         private readonly Func<bool?> callback;
 
-        private InfoStream infoStream = InfoStream.Default;
-
-        public string CurrentVersion { get; private set; }
-        public IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; private set; }
-
-        /// <summary>
-        /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages.
-        /// </summary>
-        public InfoStream InfoStream
-        {
-            get { return infoStream; }
-            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
-        }
+        private volatile IDictionary<string, IList<RevisionFile>> currentRevisionFiles;
+        private volatile string currentVersion;
+        private volatile InfoStream infoStream = InfoStream.Default;
 
         /// <summary>
         /// Constructor with the given index directory and callback to notify when the indexes were updated.
@@ -77,8 +67,8 @@ namespace Lucene.Net.Replicator
             this.taxonomyDirectory = taxonomyDirectory;
             this.callback = callback;
 
-            CurrentVersion = null;
-            CurrentRevisionFiles = null;
+            currentVersion = null;
+            currentRevisionFiles = null;
 
             bool indexExists = DirectoryReader.IndexExists(indexDirectory);
             bool taxonomyExists = DirectoryReader.IndexExists(taxonomyDirectory);
@@ -91,16 +81,19 @@ namespace Lucene.Net.Replicator
                 IndexCommit indexCommit = IndexReplicationHandler.GetLastCommit(indexDirectory);
                 IndexCommit taxonomyCommit = IndexReplicationHandler.GetLastCommit(taxonomyDirectory);
 
-                CurrentRevisionFiles = IndexAndTaxonomyRevision.RevisionFiles(indexCommit, taxonomyCommit);
-                CurrentVersion = IndexAndTaxonomyRevision.RevisionVersion(indexCommit, taxonomyCommit);
+                currentRevisionFiles = IndexAndTaxonomyRevision.RevisionFiles(indexCommit, taxonomyCommit);
+                currentVersion = IndexAndTaxonomyRevision.RevisionVersion(indexCommit, taxonomyCommit);
 
                 WriteToInfoStream(
-                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles),
+                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", currentVersion, currentRevisionFiles),
                     string.Format("constructor(): indexCommit={0} taxoCommit={1}", indexCommit, taxonomyCommit));
             }
         }
 
-        public void RevisionReady(string version,
+        public virtual string CurrentVersion { get { return currentVersion; } }
+        public virtual IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get { return currentRevisionFiles; } }
+
+        public virtual void RevisionReady(string version,
             IDictionary<string, IList<RevisionFile>> revisionFiles,
             IDictionary<string, IList<string>> copiedFiles,
             IDictionary<string, Directory> sourceDirectory)
@@ -148,10 +141,10 @@ namespace Lucene.Net.Replicator
             }
 
             // all files have been successfully copied + sync'd. update the handler's state
-            CurrentRevisionFiles = revisionFiles;
-            CurrentVersion = version;
+            currentRevisionFiles = revisionFiles;
+            currentVersion = version;
             
-            WriteToInfoStream("revisionReady(): currentVersion=" + CurrentVersion + " currentRevisionFiles=" + CurrentRevisionFiles);
+            WriteToInfoStream("revisionReady(): currentVersion=" + currentVersion + " currentRevisionFiles=" + currentRevisionFiles);
             
             // update the segments.gen file
             IndexReplicationHandler.WriteSegmentsGen(taxonomySegmentsFile, taxonomyDirectory);
@@ -176,6 +169,7 @@ namespace Lucene.Net.Replicator
             } 
         }
 
+        // LUCENENET specific utility method
         private void WriteToInfoStream(params string[] messages)
         {
             if (!InfoStream.IsEnabled(INFO_STREAM_COMPONENT))
@@ -184,5 +178,14 @@ namespace Lucene.Net.Replicator
             foreach (string message in messages)
                 InfoStream.Message(INFO_STREAM_COMPONENT, message);
         }
+
+        /// <summary>
+        /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages.
+        /// </summary>
+        public virtual InfoStream InfoStream
+        {
+            get { return infoStream; }
+            set { infoStream = value ?? InfoStream.NO_OUTPUT; }
+        }
     }
 }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs b/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
index 63040b0..e501a58 100644
--- a/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
+++ b/src/Lucene.Net.Replicator/IndexAndTaxonomyRevision.cs
@@ -1,13 +1,13 @@
-using System;
+using Lucene.Net.Facet.Taxonomy.Directory;
+using Lucene.Net.Facet.Taxonomy.WriterCache;
+using Lucene.Net.Index;
+using Lucene.Net.Store;
+using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;
 using System.IO;
 using System.Linq;
-using Lucene.Net.Facet.Taxonomy.Directory;
-using Lucene.Net.Facet.Taxonomy.WriterCache;
-using Lucene.Net.Index;
-using Lucene.Net.Store;
 using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Replicator
@@ -48,14 +48,8 @@ namespace Lucene.Net.Replicator
         /// </summary>
         public class SnapshotDirectoryTaxonomyWriter : DirectoryTaxonomyWriter
         {
-            /// <summary>
-            /// Gets the <see cref="SnapshotDeletionPolicy"/> used by the underlying <see cref="Index.IndexWriter"/>.
-            /// </summary>
-            public SnapshotDeletionPolicy DeletionPolicy { get; private set; }
-            /// <summary>
-            /// Gets the <see cref="Index.IndexWriter"/> used by this <see cref="DirectoryTaxonomyWriter"/>.
-            /// </summary>
-            public IndexWriter IndexWriter { get; private set; }
+            private SnapshotDeletionPolicy sdp;
+            private IndexWriter writer;
 
             /// <summary>
             /// <see cref="DirectoryTaxonomyWriter(Directory, OpenMode, ITaxonomyWriterCache)"/>
@@ -78,14 +72,24 @@ namespace Lucene.Net.Replicator
             protected override IndexWriterConfig CreateIndexWriterConfig(OpenMode openMode)
             {
                 IndexWriterConfig conf = base.CreateIndexWriterConfig(openMode);
-                conf.IndexDeletionPolicy = DeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+                conf.IndexDeletionPolicy = sdp = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
                 return conf;
             }
 
             protected override IndexWriter OpenIndexWriter(Directory directory, IndexWriterConfig config)
             {
-                return IndexWriter = base.OpenIndexWriter(directory, config);
+                return writer = base.OpenIndexWriter(directory, config);
             }
+
+            /// <summary>
+            /// Gets the <see cref="SnapshotDeletionPolicy"/> used by the underlying <see cref="Index.IndexWriter"/>.
+            /// </summary>
+            public virtual SnapshotDeletionPolicy DeletionPolicy { get { return sdp; } }
+
+            /// <summary>
+            /// Gets the <see cref="Index.IndexWriter"/> used by this <see cref="DirectoryTaxonomyWriter"/>.
+            /// </summary>
+            public virtual IndexWriter IndexWriter { get { return writer; } }
         }
 
         public const string INDEX_SOURCE = "index";
@@ -95,6 +99,8 @@ namespace Lucene.Net.Replicator
         private readonly SnapshotDirectoryTaxonomyWriter taxonomyWriter;
         private readonly IndexCommit indexCommit, taxonomyCommit;
         private readonly SnapshotDeletionPolicy indexSdp, taxonomySdp;
+        private readonly string version;
+        private readonly IDictionary<string, IList<RevisionFile>> sourceFiles;
 
         /// <summary>
         /// Returns a map of the revision files from the given <see cref="IndexCommit"/>s of the search and taxonomy indexes.
@@ -136,14 +142,14 @@ namespace Lucene.Net.Replicator
             this.taxonomySdp = taxonomyWriter.DeletionPolicy;
             this.indexCommit = indexSdp.Snapshot();
             this.taxonomyCommit = taxonomySdp.Snapshot();
-            this.Version = RevisionVersion(indexCommit, taxonomyCommit);
-            this.SourceFiles = RevisionFiles(indexCommit, taxonomyCommit);
+            this.version = RevisionVersion(indexCommit, taxonomyCommit);
+            this.sourceFiles = RevisionFiles(indexCommit, taxonomyCommit);
         }
 
         /// <summary>
         /// Compares this <see cref="IndexAndTaxonomyRevision"/> to the given <see cref="version"/>.
         /// </summary>
-        public int CompareTo(string version)
+        public virtual int CompareTo(string version)
         {
             string[] parts = version.Split(':');
             long indexGen = long.Parse(parts[0], NumberStyles.HexNumber);
@@ -160,7 +166,7 @@ namespace Lucene.Net.Replicator
             return taxonomyCommitGen < taxonomyGen ? -1 : (taxonomyCommitGen > taxonomyGen ? 1 : 0);
         }
 
-        public int CompareTo(IRevision other)
+        public virtual int CompareTo(IRevision other)
         {
             if (other == null)
                 throw new ArgumentNullException("other");
@@ -173,12 +179,12 @@ namespace Lucene.Net.Replicator
             return cmp != 0 ? cmp : taxonomyCommit.CompareTo(itr.taxonomyCommit);
         }
 
-        public string Version { get; private set; }
+        public virtual string Version { get { return version; } }
 
-        public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
+        public virtual IDictionary<string, IList<RevisionFile>> SourceFiles { get { return sourceFiles; } }
 
         /// <exception cref="IOException"></exception>
-        public Stream Open(string source, string fileName)
+        public virtual Stream Open(string source, string fileName)
         {
             Debug.Assert(source.Equals(INDEX_SOURCE) || source.Equals(TAXONOMY_SOURCE), string.Format("invalid source; expected=({0} or {1}) got={2}", INDEX_SOURCE, TAXONOMY_SOURCE, source));
             IndexCommit commit = source.Equals(INDEX_SOURCE) ? indexCommit : taxonomyCommit;
@@ -186,7 +192,7 @@ namespace Lucene.Net.Replicator
         }
 
         /// <exception cref="IOException"></exception>
-        public void Release()
+        public virtual void Release()
         {
             try
             {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/IndexInputInputStream.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexInputInputStream.cs b/src/Lucene.Net.Replicator/IndexInputInputStream.cs
index df72010..d6af827 100644
--- a/src/Lucene.Net.Replicator/IndexInputInputStream.cs
+++ b/src/Lucene.Net.Replicator/IndexInputInputStream.cs
@@ -1,6 +1,6 @@
-using System;
+using Lucene.Net.Store;
+using System;
 using System.IO;
-using Lucene.Net.Store;
 
 namespace Lucene.Net.Replicator
 {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexReplicationHandler.cs b/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
index 5189e44..99d3445 100644
--- a/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
+++ b/src/Lucene.Net.Replicator/IndexReplicationHandler.cs
@@ -1,11 +1,11 @@
+using Lucene.Net.Index;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Text.RegularExpressions;
-using Lucene.Net.Index;
-using Lucene.Net.Store;
-using Lucene.Net.Util;
 using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Replicator
@@ -57,7 +57,10 @@ namespace Lucene.Net.Replicator
 
         private readonly Directory indexDirectory;
         private readonly Func<bool?> callback;
-        private InfoStream infoStream;
+
+        private volatile IDictionary<string, IList<RevisionFile>> currentRevisionFiles;
+        private volatile string currentVersion;
+        private volatile InfoStream infoStream;
 
         //Note: LUCENENET Specific Utility Method
         private void WriteToInfoStream(params string[] messages)
@@ -236,28 +239,28 @@ namespace Lucene.Net.Replicator
             this.callback = callback;
             this.indexDirectory = indexDirectory;
 
-            CurrentVersion = null;
-            CurrentRevisionFiles = null;
+            currentVersion = null;
+            currentRevisionFiles = null;
 
             if (DirectoryReader.IndexExists(indexDirectory))
             {
                 IList<IndexCommit> commits = DirectoryReader.ListCommits(indexDirectory);
                 IndexCommit commit = commits.Last();
 
-                CurrentVersion = IndexRevision.RevisionVersion(commit);
-                CurrentRevisionFiles = IndexRevision.RevisionFiles(commit);
+                currentVersion = IndexRevision.RevisionVersion(commit);
+                currentRevisionFiles = IndexRevision.RevisionFiles(commit);
 
                 WriteToInfoStream(
-                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles),
+                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", currentVersion, currentRevisionFiles),
                     string.Format("constructor(): commit={0}", commit));
             }
         }
 
-        public string CurrentVersion { get; private set; }
+        public virtual string CurrentVersion { get { return currentVersion; } }
 
-        public IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get; private set; }
+        public virtual IDictionary<string, IList<RevisionFile>> CurrentRevisionFiles { get { return currentRevisionFiles; } }
 
-        public void RevisionReady(string version,
+        public virtual void RevisionReady(string version,
             IDictionary<string, IList<RevisionFile>> revisionFiles,
             IDictionary<string, IList<string>> copiedFiles,
             IDictionary<string, Directory> sourceDirectory)
@@ -293,10 +296,10 @@ namespace Lucene.Net.Replicator
             }
 
             // all files have been successfully copied + sync'd. update the handler's state
-            CurrentRevisionFiles = revisionFiles;
-            CurrentVersion = version;
+            currentRevisionFiles = revisionFiles;
+            currentVersion = version;
 
-            WriteToInfoStream(string.Format("revisionReady(): currentVersion={0} currentRevisionFiles={1}", CurrentVersion, CurrentRevisionFiles));
+            WriteToInfoStream(string.Format("revisionReady(): currentVersion={0} currentRevisionFiles={1}", currentVersion, currentRevisionFiles));
 
             // update the segments.gen file
             WriteSegmentsGen(segmentsFile, indexDirectory);
@@ -326,7 +329,7 @@ namespace Lucene.Net.Replicator
         /// <summary>
         /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages.
         /// </summary>
-        public InfoStream InfoStream
+        public virtual InfoStream InfoStream
         {
             get { return infoStream; }
             set { infoStream = value ?? InfoStream.NO_OUTPUT; }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/IndexRevision.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/IndexRevision.cs b/src/Lucene.Net.Replicator/IndexRevision.cs
index 29ea77c..092fc3e 100644
--- a/src/Lucene.Net.Replicator/IndexRevision.cs
+++ b/src/Lucene.Net.Replicator/IndexRevision.cs
@@ -1,11 +1,11 @@
+using Lucene.Net.Index;
+using Lucene.Net.Store;
 using System;
-using System.IO;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Globalization;
+using System.IO;
 using System.Linq;
-using Lucene.Net.Index;
-using Lucene.Net.Store;
 using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Replicator
@@ -50,8 +50,8 @@ namespace Lucene.Net.Replicator
         private readonly IndexWriter writer;
         private readonly IndexCommit commit;
         private readonly SnapshotDeletionPolicy sdp;
-
-        public IDictionary<string, IList<RevisionFile>> SourceFiles { get; private set; }
+        private readonly string version;
+        private readonly IDictionary<string, IList<RevisionFile>> sourceFiles;
 
         // returns a RevisionFile with some metadata
         private static RevisionFile CreateRevisionFile(string fileName, Directory directory)
@@ -98,11 +98,11 @@ namespace Lucene.Net.Replicator
 
             this.writer = writer;
             this.commit = sdp.Snapshot();
-            this.Version = RevisionVersion(commit);
-            this.SourceFiles = RevisionFiles(commit);
+            this.version = RevisionVersion(commit);
+            this.sourceFiles = RevisionFiles(commit);
         }
 
-        public int CompareTo(string version)
+        public virtual int CompareTo(string version)
         {
             long gen = long.Parse(version, NumberStyles.HexNumber);
             long commitGen = commit.Generation;
@@ -110,7 +110,7 @@ namespace Lucene.Net.Replicator
             return commitGen < gen ? -1 : (commitGen > gen ? 1 : 0);
         }
 
-        public int CompareTo(IRevision other)
+        public virtual int CompareTo(IRevision other)
         {
             //TODO: This breaks the contract and will fail if called with a different implementation
             //      This is a flaw inherited from the original source...
@@ -119,15 +119,17 @@ namespace Lucene.Net.Replicator
             return commit.CompareTo(or.commit);
         }
 
-        public string Version { get; private set; }
+        public virtual string Version { get { return version; } }
+
+        public virtual IDictionary<string, IList<RevisionFile>> SourceFiles { get { return sourceFiles; } }
 
-        public Stream Open(string source, string fileName)
+        public virtual Stream Open(string source, string fileName)
         {
             Debug.Assert(source.Equals(SOURCE), string.Format("invalid source; expected={0} got={1}", SOURCE, source));
             return new IndexInputStream(commit.Directory.OpenInput(fileName, IOContext.READ_ONCE));
         }
 
-        public void Release()
+        public virtual void Release()
         {
             sdp.Release(commit);
             writer.DeleteUnusedFiles();

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/LocalReplicator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/LocalReplicator.cs b/src/Lucene.Net.Replicator/LocalReplicator.cs
index 981eecb..349a088 100644
--- a/src/Lucene.Net.Replicator/LocalReplicator.cs
+++ b/src/Lucene.Net.Replicator/LocalReplicator.cs
@@ -55,7 +55,7 @@ namespace Lucene.Net.Replicator
 
             /// <summary/>
             /// <exception cref="InvalidOperationException"></exception>
-            public void DecRef()
+            public virtual void DecRef()
             {
                 if (refCount.Get() <= 0)
                 {
@@ -86,7 +86,7 @@ namespace Lucene.Net.Replicator
                 }
             }
 
-            public void IncRef()
+            public virtual void IncRef()
             {
                 refCount.IncrementAndGet();
             }
@@ -106,12 +106,12 @@ namespace Lucene.Net.Replicator
                 lastAccessTime = Stopwatch.GetTimestamp();
             }
 
-            public bool IsExpired(long expirationThreshold)
+            public virtual bool IsExpired(long expirationThreshold)
             {
                 return lastAccessTime < Stopwatch.GetTimestamp() - expirationThreshold * Stopwatch.Frequency / 1000; // LUCENENET TODO: CurrentTimeMilliseconds()
             }
 
-            public void MarkAccessed()
+            public virtual void MarkAccessed()
             {
                 lastAccessTime = Stopwatch.GetTimestamp(); // LUCENENET TODO: CurrentTimeMilliseconds()
             }
@@ -169,7 +169,7 @@ namespace Lucene.Net.Replicator
             }
         }
 
-        public SessionToken CheckForUpdate(string currentVersion)
+        public virtual SessionToken CheckForUpdate(string currentVersion)
         {
             lock (padlock)
             {
@@ -190,9 +190,9 @@ namespace Lucene.Net.Replicator
             }
         }
 
-        public void Dispose() // LUCENENET TODO: API Dispose pattern
+        protected virtual void Dispose(bool disposing)
         {
-            if (disposed)
+            if (disposed || !disposing)
                 return;
 
             lock (padlock)
@@ -204,14 +204,20 @@ namespace Lucene.Net.Replicator
             disposed = true;
         }
 
+        public void Dispose()
+        {
+            Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
         /// <summary>
-        /// Gets or sets the expiration threshold.
+        /// Gets or sets the expiration threshold in milliseconds.
         /// <para/>
         /// If a replication session is inactive this
         /// long it is automatically expired, and further attempts to operate within
         /// this session will throw a <see cref="SessionExpiredException"/>.
         /// </summary>
-        public long ExpirationThreshold
+        public virtual long ExpirationThreshold
         {
             get { return expirationThreshold; }
             set
@@ -225,7 +231,7 @@ namespace Lucene.Net.Replicator
             }
         }
 
-        public Stream ObtainFile(string sessionId, string source, string fileName)
+        public virtual Stream ObtainFile(string sessionId, string source, string fileName)
         {
             lock (padlock)
             {
@@ -247,7 +253,7 @@ namespace Lucene.Net.Replicator
             }
         }
 
-        public void Publish(IRevision revision)
+        public virtual void Publish(IRevision revision)
         {
             lock (padlock)
             {
@@ -280,7 +286,7 @@ namespace Lucene.Net.Replicator
         }
 
         /// <exception cref="InvalidOperationException"></exception>
-        public void Release(string sessionId)
+        public virtual void Release(string sessionId)
         {
             lock (padlock)
             {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs b/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
index 3661f71..d16ea4e 100644
--- a/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
+++ b/src/Lucene.Net.Replicator/PerSessionDirectoryFactory.cs
@@ -1,6 +1,6 @@
+using Lucene.Net.Store;
 using System;
 using System.IO;
-using Lucene.Net.Store;
 using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Replicator
@@ -40,14 +40,14 @@ namespace Lucene.Net.Replicator
             this.workingDirectory = workingDirectory;
         }
 
-        public Directory GetDirectory(string sessionId, string source)
+        public virtual Directory GetDirectory(string sessionId, string source)
         {
             string sourceDirectory = Path.Combine(workingDirectory, sessionId, source);
             System.IO.Directory.CreateDirectory(sourceDirectory);
             return FSDirectory.Open(sourceDirectory);
         }
 
-        public void CleanupSession(string sessionId)
+        public virtual void CleanupSession(string sessionId)
         {
             if (string.IsNullOrEmpty(sessionId)) throw new ArgumentException("sessionID cannot be empty", "sessionId");
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/ReplicationClient.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/ReplicationClient.cs b/src/Lucene.Net.Replicator/ReplicationClient.cs
index 6064856..7388093 100644
--- a/src/Lucene.Net.Replicator/ReplicationClient.cs
+++ b/src/Lucene.Net.Replicator/ReplicationClient.cs
@@ -1,3 +1,6 @@
+using Lucene.Net.Store;
+using Lucene.Net.Support.Threading;
+using Lucene.Net.Util;
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
@@ -5,9 +8,6 @@ using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Threading;
-using Lucene.Net.Store;
-using Lucene.Net.Support.Threading;
-using Lucene.Net.Util;
 using Directory = Lucene.Net.Store.Directory;
 
 namespace Lucene.Net.Replicator
@@ -314,7 +314,7 @@ namespace Lucene.Net.Replicator
         }
 
         /// <summary>Throws <see cref="ObjectDisposedException"/> if the client has already been disposed.</summary>
-        protected virtual void EnsureOpen()
+        protected void EnsureOpen()
         {
             if (!disposed)
                 return;
@@ -350,7 +350,7 @@ namespace Lucene.Net.Replicator
         /// Returns the files required for replication. By default, this method returns
         /// all files that exist in the new revision, but not in the handler.
         /// </summary>
-        private IDictionary<string, IList<RevisionFile>> RequiredFiles(IDictionary<string, IList<RevisionFile>> newRevisionFiles)
+        protected virtual IDictionary<string, IList<RevisionFile>> RequiredFiles(IDictionary<string, IList<RevisionFile>> newRevisionFiles)
         {
             IDictionary<string, IList<RevisionFile>> handlerRevisionFiles = handler.CurrentRevisionFiles;
             if (handlerRevisionFiles == null)
@@ -375,7 +375,7 @@ namespace Lucene.Net.Replicator
 
         protected virtual void Dispose(bool disposing)
         {
-            if (disposed)
+            if (disposed || !disposing)
                 return;
 
             StopUpdateThread();
@@ -395,7 +395,7 @@ namespace Lucene.Net.Replicator
         /// will be set.
         /// </summary>
         /// <exception cref="InvalidOperationException"> if the thread has already been started </exception>
-        public void StartUpdateThread(long intervalMillis, string threadName)
+        public virtual void StartUpdateThread(long intervalMillis, string threadName)
         {
             EnsureOpen();
             if (updateThread != null && updateThread.IsAlive)
@@ -412,7 +412,7 @@ namespace Lucene.Net.Replicator
         /// Stop the update thread. If the update thread is not running, silently does
         /// nothing. This method returns after the update thread has stopped.
         /// </summary>
-        public void StopUpdateThread()
+        public virtual void StopUpdateThread()
         {
             // this will trigger the thread to terminate if it awaits the lock.
             // otherwise, if it's in the middle of replication, we wait for it to
@@ -429,7 +429,7 @@ namespace Lucene.Net.Replicator
         /// caused it to terminate (i.e. <see cref="HandleUpdateException"/>
         /// threw the exception further).
         /// </summary>
-        public bool IsUpdateThreadAlive
+        public virtual bool IsUpdateThreadAlive
         {
             get { return updateThread != null && updateThread.IsAlive; }
         }
@@ -446,7 +446,7 @@ namespace Lucene.Net.Replicator
         /// is running or not.
         /// </summary>
         /// <exception cref="IOException"></exception>
-        public void UpdateNow() 
+        public virtual void UpdateNow() 
         {
             EnsureOpen();
             if (updateThread != null)
@@ -472,7 +472,7 @@ namespace Lucene.Net.Replicator
         /// <summary> 
         /// Gets or sets the <see cref="Util.InfoStream"/> to use for logging messages. 
         /// </summary>
-        public InfoStream InfoStream
+        public virtual InfoStream InfoStream
         {
             get { return infoStream; }
             set { infoStream = value ?? InfoStream.NO_OUTPUT; }

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/73f6a4e2/src/Lucene.Net.Replicator/RevisionFile.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/RevisionFile.cs b/src/Lucene.Net.Replicator/RevisionFile.cs
index c74f057..0fa897f 100644
--- a/src/Lucene.Net.Replicator/RevisionFile.cs
+++ b/src/Lucene.Net.Replicator/RevisionFile.cs
@@ -60,7 +60,7 @@ namespace Lucene.Net.Replicator
         }
 
         // LUCENENET specific Equals overload
-        public bool Equals(RevisionFile other)
+        public virtual bool Equals(RevisionFile other)
         {
             if (ReferenceEquals(null, other)) return false;
             if (ReferenceEquals(this, other)) return true;


[14/20] lucenenet git commit: Lucene.Net.Replicator, Lucene.Net.Replicator.AspNetCore, Lucene.Net.Tests.Replicator: Ported to .NET Standard 1.5/.NET Core 1.0

Posted by ni...@apache.org.
Lucene.Net.Replicator, Lucene.Net.Replicator.AspNetCore, Lucene.Net.Tests.Replicator: Ported to .NET Standard 1.5/.NET Core 1.0


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

Branch: refs/heads/replicator
Commit: 4db2b0ae921e42d9f3aaff5f4fe7a49c1ecb45f1
Parents: 1e6ce74
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 05:30:05 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 05:30:05 2017 +0700

----------------------------------------------------------------------
 Lucene.Net.Portable.sln                         |  30 +++++
 .../Lucene.Net.Replicator.AspNetCore.csproj     |  21 +--
 ...ucene.Net.Replicator.AspNetCore.project.json |  11 ++
 .../Lucene.Net.Replicator.AspNetCore.xproj      |  18 +++
 .../Properties/AssemblyInfo.cs                  |  30 ++++-
 .../packages.config                             |   9 --
 .../project.json                                |  42 ++++++
 .../Lucene.Net.Replicator.csproj                |   9 +-
 .../Lucene.Net.Replicator.project.json          |  11 ++
 .../Lucene.Net.Replicator.xproj                 |  18 +++
 .../Properties/AssemblyInfo.cs                  |  21 ++-
 src/Lucene.Net.Replicator/packages.config       |   4 -
 src/Lucene.Net.Replicator/project.json          |  46 +++++++
 .../Http/HttpReplicatorTest.cs                  |   2 +-
 .../IndexAndTaxonomyReplicationClientTest.cs    |  16 +--
 .../IndexReplicationClientTest.cs               |  10 +-
 .../IndexRevisionTest.cs                        |   4 +-
 .../LocalReplicatorTest.cs                      |   2 +-
 .../Lucene.Net.Tests.Replicator.csproj          | 134 +------------------
 .../Lucene.Net.Tests.Replicator.project.json    |  13 ++
 .../Lucene.Net.Tests.Replicator.xproj           |  21 +++
 .../Properties/AssemblyInfo.cs                  |  23 +++-
 .../SessionTokenTest.cs                         |   2 +-
 src/Lucene.Net.Tests.Replicator/packages.config |  52 -------
 src/Lucene.Net.Tests.Replicator/project.json    |  43 ++++++
 25 files changed, 351 insertions(+), 241 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/Lucene.Net.Portable.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.Portable.sln b/Lucene.Net.Portable.sln
index 5dbbd51..bab0ae5 100644
--- a/Lucene.Net.Portable.sln
+++ b/Lucene.Net.Portable.sln
@@ -111,6 +111,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Benchmark", "src
 EndProject
 Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Tests.Benchmark", "src\Lucene.Net.Tests.Benchmark\Lucene.Net.Tests.Benchmark.xproj", "{5356412F-8FC5-41D3-83C3-807740B06748}"
 EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Replicator", "src\Lucene.Net.Replicator\Lucene.Net.Replicator.xproj", "{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Replicator.AspNetCore", "src\Lucene.Net.Replicator.AspNetCore\Lucene.Net.Replicator.AspNetCore.xproj", "{338E63C1-CEAC-47C4-A89A-090C764BE274}"
+EndProject
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Lucene.Net.Tests.Replicator", "src\Lucene.Net.Tests.Replicator\Lucene.Net.Tests.Replicator.xproj", "{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -511,6 +517,30 @@ Global
 		{5356412F-8FC5-41D3-83C3-807740B06748}.Release|Any CPU.Build.0 = Release|Any CPU
 		{5356412F-8FC5-41D3-83C3-807740B06748}.Release|x86.ActiveCfg = Release|Any CPU
 		{5356412F-8FC5-41D3-83C3-807740B06748}.Release|x86.Build.0 = Release|Any CPU
+		{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}.Debug|x86.Build.0 = Debug|Any CPU
+		{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}.Release|x86.ActiveCfg = Release|Any CPU
+		{7EF82DA1-570C-41A6-BBF3-E609E9AEE905}.Release|x86.Build.0 = Release|Any CPU
+		{338E63C1-CEAC-47C4-A89A-090C764BE274}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{338E63C1-CEAC-47C4-A89A-090C764BE274}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{338E63C1-CEAC-47C4-A89A-090C764BE274}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{338E63C1-CEAC-47C4-A89A-090C764BE274}.Debug|x86.Build.0 = Debug|Any CPU
+		{338E63C1-CEAC-47C4-A89A-090C764BE274}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{338E63C1-CEAC-47C4-A89A-090C764BE274}.Release|Any CPU.Build.0 = Release|Any CPU
+		{338E63C1-CEAC-47C4-A89A-090C764BE274}.Release|x86.ActiveCfg = Release|Any CPU
+		{338E63C1-CEAC-47C4-A89A-090C764BE274}.Release|x86.Build.0 = Release|Any CPU
+		{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}.Debug|x86.Build.0 = Debug|Any CPU
+		{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}.Release|x86.ActiveCfg = Release|Any CPU
+		{685A1388-5D85-42D0-A98C-4EC3D0C01C5F}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/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
index e4345b0..8d71c07 100644
--- a/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.csproj
+++ b/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.csproj
@@ -30,25 +30,9 @@
     <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" />
@@ -61,10 +45,13 @@
     <Compile Include="AspNetCoreReplicationResponse.cs" />
     <Compile Include="AspNetCoreReplicationServiceExtentions.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="..\CommonAssemblyInfo.cs">
+      <Link>Properties\CommonAssemblyInfo.cs</Link>
+    </Compile>
   </ItemGroup>
   <ItemGroup>
     <None Include="examples.md" />
-    <None Include="packages.config" />
+    <None Include="Lucene.Net.Replicator.AspNetCore.project.json" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Lucene.Net.Replicator\Lucene.Net.Replicator.csproj">

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.project.json
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.project.json b/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.project.json
new file mode 100644
index 0000000..1957363
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.project.json
@@ -0,0 +1,11 @@
+{
+  "runtimes": {
+    "win": {}
+  },
+  "dependencies": {
+    "Microsoft.AspNetCore.Http.Abstractions": "1.0.3"
+  },
+  "frameworks": {
+    "net451": {}
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.xproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.xproj b/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.xproj
new file mode 100644
index 0000000..ac0df83
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/Lucene.Net.Replicator.AspNetCore.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>338e63c1-ceac-47c4-a89a-090c764be274</ProjectGuid>
+    <RootNamespace>Lucene.Net.Replicator.AspNetCore</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/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
index c0e4fd2..f4c3a95 100644
--- a/src/Lucene.Net.Replicator.AspNetCore/Properties/AssemblyInfo.cs
+++ b/src/Lucene.Net.Replicator.AspNetCore/Properties/AssemblyInfo.cs
@@ -1,4 +1,26 @@
-using System.Reflection;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+using System;
+using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 
@@ -6,12 +28,14 @@ using System.Runtime.InteropServices;
 // 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: AssemblyDescription("AspNetCore integration of 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("")]
 
+[assembly: CLSCompliant(true)]
+
 // 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.

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/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
deleted file mode 100644
index 3ffed90..0000000
--- a/src/Lucene.Net.Replicator.AspNetCore/packages.config
+++ /dev/null
@@ -1,9 +0,0 @@
-<?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/4db2b0ae/src/Lucene.Net.Replicator.AspNetCore/project.json
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator.AspNetCore/project.json b/src/Lucene.Net.Replicator.AspNetCore/project.json
new file mode 100644
index 0000000..23ec8c2
--- /dev/null
+++ b/src/Lucene.Net.Replicator.AspNetCore/project.json
@@ -0,0 +1,42 @@
+{
+  "version": "4.8.0",
+  "title": "Lucene.Net.Replicator.AspNetCore",
+  "description": "AspNetCore integration of Lucene.Net.Replicator for the Lucene.Net full-text search engine library from The Apache Software Foundation.",
+  "authors": [ "The Apache Software Foundation" ],
+  "packOptions": {
+    "projectUrl": "http://lucenenet.apache.org/",
+    "licenseUrl": "https://github.com/apache/lucenenet/blob/master/LICENSE.txt",
+    "iconUrl": "https://github.com/apache/lucenenet/blob/master/branding/logo/lucene-net-icon-128x128.png?raw=true",
+    "owners": [ "The Apache Software Foundation" ],
+    "repository": { "url": "https://github.com/apache/lucenenet" },
+    "tags": [ "lucene.net", "core", "text", "search", "information", "retrieval", "lucene", "apache", "analysis", "index", "query", "files", "replication", "replicate", "aspnetcore" ]
+  },
+  "buildOptions": {
+    "compile": {
+      "includeFiles": [ "../CommonAssemblyInfo.cs" ]
+    },
+    "nowarn": [ "1591", "1573" ]
+  },
+  "dependencies": {
+    "Lucene.Net.Replicator": "4.8.0",
+    "Microsoft.AspNetCore.Http.Abstractions": "1.0.3"
+  },
+  "frameworks": {
+    "netstandard1.5": {
+      "imports": "dnxcore50",
+      "buildOptions": {
+        "debugType": "portable",
+        "define": [ "NETSTANDARD" ]
+      },
+      "dependencies": {
+        "NETStandard.Library": "1.6.0"
+      }
+    },
+    "net451": {
+      "buildOptions": {
+        "debugType": "full",
+        "define": [ "FEATURE_SERIALIZABLE" ]
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
index 5efeb74..7ea6243 100644
--- a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
+++ b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
@@ -53,10 +53,6 @@
     <DefineConstants>$(DefineConstants);FEATURE_SERIALIZABLE</DefineConstants>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core" />
     <Reference Include="System.Xml.Linq" />
@@ -86,6 +82,9 @@
     <Compile Include="RevisionFile.cs" />
     <Compile Include="SessionExpiredException.cs" />
     <Compile Include="SessionToken.cs" />
+    <Compile Include="..\CommonAssemblyInfo.cs">
+      <Link>Properties\CommonAssemblyInfo.cs</Link>
+    </Compile>
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
@@ -98,7 +97,7 @@
     </ProjectReference>
   </ItemGroup>
   <ItemGroup>
-    <None Include="packages.config" />
+    <None Include="Lucene.Net.Replicator.project.json" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Replicator/Lucene.Net.Replicator.project.json
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.project.json b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.project.json
new file mode 100644
index 0000000..f19c540
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.project.json
@@ -0,0 +1,11 @@
+{
+  "runtimes": {
+    "win": {}
+  },
+  "dependencies": {
+    "Newtonsoft.Json": "9.0.1"
+  },
+  "frameworks": {
+    "net451": {}
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Replicator/Lucene.Net.Replicator.xproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.xproj b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.xproj
new file mode 100644
index 0000000..1ab83cf
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.xproj
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>7ef82da1-570c-41a6-bbf3-e609e9aee905</ProjectGuid>
+    <RootNamespace>Lucene.Net.Replicator</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs b/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
index 6cc1e58..1f1835b 100644
--- a/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
+++ b/src/Lucene.Net.Replicator/Properties/AssemblyInfo.cs
@@ -1,4 +1,21 @@
-using System;
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
 using System.Reflection;
 using System.Runtime.InteropServices;
 
@@ -6,7 +23,7 @@ using System.Runtime.InteropServices;
 // set of attributes. Change these attribute values to modify the information
 // associated with an assembly.
 [assembly: AssemblyTitle("Lucene.Net.Replicator")]
-[assembly: AssemblyDescription("Replicator that allows replication of Lucene.Net files between a server and client(s) " +
+[assembly: AssemblyDescription("Replicator that allows replication of files between a server and client(s) " +
                                "for the Lucene.Net full - text search engine library from The Apache Software Foundation.")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyDefaultAlias("Lucene.Net.Replicator")]

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Replicator/packages.config
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/packages.config b/src/Lucene.Net.Replicator/packages.config
deleted file mode 100644
index 3e14be6..0000000
--- a/src/Lucene.Net.Replicator/packages.config
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net451" />
-</packages>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Replicator/project.json
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/project.json b/src/Lucene.Net.Replicator/project.json
new file mode 100644
index 0000000..11cd0e1
--- /dev/null
+++ b/src/Lucene.Net.Replicator/project.json
@@ -0,0 +1,46 @@
+{
+  "version": "4.8.0",
+  "title": "Lucene.Net.Replicator",
+  "description": "Replicator that allows replication of files between a server and client(s) for the Lucene.Net full-text search engine library from The Apache Software Foundation.",
+  "authors": [ "The Apache Software Foundation" ],
+  "packOptions": {
+    "projectUrl": "http://lucenenet.apache.org/",
+    "licenseUrl": "https://github.com/apache/lucenenet/blob/master/LICENSE.txt",
+    "iconUrl": "https://github.com/apache/lucenenet/blob/master/branding/logo/lucene-net-icon-128x128.png?raw=true",
+    "owners": [ "The Apache Software Foundation" ],
+    "repository": { "url": "https://github.com/apache/lucenenet" },
+    "tags": [ "lucene.net", "core", "text", "search", "information", "retrieval", "lucene", "apache", "analysis", "index", "query", "files", "replication", "replicate" ]
+  },
+  "buildOptions": {
+    "compile": {
+      "includeFiles": [ "../CommonAssemblyInfo.cs" ]
+    },
+    "nowarn": [ "1591", "1573" ]
+  },
+  "dependencies": {
+    "Lucene.Net": "4.8.0",
+    "Lucene.Net.Facet": "4.8.0",
+    "Newtonsoft.Json": "9.0.1"
+  },
+  "frameworks": {
+    "netstandard1.5": {
+      "imports": "dnxcore50",
+      "buildOptions": {
+        "debugType": "portable",
+        "define": [ "NETSTANDARD" ]
+      },
+      "dependencies": {
+        "NETStandard.Library": "1.6.0"
+      }
+    },
+    "net451": {
+      "buildOptions": {
+        "debugType": "full",
+        "define": [ "FEATURE_SERIALIZABLE" ]
+      },
+      "frameworkAssemblies": {
+        "System.Net.Http": "4.0.0.0"
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
index 564eceb..b3061ad 100644
--- a/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
@@ -95,7 +95,7 @@ namespace Lucene.Net.Replicator.Http
         public void TestBasic()
         {
             IReplicator replicator = new HttpReplicator(host, port, ReplicationService.REPLICATION_CONTEXT + "/s1", server.CreateHandler());
-            ReplicationClient client = new ReplicationClient(replicator, new IndexReplicationHandler(handlerIndexDir, null), 
+            ReplicationClient client = new ReplicationClient(replicator, new IndexReplicationHandler(handlerIndexDir, null),
                 new PerSessionDirectoryFactory(clientWorkDir.FullName));
 
             PublishRevision(1);

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
index 4b93b49..3a77760 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
@@ -303,7 +303,7 @@ namespace Lucene.Net.Replicator
             // where the handler overwrites an existing index file, but
             // there's nothing currently we can do about it, unless we don't
             // use MDW.
-            handlerIndexDir.PreventDoubleWrite=(false);
+            handlerIndexDir.PreventDoubleWrite = (false);
             handlerTaxoDir.PreventDoubleWrite = (false);
 
             // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
@@ -330,12 +330,12 @@ namespace Lucene.Net.Replicator
 
             // disable errors -- maybe randomness didn't exhaust all allowed failures,
             // and we don't want e.g. CheckIndex to hit false errors. 
-            handlerIndexDir.MaxSizeInBytes=(0);
-            handlerIndexDir.RandomIOExceptionRate=(0.0);
-            handlerIndexDir.RandomIOExceptionRateOnOpen=(0.0);
-            handlerTaxoDir.MaxSizeInBytes=(0);
-            handlerTaxoDir.RandomIOExceptionRate=(0.0);
-            handlerTaxoDir.RandomIOExceptionRateOnOpen=(0.0);
+            handlerIndexDir.MaxSizeInBytes = (0);
+            handlerIndexDir.RandomIOExceptionRate = (0.0);
+            handlerIndexDir.RandomIOExceptionRateOnOpen = (0.0);
+            handlerTaxoDir.MaxSizeInBytes = (0);
+            handlerTaxoDir.RandomIOExceptionRate = (0.0);
+            handlerTaxoDir.RandomIOExceptionRateOnOpen = (0.0);
         }
 
         private class SourceDirectoryFactoryAnonymousInnerClass : ISourceDirectoryFactory
@@ -378,7 +378,7 @@ namespace Lucene.Net.Replicator
                 { // handler should fail
                     if (Random().nextBoolean())
                     { // index dir fail
-                        test.handlerIndexDir.MaxSizeInBytes=(handlerIndexMaxSize);
+                        test.handlerIndexDir.MaxSizeInBytes = (handlerIndexMaxSize);
                         test.handlerIndexDir.RandomIOExceptionRate = (handlerIndexExRate);
                         test.handlerIndexDir.RandomIOExceptionRateOnOpen = (handlerIndexExRate);
                         handlerIndexMaxSize *= 2;

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
index 4e816a4..65f416b 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
@@ -263,8 +263,8 @@ namespace Lucene.Net.Replicator
             // disable errors -- maybe randomness didn't exhaust all allowed failures,
             // and we don't want e.g. CheckIndex to hit false errors. 
             handlerDir.MaxSizeInBytes = 0;
-            handlerDir.RandomIOExceptionRate=0.0;
-            handlerDir.RandomIOExceptionRateOnOpen=0.0;
+            handlerDir.RandomIOExceptionRate = 0.0;
+            handlerDir.RandomIOExceptionRateOnOpen = 0.0;
         }
 
         private class SourceDirectoryFactoryAnonymousInnerClass : ISourceDirectoryFactory
@@ -377,11 +377,13 @@ namespace Lucene.Net.Replicator
                             }
                         }
                     }
-                } else {
+                }
+                else
+                {
                     throw exception;
                 }
             }
         }
-      
+
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
index 22d88be..cea6e51 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
@@ -145,8 +145,8 @@ namespace Lucene.Net.Replicator
                     IndexInput src = dir.OpenInput(file.FileName, IOContext.READ_ONCE);
                     Stream @in = rev.Open(source, file.FileName);
                     assertEquals(src.Length, @in.Length);
-                    byte[] srcBytes = new byte[(int) src.Length];
-                    byte[] inBytes = new byte[(int) src.Length];
+                    byte[] srcBytes = new byte[(int)src.Length];
+                    byte[] inBytes = new byte[(int)src.Length];
                     int offset = 0;
                     if (Random().nextBoolean())
                     {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
index 65f37bc..0a73674 100644
--- a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
@@ -68,7 +68,7 @@ namespace Lucene.Net.Replicator
         {
             assertNull(replicator.CheckForUpdate(null));
         }
-        
+
         [Test]
         public void TestObtainFileAlreadyClosed()
         {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
index 41cb28d..cb21da7 100644
--- a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
+++ b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
@@ -30,137 +30,9 @@
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
   <ItemGroup>
-    <Reference Include="Microsoft.AspNetCore.Hosting, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.AspNetCore.Hosting.Abstractions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.Abstractions.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.Abstractions.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.Server.Abstractions.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.AspNetCore.Http, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.AspNetCore.Http.1.0.3\lib\net451\Microsoft.AspNetCore.Http.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <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.Extensions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.AspNetCore.Http.Extensions.1.0.3\lib\net451\Microsoft.AspNetCore.Http.Extensions.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.AspNetCore.TestHost, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.AspNetCore.TestHost.1.0.3\lib\net451\Microsoft.AspNetCore.TestHost.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.AspNetCore.WebUtilities, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.AspNetCore.WebUtilities.1.0.3\lib\net451\Microsoft.AspNetCore.WebUtilities.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Configuration.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.Abstractions.1.0.2\lib\netstandard1.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.EnvironmentVariables.1.0.2\lib\net451\Microsoft.Extensions.Configuration.EnvironmentVariables.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.DependencyInjection, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.1.0.2\lib\netstandard1.1\Microsoft.Extensions.DependencyInjection.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.0.2\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.FileProviders.Abstractions, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.FileProviders.Abstractions.1.0.1\lib\netstandard1.0\Microsoft.Extensions.FileProviders.Abstractions.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.FileProviders.Physical, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.FileProviders.Physical.1.0.1\lib\net451\Microsoft.Extensions.FileProviders.Physical.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.FileSystemGlobbing, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.FileSystemGlobbing.1.0.1\lib\net451\Microsoft.Extensions.FileSystemGlobbing.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Logging, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.Logging.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.Logging.Abstractions.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.ObjectPool, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.ObjectPool.1.0.1\lib\net451\Microsoft.Extensions.ObjectPool.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.Options, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.Options.1.0.2\lib\netstandard1.0\Microsoft.Extensions.Options.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Microsoft.Extensions.PlatformAbstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Extensions.PlatformAbstractions.1.0.0\lib\net451\Microsoft.Extensions.PlatformAbstractions.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="Microsoft.Net.Http.Headers, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Microsoft.Net.Http.Headers.1.0.3\lib\netstandard1.1\Microsoft.Net.Http.Headers.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
     <Reference Include="System" />
-    <Reference Include="System.Buffers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\System.Buffers.4.0.0\lib\netstandard1.1\System.Buffers.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
     <Reference Include="System.ComponentModel.Composition" />
     <Reference Include="System.Core" />
-    <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.0.0\lib\portable-net45+win8+wpa81\System.Diagnostics.DiagnosticSource.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System.Reflection.Metadata, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
-      <HintPath>..\..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
-      <Private>True</Private>
-    </Reference>
-    <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" />
@@ -184,9 +56,6 @@
     <Compile Include="SessionTokenTest.cs" />
   </ItemGroup>
   <ItemGroup>
-    <None Include="packages.config" />
-  </ItemGroup>
-  <ItemGroup>
     <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
       <Project>{48F7884A-9454-4E88-8413-9D35992CB440}</Project>
       <Name>Lucene.Net.Facet</Name>
@@ -211,6 +80,9 @@
   <ItemGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Lucene.Net.Tests.Replicator.project.json" />
+  </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.

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.project.json
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.project.json b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.project.json
new file mode 100644
index 0000000..4a31f14
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.project.json
@@ -0,0 +1,13 @@
+{
+  "runtimes": {
+    "win": {}
+  },
+  "dependencies": {
+    "Microsoft.AspNetCore.TestHost": "1.0.3",
+    "Newtonsoft.Json": "9.0.1",
+    "NUnit": "3.5.0"
+  },
+  "frameworks": {
+    "net451": {}
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.xproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.xproj b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.xproj
new file mode 100644
index 0000000..02b9bb3
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.xproj
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0.25420" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.25420</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+  </PropertyGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>685a1388-5d85-42d0-a98c-4ec3d0c01c5f</ProjectGuid>
+    <RootNamespace>Lucene.Net.Replicator</RootNamespace>
+    <BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
+    <OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SchemaVersion>2.0</SchemaVersion>
+  </PropertyGroup>
+  <ItemGroup>
+    <Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
+  </ItemGroup>
+  <Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
+</Project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs b/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs
index 457c56c..b71db2a 100644
--- a/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs
+++ b/src/Lucene.Net.Tests.Replicator/Properties/AssemblyInfo.cs
@@ -1,4 +1,25 @@
-using System.Reflection;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs b/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
index 5f01824..46fd22c 100644
--- a/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
@@ -58,6 +58,6 @@ namespace Lucene.Net.Replicator
 
             IOUtils.Dispose(writer, directory);
         }
-        
+
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/packages.config
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/packages.config b/src/Lucene.Net.Tests.Replicator/packages.config
deleted file mode 100644
index 1f96d54..0000000
--- a/src/Lucene.Net.Tests.Replicator/packages.config
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<packages>
-  <package id="Microsoft.AspNetCore.Hosting" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.AspNetCore.Hosting.Abstractions" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.AspNetCore.Hosting.Server.Abstractions" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.AspNetCore.Http" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.AspNetCore.Http.Abstractions" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.AspNetCore.Http.Extensions" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.AspNetCore.Http.Features" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.AspNetCore.TestHost" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.AspNetCore.WebUtilities" version="1.0.3" targetFramework="net451" />
-  <package id="Microsoft.Extensions.Configuration" version="1.0.2" targetFramework="net451" />
-  <package id="Microsoft.Extensions.Configuration.Abstractions" version="1.0.2" targetFramework="net451" />
-  <package id="Microsoft.Extensions.Configuration.EnvironmentVariables" version="1.0.2" targetFramework="net451" />
-  <package id="Microsoft.Extensions.DependencyInjection" version="1.0.2" targetFramework="net451" />
-  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="1.0.2" targetFramework="net451" />
-  <package id="Microsoft.Extensions.FileProviders.Abstractions" version="1.0.1" targetFramework="net451" />
-  <package id="Microsoft.Extensions.FileProviders.Physical" version="1.0.1" targetFramework="net451" />
-  <package id="Microsoft.Extensions.FileSystemGlobbing" version="1.0.1" targetFramework="net451" />
-  <package id="Microsoft.Extensions.Logging" version="1.0.2" targetFramework="net451" />
-  <package id="Microsoft.Extensions.Logging.Abstractions" version="1.0.2" targetFramework="net451" />
-  <package id="Microsoft.Extensions.ObjectPool" version="1.0.1" targetFramework="net451" />
-  <package id="Microsoft.Extensions.Options" version="1.0.2" targetFramework="net451" />
-  <package id="Microsoft.Extensions.PlatformAbstractions" version="1.0.0" targetFramework="net451" />
-  <package id="Microsoft.Extensions.Primitives" version="1.0.1" targetFramework="net451" />
-  <package id="Microsoft.Net.Http.Headers" version="1.0.3" targetFramework="net451" />
-  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net451" />
-  <package id="NUnit" version="3.5.0" targetFramework="net451" />
-  <package id="System.Buffers" version="4.0.0" targetFramework="net451" />
-  <package id="System.Collections" version="4.0.11" targetFramework="net451" />
-  <package id="System.Collections.Concurrent" version="4.0.12" targetFramework="net451" />
-  <package id="System.Collections.Immutable" version="1.2.0" targetFramework="net451" />
-  <package id="System.ComponentModel" version="4.0.1" targetFramework="net451" />
-  <package id="System.Diagnostics.Contracts" version="4.0.1" targetFramework="net451" />
-  <package id="System.Diagnostics.Debug" version="4.0.11" targetFramework="net451" />
-  <package id="System.Diagnostics.DiagnosticSource" version="4.0.0" targetFramework="net451" />
-  <package id="System.Globalization" version="4.0.11" targetFramework="net451" />
-  <package id="System.IO" version="4.1.0" targetFramework="net451" />
-  <package id="System.Linq" version="4.1.0" targetFramework="net451" />
-  <package id="System.Linq.Expressions" version="4.1.1" targetFramework="net451" />
-  <package id="System.Reflection" version="4.1.0" targetFramework="net451" />
-  <package id="System.Reflection.Metadata" version="1.3.0" 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.Runtime.Extensions" version="4.1.0" targetFramework="net451" />
-  <package id="System.Runtime.InteropServices" version="4.1.0" targetFramework="net451" />
-  <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.0.0" targetFramework="net451" />
-  <package id="System.Text.Encoding" version="4.0.11" targetFramework="net451" />
-  <package id="System.Text.Encodings.Web" version="4.0.1" targetFramework="net451" />
-  <package id="System.Threading" version="4.0.11" targetFramework="net451" />
-  <package id="System.Threading.Tasks" version="4.0.11" targetFramework="net451" />
-</packages>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/4db2b0ae/src/Lucene.Net.Tests.Replicator/project.json
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/project.json b/src/Lucene.Net.Tests.Replicator/project.json
new file mode 100644
index 0000000..b37a362
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/project.json
@@ -0,0 +1,43 @@
+{
+  "version": "4.8.0",
+  "title": "Lucene.Net.Tests.Replicator",
+  "buildOptions": {
+    "compile": {
+      "includeFiles": [ "../CommonAssemblyInfo.cs" ]
+    },
+    "embed": {
+      "includeFiles": [
+      ]
+    }
+  },
+  "dependencies": {
+    "dotnet-test-nunit-teamcity": "3.4.0-beta-3",
+    "Lucene.Net.Replicator": "4.8.0",
+    "Lucene.Net.Replicator.AspNetCore": "4.8.0",
+    "Lucene.Net.TestFramework": "4.8.0",
+    "Microsoft.AspNetCore.TestHost": "1.0.3",
+    "Newtonsoft.Json": "9.0.1",
+    "NUnit": "3.5.0"
+  },
+  "testRunner": "nunit-teamcity",
+  "frameworks": {
+    "netcoreapp1.0": {
+      "imports": "dnxcore50",
+      "buildOptions": {
+        "debugType": "portable",
+        "define": [ "NETSTANDARD" ]
+      }
+    },
+    "net451": {
+      "buildOptions": {
+        "debugType": "full",
+        "define": [ "FEATURE_SERIALIZABLE" ]
+      }
+    }
+  },
+
+  "runtimes": {
+    "win7-x86": {},
+    "win7-x64": {}
+  }
+}


[12/20] lucenenet git commit: Lucene.Net.sln: fixed merge conflict

Posted by ni...@apache.org.
Lucene.Net.sln: fixed merge conflict


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

Branch: refs/heads/replicator
Commit: fd43c50433f3c6dc20c850ccdc25849031c66348
Parents: 3b0e132
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 02:52:00 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 02:52:00 2017 +0700

----------------------------------------------------------------------
 Lucene.Net.sln | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/fd43c504/Lucene.Net.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.sln b/Lucene.Net.sln
index 470a270..2fa6d04 100644
--- a/Lucene.Net.sln
+++ b/Lucene.Net.sln
@@ -111,6 +111,7 @@ 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
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Analysis.Kuromoji", "src\Lucene.Net.Analysis.Kuromoji\Lucene.Net.Analysis.Kuromoji.csproj", "{8408625A-2508-46D5-8519-045183C43724}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Analysis.Kuromoji", "src\Lucene.Net.Tests.Analysis.Kuromoji\Lucene.Net.Tests.Analysis.Kuromoji.csproj", "{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}"


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

Posted by ni...@apache.org.
http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
new file mode 100644
index 0000000..645888a
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
@@ -0,0 +1,518 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Facet.Taxonomy.Directory;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Search;
+using Lucene.Net.Store;
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Tests.Replicator
+{
+    [TestFixture]
+    public class IndexAndTaxonomyReplicationClientTest : ReplicatorTestCase
+    {
+        private class IndexAndTaxonomyReadyCallback : IDisposable
+        {
+            private Directory indexDir, taxoDir;
+            private DirectoryReader indexReader;
+            private DirectoryTaxonomyReader taxoReader;
+            private FacetsConfig config;
+            private long lastIndexGeneration = -1;
+
+            public IndexAndTaxonomyReadyCallback(MockDirectoryWrapper indexDir, MockDirectoryWrapper taxoDir)
+            {
+                this.indexDir = indexDir;
+                this.taxoDir = taxoDir;
+                config = new FacetsConfig();
+                config.SetHierarchical("A", true);
+                if (DirectoryReader.IndexExists(indexDir))
+                {
+                    indexReader = DirectoryReader.Open(indexDir);
+                    lastIndexGeneration = indexReader.IndexCommit.Generation;
+                    taxoReader = new DirectoryTaxonomyReader(taxoDir);
+                }
+            }
+
+            public bool? Call()
+            {
+                if (indexReader == null)
+                {
+                    indexReader = DirectoryReader.Open(indexDir);
+                    lastIndexGeneration = indexReader.IndexCommit.Generation;
+                    taxoReader = new DirectoryTaxonomyReader(taxoDir);
+                }
+                else
+                {
+                    // verify search index
+                    DirectoryReader newReader = DirectoryReader.OpenIfChanged(indexReader);
+                    assertNotNull("should not have reached here if no changes were made to the index", newReader);
+                    long newGeneration = newReader.IndexCommit.Generation;
+                    assertTrue("expected newer generation; current=" + lastIndexGeneration + " new=" + newGeneration, newGeneration > lastIndexGeneration);
+                    indexReader.Dispose();
+                    indexReader = newReader;
+                    lastIndexGeneration = newGeneration;
+                    TestUtil.CheckIndex(indexDir);
+
+                    // verify taxonomy index
+                    DirectoryTaxonomyReader newTaxoReader = TaxonomyReader.OpenIfChanged(taxoReader);
+                    if (newTaxoReader != null)
+                    {
+                        taxoReader.Dispose();
+                        taxoReader = newTaxoReader;
+                    }
+                    TestUtil.CheckIndex(taxoDir);
+
+                    // verify faceted search
+                    int id = int.Parse(indexReader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+                    IndexSearcher searcher = new IndexSearcher(indexReader);
+                    FacetsCollector fc = new FacetsCollector();
+                    searcher.Search(new MatchAllDocsQuery(), fc);
+                    Facets facets = new FastTaxonomyFacetCounts(taxoReader, config, fc);
+                    assertEquals(1, (int)facets.GetSpecificValue("A", id.ToString("X")));
+
+                    DrillDownQuery drillDown = new DrillDownQuery(config);
+                    drillDown.Add("A", id.ToString("X"));
+                    TopDocs docs = searcher.Search(drillDown, 10);
+                    assertEquals(1, docs.TotalHits);
+                }
+                return null;
+            }
+
+            public void Dispose()
+            {
+                IOUtils.Dispose(indexReader, taxoReader);
+            }
+        }
+
+        private Directory publishIndexDir, publishTaxoDir;
+        private MockDirectoryWrapper handlerIndexDir, handlerTaxoDir;
+        private IReplicator replicator;
+        private ISourceDirectoryFactory sourceDirFactory;
+        private ReplicationClient client;
+        private IReplicationHandler handler;
+        private IndexWriter publishIndexWriter;
+        private IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter publishTaxoWriter;
+        private FacetsConfig config;
+        private IndexAndTaxonomyReadyCallback callback;
+        private DirectoryInfo clientWorkDir;
+
+        private const string VERSION_ID = "version";
+
+        private void AssertHandlerRevision(int expectedId, Directory dir)
+        {
+            //JAVA: private void assertHandlerRevision(int expectedID, Directory dir) throws IOException {
+            //JAVA:   // loop as long as client is alive. test-framework will terminate us if
+            //JAVA:   // there's a serious bug, e.g. client doesn't really update. otherwise,
+            //JAVA:   // introducing timeouts is not good, can easily lead to false positives.
+            //JAVA:   while (client.isUpdateThreadAlive()) {
+            //JAVA:     // give client a chance to update
+            //JAVA:     try {
+            //JAVA:       Thread.sleep(100);
+            //JAVA:     } catch (InterruptedException e) {
+            //JAVA:       throw new ThreadInterruptedException(e);
+            //JAVA:     }
+            //JAVA:     
+            //JAVA:     try {
+            //JAVA:       DirectoryReader reader = DirectoryReader.open(dir);
+            //JAVA:       try {
+            //JAVA:         int handlerID = Integer.parseInt(reader.getIndexCommit().getUserData().get(VERSION_ID), 16);
+            //JAVA:         if (expectedID == handlerID) {
+            //JAVA:           return;
+            //JAVA:         }
+            //JAVA:       } finally {
+            //JAVA:         reader.close();
+            //JAVA:       }
+            //JAVA:     } catch (Exception e) {
+            //JAVA:       // we can hit IndexNotFoundException or e.g. EOFException (on
+            //JAVA:       // segments_N) because it is being copied at the same time it is read by
+            //JAVA:       // DirectoryReader.open().
+            //JAVA:     }
+            //JAVA:   }
+            //JAVA: }
+
+            // loop as long as client is alive. test-framework will terminate us if
+            // there's a serious bug, e.g. client doesn't really update. otherwise,
+            // introducing timeouts is not good, can easily lead to false positives.
+            while (client.IsUpdateThreadAlive)
+            {
+                Thread.Sleep(100);
+
+                try
+                {
+                    DirectoryReader reader = DirectoryReader.Open(dir);
+                    try
+                    {
+                        int handlerId = int.Parse(reader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+                        if (expectedId == handlerId)
+                        {
+                            return;
+                        }
+                    }
+                    finally
+                    {
+                        reader.Dispose();
+                    }
+                }
+                catch (Exception)
+                {
+                    // we can hit IndexNotFoundException or e.g. EOFException (on
+                    // segments_N) because it is being copied at the same time it is read by
+                    // DirectoryReader.open().
+                }
+            }
+        }
+
+        private IRevision CreateRevision(int id)
+        {
+            //JAVA: private Revision createRevision(final int id) throws IOException {
+            //JAVA:   publishIndexWriter.addDocument(newDocument(publishTaxoWriter, id));
+            //JAVA:   publishIndexWriter.setCommitData(new HashMap<String, String>() {{
+            //JAVA:     put(VERSION_ID, Integer.toString(id, 16));
+            //JAVA:   }});
+            //JAVA:   publishIndexWriter.commit();
+            //JAVA:   publishTaxoWriter.commit();
+            //JAVA:   return new IndexAndTaxonomyRevision(publishIndexWriter, publishTaxoWriter);
+            //JAVA: }
+            publishIndexWriter.AddDocument(NewDocument(publishTaxoWriter, id));
+            publishIndexWriter.SetCommitData(new Dictionary<string, string>{
+                { VERSION_ID, id.ToString("X") }
+            });
+            publishIndexWriter.Commit();
+            publishTaxoWriter.Commit();
+            return new IndexAndTaxonomyRevision(publishIndexWriter, publishTaxoWriter);
+        }
+
+        private Document NewDocument(ITaxonomyWriter taxoWriter, int id)
+        {
+            Document doc = new Document();
+            doc.Add(new FacetField("A", id.ToString("X")));
+            return config.Build(taxoWriter, doc);
+        }
+
+        public override void SetUp()
+        {
+            base.SetUp();
+
+            publishIndexDir = NewDirectory();
+            publishTaxoDir = NewDirectory();
+            handlerIndexDir = NewMockDirectory();
+            handlerTaxoDir = NewMockDirectory();
+            clientWorkDir = CreateTempDir("replicationClientTest");
+            sourceDirFactory = new PerSessionDirectoryFactory(clientWorkDir.FullName);
+            replicator = new LocalReplicator();
+            callback = new IndexAndTaxonomyReadyCallback(handlerIndexDir, handlerTaxoDir);
+            handler = new IndexAndTaxonomyReplicationHandler(handlerIndexDir, handlerTaxoDir, callback.Call);
+            client = new ReplicationClient(replicator, handler, sourceDirFactory);
+
+            IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            publishIndexWriter = new IndexWriter(publishIndexDir, conf);
+            publishTaxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(publishTaxoDir);
+            config = new FacetsConfig();
+            config.SetHierarchical("A", true);
+        }
+
+        public override void TearDown()
+        {
+            IOUtils.Dispose(client, callback, publishIndexWriter, publishTaxoWriter, replicator, publishIndexDir, publishTaxoDir,
+                handlerIndexDir, handlerTaxoDir);
+            base.TearDown();
+        }
+
+        [Test]
+        public void TestNoUpdateThread()
+        {
+            assertNull("no version expected at start", handler.CurrentVersion);
+
+            // Callback validates the replicated index
+            replicator.Publish(CreateRevision(1));
+            client.UpdateNow();
+
+            // make sure updating twice, when in fact there's nothing to update, works
+            client.UpdateNow();
+
+            replicator.Publish(CreateRevision(2));
+            client.UpdateNow();
+
+            // Publish two revisions without update, handler should be upgraded to latest
+            replicator.Publish(CreateRevision(3));
+            replicator.Publish(CreateRevision(4));
+            client.UpdateNow();
+        }
+
+        [Test]
+        public void TestRestart()
+        {
+            replicator.Publish(CreateRevision(1));
+            client.UpdateNow();
+
+            replicator.Publish(CreateRevision(2));
+            client.UpdateNow();
+
+            client.StopUpdateThread();
+            client.Dispose();
+            client = new ReplicationClient(replicator, handler, sourceDirFactory);
+
+            // Publish two revisions without update, handler should be upgraded to latest
+            replicator.Publish(CreateRevision(3));
+            replicator.Publish(CreateRevision(4));
+            client.UpdateNow();
+        }
+
+        [Test]
+        public void TestUpdateThread()
+        {
+            client.StartUpdateThread(10, "indexTaxo");
+
+            replicator.Publish(CreateRevision(1));
+            AssertHandlerRevision(1, handlerIndexDir);
+
+            replicator.Publish(CreateRevision(2));
+            AssertHandlerRevision(2, handlerIndexDir);
+
+            // Publish two revisions without update, handler should be upgraded to latest
+            replicator.Publish(CreateRevision(3));
+            replicator.Publish(CreateRevision(4));
+            AssertHandlerRevision(4, handlerIndexDir);
+        }
+
+        [Test]
+        public void TestRecreateTaxonomy()
+        {
+            replicator.Publish(CreateRevision(1));
+            client.UpdateNow();
+
+            // recreate index and taxonomy
+            Directory newTaxo = NewDirectory();
+            new DirectoryTaxonomyWriter(newTaxo).Dispose();
+            publishTaxoWriter.ReplaceTaxonomy(newTaxo);
+            publishIndexWriter.DeleteAll();
+            replicator.Publish(CreateRevision(2));
+
+            client.UpdateNow();
+            newTaxo.Dispose();
+        }
+
+        //JAVA: /*
+        //JAVA:  * This test verifies that the client and handler do not end up in a corrupt
+        //JAVA:  * index if exceptions are thrown at any point during replication. Either when
+        //JAVA:  * a client copies files from the server to the temporary space, or when the
+        //JAVA:  * handler copies them to the index directory.
+        //JAVA:  */
+        [Test]
+        public void TestConsistencyOnExceptions()
+        {
+            // so the handler's index isn't empty
+            replicator.Publish(CreateRevision(1));
+            client.UpdateNow();
+            client.Dispose();
+            callback.Dispose();
+
+            // Replicator violates write-once policy. It may be that the
+            // handler copies files to the index dir, then fails to copy a
+            // file and reverts the copy operation. On the next attempt, it
+            // will copy the same file again. There is nothing wrong with this
+            // in a real system, but it does violate write-once, and MDW
+            // doesn't like it. Disabling it means that we won't catch cases
+            // where the handler overwrites an existing index file, but
+            // there's nothing currently we can do about it, unless we don't
+            // use MDW.
+            handlerIndexDir.PreventDoubleWrite=(false);
+            handlerTaxoDir.PreventDoubleWrite = (false);
+
+            // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
+            ISourceDirectoryFactory @in = sourceDirFactory;
+            AtomicInt32 failures = new AtomicInt32(AtLeast(10));
+
+            sourceDirFactory = new SourceDirectoryFactoryAnonymousInnerClass(this, @in, failures);
+            handler = new IndexAndTaxonomyReplicationHandler(handlerIndexDir, handlerTaxoDir, () =>
+            {
+                if (Random().NextDouble() < 0.2 && failures.Get() > 0)
+                    throw new Exception("random exception from callback");
+                return null;
+            });
+            client = new ReplicationClientAnonymousInnerClass(this, replicator, handler, @in, failures);
+            client.StartUpdateThread(10, "indexAndTaxo");
+
+            Directory baseHandlerIndexDir = handlerIndexDir.Delegate;
+            int numRevisions = AtLeast(20) + 2;
+            for (int i = 2; i < numRevisions; i++)
+            {
+                replicator.Publish(CreateRevision(i));
+                AssertHandlerRevision(i, baseHandlerIndexDir);
+            }
+
+            // disable errors -- maybe randomness didn't exhaust all allowed failures,
+            // and we don't want e.g. CheckIndex to hit false errors. 
+            handlerIndexDir.MaxSizeInBytes=(0);
+            handlerIndexDir.RandomIOExceptionRate=(0.0);
+            handlerIndexDir.RandomIOExceptionRateOnOpen=(0.0);
+            handlerTaxoDir.MaxSizeInBytes=(0);
+            handlerTaxoDir.RandomIOExceptionRate=(0.0);
+            handlerTaxoDir.RandomIOExceptionRateOnOpen=(0.0);
+        }
+
+        private class SourceDirectoryFactoryAnonymousInnerClass : ISourceDirectoryFactory
+        {
+            private long clientMaxSize = 100, handlerIndexMaxSize = 100, handlerTaxoMaxSize = 100;
+            private double clientExRate = 1.0, handlerIndexExRate = 1.0, handlerTaxoExRate = 1.0;
+
+            private readonly IndexAndTaxonomyReplicationClientTest test;
+            private readonly ISourceDirectoryFactory @in;
+            private readonly AtomicInt32 failures;
+
+            public SourceDirectoryFactoryAnonymousInnerClass(IndexAndTaxonomyReplicationClientTest test, ISourceDirectoryFactory @in, AtomicInt32 failures)
+            {
+                this.test = test;
+                this.@in = @in;
+                this.failures = failures;
+            }
+
+            public void CleanupSession(string sessionId)
+            {
+                @in.CleanupSession(sessionId);
+            }
+
+            public Directory GetDirectory(string sessionId, string source)
+            {
+                Directory dir = @in.GetDirectory(sessionId, source);
+                if (Random().nextBoolean() && failures.Get() > 0)
+                { // client should fail, return wrapped dir
+                    MockDirectoryWrapper mdw = new MockDirectoryWrapper(Random(), dir);
+                    mdw.RandomIOExceptionRateOnOpen = clientExRate;
+                    mdw.MaxSizeInBytes = clientMaxSize;
+                    mdw.RandomIOExceptionRate = clientExRate;
+                    mdw.CheckIndexOnClose = false;
+                    clientMaxSize *= 2;
+                    clientExRate /= 2;
+                    return mdw;
+                }
+
+                if (failures.Get() > 0 && Random().nextBoolean())
+                { // handler should fail
+                    if (Random().nextBoolean())
+                    { // index dir fail
+                        test.handlerIndexDir.MaxSizeInBytes=(handlerIndexMaxSize);
+                        test.handlerIndexDir.RandomIOExceptionRate = (handlerIndexExRate);
+                        test.handlerIndexDir.RandomIOExceptionRateOnOpen = (handlerIndexExRate);
+                        handlerIndexMaxSize *= 2;
+                        handlerIndexExRate /= 2;
+                    }
+                    else
+                    { // taxo dir fail
+                        test.handlerTaxoDir.MaxSizeInBytes = (handlerTaxoMaxSize);
+                        test.handlerTaxoDir.RandomIOExceptionRate = (handlerTaxoExRate);
+                        test.handlerTaxoDir.RandomIOExceptionRateOnOpen = (handlerTaxoExRate);
+                        test.handlerTaxoDir.CheckIndexOnClose = (false);
+                        handlerTaxoMaxSize *= 2;
+                        handlerTaxoExRate /= 2;
+                    }
+                }
+                else
+                {
+                    // disable all errors
+                    test.handlerIndexDir.MaxSizeInBytes = (0);
+                    test.handlerIndexDir.RandomIOExceptionRate = (0.0);
+                    test.handlerIndexDir.RandomIOExceptionRateOnOpen = (0.0);
+                    test.handlerTaxoDir.MaxSizeInBytes = (0);
+                    test.handlerTaxoDir.RandomIOExceptionRate = (0.0);
+                    test.handlerTaxoDir.RandomIOExceptionRateOnOpen = (0.0);
+                }
+                return dir;
+            }
+        }
+
+
+
+        private class ReplicationClientAnonymousInnerClass : ReplicationClient
+        {
+            private readonly IndexAndTaxonomyReplicationClientTest test;
+            private readonly AtomicInt32 failures;
+
+            public ReplicationClientAnonymousInnerClass(IndexAndTaxonomyReplicationClientTest test, IReplicator replicator, IReplicationHandler handler, ISourceDirectoryFactory factory, AtomicInt32 failures)
+                : base(replicator, handler, factory)
+            {
+                this.test = test;
+                this.failures = failures;
+            }
+
+            protected override void HandleUpdateException(Exception exception)
+            {
+                if (exception is IOException)
+                {
+                    try
+                    {
+                        if (VERBOSE)
+                        {
+                            Console.WriteLine("hit exception during update: " + exception);
+                        }
+
+                        // test that the index can be read and also some basic statistics
+                        DirectoryReader reader = DirectoryReader.Open(test.handlerIndexDir.Delegate);
+                        try
+                        {
+                            int numDocs = reader.NumDocs;
+                            int version = int.Parse(reader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+                            assertEquals(numDocs, version);
+                        }
+                        finally
+                        {
+                            reader.Dispose();
+                        }
+                        // verify index consistency
+                        TestUtil.CheckIndex(test.handlerIndexDir.Delegate);
+
+                        // verify taxonomy index is fully consistent (since we only add one
+                        // category to all documents, there's nothing much more to validate
+                        TestUtil.CheckIndex(test.handlerTaxoDir.Delegate);
+                    }
+                    //TODO: Java had this, but considering what it does do we need it?
+                    //JAVA: catch (IOException e)
+                    //JAVA: {
+                    //JAVA:     throw new RuntimeException(e);
+                    //JAVA: }
+                    finally
+                    {
+                        // count-down number of failures
+                        failures.DecrementAndGet();
+                        Debug.Assert(failures.Get() >= 0, "handler failed too many times: " + failures.Get());
+                        if (VERBOSE)
+                        {
+                            if (failures.Get() == 0)
+                            {
+                                Console.WriteLine("no more failures expected");
+                            }
+                            else
+                            {
+                                Console.WriteLine("num failures left: " + failures.Get());
+                            }
+                        }
+                    }
+                }
+                else
+                {
+                    //JAVA:          if (t instanceof RuntimeException) throw (RuntimeException) t;
+                    //JAVA:          throw new RuntimeException(t);
+                    throw exception;
+                }
+            }
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
new file mode 100644
index 0000000..dd20864
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
@@ -0,0 +1,188 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Lucene.Net.Documents;
+using Lucene.Net.Facet;
+using Lucene.Net.Facet.Taxonomy;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using NUnit.Framework;
+
+namespace Lucene.Net.Tests.Replicator
+{
+    /*
+	 * 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.
+	 */
+
+    public class IndexAndTaxonomyRevisionTest : ReplicatorTestCase
+    {
+        private Document NewDocument(ITaxonomyWriter taxoWriter)
+        {
+            FacetsConfig config = new FacetsConfig();
+            Document doc = new Document();
+            doc.Add(new FacetField("A", "1"));
+            return config.Build(taxoWriter, doc);
+        }
+
+        [Test]
+        public void TestNoCommit()
+        {
+            Directory indexDir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            IndexWriter indexWriter = new IndexWriter(indexDir, conf);
+
+            Directory taxoDir = NewDirectory();
+            IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter taxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(taxoDir);
+            try
+            {
+                assertNotNull(new IndexAndTaxonomyRevision(indexWriter, taxoWriter));
+                fail("should have failed when there are no commits to snapshot");
+            }
+            catch (System.InvalidOperationException)
+            {
+                // expected
+            }
+            finally
+            {
+                IOUtils.Dispose(indexWriter, taxoWriter, taxoDir, indexDir);
+            }
+        }
+
+        [Test]
+        public void TestRevisionRelease()
+        {
+            Directory indexDir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            IndexWriter indexWriter = new IndexWriter(indexDir, conf);
+
+            Directory taxoDir = NewDirectory();
+            IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter taxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(taxoDir);
+            try
+            {
+                indexWriter.AddDocument(NewDocument(taxoWriter));
+                indexWriter.Commit();
+                taxoWriter.Commit();
+                IRevision rev1 = new IndexAndTaxonomyRevision(indexWriter, taxoWriter);
+                // releasing that revision should not delete the files
+                rev1.Release();
+                assertTrue(SlowFileExists(indexDir, IndexFileNames.SEGMENTS + "_1"));
+                assertTrue(SlowFileExists(taxoDir, IndexFileNames.SEGMENTS + "_1"));
+
+                rev1 = new IndexAndTaxonomyRevision(indexWriter, taxoWriter); // create revision again, so the files are snapshotted
+                indexWriter.AddDocument(NewDocument(taxoWriter));
+                indexWriter.Commit();
+                taxoWriter.Commit();
+                assertNotNull(new IndexAndTaxonomyRevision(indexWriter, taxoWriter));
+                rev1.Release(); // this release should trigger the delete of segments_1
+                assertFalse(SlowFileExists(indexDir, IndexFileNames.SEGMENTS + "_1"));
+            }
+            finally
+            {
+                IOUtils.Dispose(indexWriter, taxoWriter, taxoDir, indexDir);
+            }
+        }
+
+        [Test]
+        public void TestSegmentsFileLast()
+        {
+            Directory indexDir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            IndexWriter indexWriter = new IndexWriter(indexDir, conf);
+
+            Directory taxoDir = NewDirectory();
+            IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter taxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(taxoDir);
+            try
+            {
+                indexWriter.AddDocument(NewDocument(taxoWriter));
+                indexWriter.Commit();
+                taxoWriter.Commit();
+                IRevision rev = new IndexAndTaxonomyRevision(indexWriter, taxoWriter);
+                var sourceFiles = rev.SourceFiles;
+                assertEquals(2, sourceFiles.Count);
+                foreach (var files in sourceFiles.Values)
+                {
+                    string lastFile = files.Last().FileName;
+                    assertTrue(lastFile.StartsWith(IndexFileNames.SEGMENTS, StringComparison.Ordinal) && !lastFile.Equals(IndexFileNames.SEGMENTS_GEN));
+                }
+            }
+            finally
+            {
+                IOUtils.Dispose(indexWriter, taxoWriter, taxoDir, indexDir);
+            }
+        }
+
+        [Test]
+        public void TestOpen()
+        {
+            Directory indexDir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            IndexWriter indexWriter = new IndexWriter(indexDir, conf);
+
+            Directory taxoDir = NewDirectory();
+            IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter taxoWriter = new IndexAndTaxonomyRevision.SnapshotDirectoryTaxonomyWriter(taxoDir);
+            try
+            {
+                indexWriter.AddDocument(NewDocument(taxoWriter));
+                indexWriter.Commit();
+                taxoWriter.Commit();
+                IRevision rev = new IndexAndTaxonomyRevision(indexWriter, taxoWriter);
+                foreach (var e in rev.SourceFiles)
+                {
+                    string source = e.Key;
+                    Directory dir = source.Equals(IndexAndTaxonomyRevision.INDEX_SOURCE) ? indexDir : taxoDir;
+                    foreach (RevisionFile file in e.Value)
+                    {
+                        IndexInput src = dir.OpenInput(file.FileName, IOContext.READ_ONCE);
+                        System.IO.Stream @in = rev.Open(source, file.FileName);
+                        assertEquals(src.Length, @in.Length);
+                        byte[] srcBytes = new byte[(int)src.Length];
+                        byte[] inBytes = new byte[(int)src.Length];
+                        int offset = 0;
+                        if (Random().nextBoolean())
+                        {
+                            int skip = Random().Next(10);
+                            if (skip >= src.Length)
+                            {
+                                skip = 0;
+                            }
+                            //JAVA: in.skip(skip);
+                            byte[] skips = new byte[skip];
+                            @in.Read(skips, 0, skip);
+                            src.Seek(skip);
+                            offset = skip;
+                        }
+                        src.ReadBytes(srcBytes, offset, srcBytes.Length - offset);
+                        @in.Read(inBytes, offset, inBytes.Length - offset);
+                        assertArrayEquals(srcBytes, inBytes);
+                        IOUtils.Dispose(src, @in);
+                    }
+                }
+            }
+            finally
+            {
+                IOUtils.Dispose(indexWriter, taxoWriter, taxoDir, indexDir);
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
new file mode 100644
index 0000000..6a56c77
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
@@ -0,0 +1,513 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Threading;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Store;
+using Lucene.Net.Support;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Tests.Replicator
+{
+    [TestFixture]
+    public class IndexReplicationClientTest : ReplicatorTestCase
+    {
+        private class IndexReadyCallback : IDisposable
+        {
+            private readonly Directory indexDir;
+            private DirectoryReader reader;
+            private long lastGeneration = -1;
+
+            public IndexReadyCallback(Directory indexDir)
+            {
+                //JAVA:    public IndexReadyCallback(Directory indexDir) throws IOException {
+                //JAVA:      this.indexDir = indexDir;
+                //JAVA:      if (DirectoryReader.indexExists(indexDir)) {
+                //JAVA:        reader = DirectoryReader.open(indexDir);
+                //JAVA:        lastGeneration = reader.getIndexCommit().getGeneration();
+                //JAVA:      }
+                //JAVA:    }
+
+                this.indexDir = indexDir;
+                if (DirectoryReader.IndexExists(indexDir))
+                {
+                    reader = DirectoryReader.Open(indexDir);
+                    lastGeneration = reader.IndexCommit.Generation;
+                }
+            }
+
+            public bool? Call()
+            {
+                //JAVA:    public Boolean call() throws Exception {
+                //JAVA:      if (reader == null) {
+                //JAVA:        reader = DirectoryReader.open(indexDir);
+                //JAVA:        lastGeneration = reader.getIndexCommit().getGeneration();
+                //JAVA:      } else {
+                //JAVA:        DirectoryReader newReader = DirectoryReader.openIfChanged(reader);
+                //JAVA:        assertNotNull("should not have reached here if no changes were made to the index", newReader);
+                //JAVA:        long newGeneration = newReader.getIndexCommit().getGeneration();
+                //JAVA:        assertTrue("expected newer generation; current=" + lastGeneration + " new=" + newGeneration, newGeneration > lastGeneration);
+                //JAVA:        reader.close();
+                //JAVA:        reader = newReader;
+                //JAVA:        lastGeneration = newGeneration;
+                //JAVA:        TestUtil.checkIndex(indexDir);
+                //JAVA:      }
+                //JAVA:      return null;
+                //JAVA:    }
+                if (reader == null)
+                {
+                    reader = DirectoryReader.Open(indexDir);
+                    lastGeneration = reader.IndexCommit.Generation;
+                }
+                else
+                {
+                    DirectoryReader newReader = DirectoryReader.OpenIfChanged(reader);
+                    assertNotNull("should not have reached here if no changes were made to the index", newReader);
+                    long newGeneration = newReader.IndexCommit.Generation;
+                    assertTrue("expected newer generation; current=" + lastGeneration + " new=" + newGeneration, newGeneration > lastGeneration);
+                    reader.Dispose();
+                    reader = newReader;
+                    lastGeneration = newGeneration;
+                    TestUtil.CheckIndex(indexDir);
+                }
+                return null;
+            }
+            public void Dispose()
+            {
+                IOUtils.Dispose(reader);
+            }
+        }
+
+
+        private MockDirectoryWrapper publishDir, handlerDir;
+        private IReplicator replicator;
+        private ISourceDirectoryFactory sourceDirFactory;
+        private ReplicationClient client;
+        private IReplicationHandler handler;
+        private IndexWriter publishWriter;
+        private IndexReadyCallback callback;
+        //JAVA:  private IndexReadyCallback callback;
+
+        private const string VERSION_ID = "version";
+
+        private void AssertHandlerRevision(int expectedId, Directory dir)
+        {
+            //JAVA:  private void assertHandlerRevision(int expectedID, Directory dir) throws IOException {
+            //JAVA:    // loop as long as client is alive. test-framework will terminate us if
+            //JAVA:    // there's a serious bug, e.g. client doesn't really update. otherwise,
+            //JAVA:    // introducing timeouts is not good, can easily lead to false positives.
+            //JAVA:    while (client.isUpdateThreadAlive()) {
+            //JAVA:      // give client a chance to update
+            //JAVA:      try {
+            //JAVA:        Thread.sleep(100);
+            //JAVA:      } catch (InterruptedException e) {
+            //JAVA:        throw new ThreadInterruptedException(e);
+            //JAVA:      }
+            //JAVA:
+            //JAVA:      try {
+            //JAVA:        DirectoryReader reader = DirectoryReader.open(dir);
+            //JAVA:        try {
+            //JAVA:          int handlerID = Integer.parseInt(reader.getIndexCommit().getUserData().get(VERSION_ID), 16);
+            //JAVA:          if (expectedID == handlerID) {
+            //JAVA:            return;
+            //JAVA:          } else if (VERBOSE) {
+            //JAVA:            System.out.println("expectedID=" + expectedID + " actual=" + handlerID + " generation=" + reader.getIndexCommit().getGeneration());
+            //JAVA:          }
+            //JAVA:        } finally {
+            //JAVA:          reader.close();
+            //JAVA:        }
+            //JAVA:      } catch (Exception e) {
+            //JAVA:        // we can hit IndexNotFoundException or e.g. EOFException (on
+            //JAVA:        // segments_N) because it is being copied at the same time it is read by
+            //JAVA:        // DirectoryReader.open().
+            //JAVA:      }
+            //JAVA:    }
+            //JAVA:  }
+
+            // loop as long as client is alive. test-framework will terminate us if
+            // there's a serious bug, e.g. client doesn't really update. otherwise,
+            // introducing timeouts is not good, can easily lead to false positives.
+            while (client.IsUpdateThreadAlive)
+            {
+                // give client a chance to update
+                Thread.Sleep(100);
+                try
+                {
+                    DirectoryReader reader = DirectoryReader.Open(dir);
+                    try
+                    {
+                        int handlerId = int.Parse(reader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+                        if (expectedId == handlerId)
+                        {
+                            return;
+                        }
+                        else if (VERBOSE)
+                        {
+                            Console.WriteLine("expectedID=" + expectedId + " actual=" + handlerId + " generation=" + reader.IndexCommit.Generation);
+                        }
+                    }
+                    finally
+                    {
+                        reader.Dispose();
+                    }
+                }
+                catch (Exception)
+                {
+                    // we can hit IndexNotFoundException or e.g. EOFException (on
+                    // segments_N) because it is being copied at the same time it is read by
+                    // DirectoryReader.open().
+                }
+            }
+        }
+
+        private IRevision CreateRevision(int id)
+        {
+            //JAVA:  private Revision createRevision(final int id) throws IOException {
+            //JAVA:    publishWriter.addDocument(new Document());
+            //JAVA:    publishWriter.setCommitData(new HashMap<String, String>() {{
+            //JAVA:      put(VERSION_ID, Integer.toString(id, 16));
+            //JAVA:    }});
+            //JAVA:    publishWriter.commit();
+            //JAVA:    return new IndexRevision(publishWriter);
+            //JAVA:  }
+            publishWriter.AddDocument(new Document());
+            publishWriter.SetCommitData(new Dictionary<string, string>{
+                { VERSION_ID, id.ToString("X") }
+            });
+            publishWriter.Commit();
+            return new IndexRevision(publishWriter);
+        }
+
+        public override void SetUp()
+        {
+            //JAVA:  public void setUp() throws Exception {
+            //JAVA:    super.setUp();
+            //JAVA:    publishDir = newMockDirectory();
+            //JAVA:    handlerDir = newMockDirectory();
+            //JAVA:    sourceDirFactory = new PerSessionDirectoryFactory(createTempDir("replicationClientTest"));
+            //JAVA:    replicator = new LocalReplicator();
+            //JAVA:    callback = new IndexReadyCallback(handlerDir);
+            //JAVA:    handler = new IndexReplicationHandler(handlerDir, callback);
+            //JAVA:    client = new ReplicationClient(replicator, handler, sourceDirFactory);
+            //JAVA:    
+            //JAVA:    IndexWriterConfig conf = newIndexWriterConfig(TEST_VERSION_CURRENT, null);
+            //JAVA:    conf.setIndexDeletionPolicy(new SnapshotDeletionPolicy(conf.getIndexDeletionPolicy()));
+            //JAVA:    publishWriter = new IndexWriter(publishDir, conf);
+            //JAVA:  }
+            base.SetUp();
+
+            publishDir = NewMockDirectory();
+            handlerDir = NewMockDirectory();
+            sourceDirFactory = new PerSessionDirectoryFactory(CreateTempDir("replicationClientTest").FullName);
+            replicator = new LocalReplicator();
+            callback = new IndexReadyCallback(handlerDir);
+            handler = new IndexReplicationHandler(handlerDir, callback.Call);
+            client = new ReplicationClient(replicator, handler, sourceDirFactory);
+
+            IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            publishWriter = new IndexWriter(publishDir, conf);
+        }
+
+        public override void TearDown()
+        {
+            //JAVA:  public void tearDown() throws Exception {
+            //JAVA:    IOUtils.close(client, callback, publishWriter, replicator, publishDir, handlerDir);
+            //JAVA:    super.tearDown();
+            //JAVA:  }
+            IOUtils.Dispose(client, callback, publishWriter, replicator, publishDir, handlerDir);
+            base.TearDown();
+        }
+
+        [Test]
+        public void TestNoUpdateThread()
+        {
+            //JAVA:  public void testNoUpdateThread() throws Exception {
+            //JAVA:    assertNull("no version expected at start", handler.currentVersion());
+            //JAVA:    
+            //JAVA:    // Callback validates the replicated index
+            //JAVA:    replicator.publish(createRevision(1));
+            //JAVA:    client.updateNow();
+            //JAVA:    
+            //JAVA:    replicator.publish(createRevision(2));
+            //JAVA:    client.updateNow();
+            //JAVA:    
+            //JAVA:    // Publish two revisions without update, handler should be upgraded to latest
+            //JAVA:    replicator.publish(createRevision(3));
+            //JAVA:    replicator.publish(createRevision(4));
+            //JAVA:    client.updateNow();
+            //JAVA:  }
+            assertNull("no version expected at start", handler.CurrentVersion);
+
+            // Callback validates the replicated ind
+            replicator.Publish(CreateRevision(1));
+            client.UpdateNow();
+
+            replicator.Publish(CreateRevision(2));
+            client.UpdateNow();
+
+            // Publish two revisions without update,
+            replicator.Publish(CreateRevision(3));
+            replicator.Publish(CreateRevision(4));
+            client.UpdateNow();
+        }
+
+
+        [Test]
+        public void TestUpdateThread()
+        {
+            //JAVA:  public void testUpdateThread() throws Exception {
+            //JAVA:    client.startUpdateThread(10, "index");
+            //JAVA:    
+            //JAVA:    replicator.publish(createRevision(1));
+            //JAVA:    assertHandlerRevision(1, handlerDir);
+            //JAVA:    
+            //JAVA:    replicator.publish(createRevision(2));
+            //JAVA:    assertHandlerRevision(2, handlerDir);
+            //JAVA:    
+            //JAVA:    // Publish two revisions without update, handler should be upgraded to latest
+            //JAVA:    replicator.publish(createRevision(3));
+            //JAVA:    replicator.publish(createRevision(4));
+            //JAVA:    assertHandlerRevision(4, handlerDir);
+            //JAVA:  }
+
+            client.StartUpdateThread(10, "index");
+
+            replicator.Publish(CreateRevision(1));
+            AssertHandlerRevision(1, handlerDir);
+
+            replicator.Publish(CreateRevision(2));
+            AssertHandlerRevision(2, handlerDir);
+
+            // Publish two revisions without update, handler should be upgraded to latest
+            replicator.Publish(CreateRevision(3));
+            replicator.Publish(CreateRevision(4));
+            AssertHandlerRevision(4, handlerDir);
+        }
+
+        [Test]
+        public void TestRestart()
+        {
+            //JAVA:  public void testRestart() throws Exception {
+            //JAVA:    replicator.publish(createRevision(1));
+            //JAVA:    client.updateNow();
+            //JAVA:    
+            //JAVA:    replicator.publish(createRevision(2));
+            //JAVA:    client.updateNow();
+            //JAVA:    
+            //JAVA:    client.stopUpdateThread();
+            //JAVA:    client.close();
+            //JAVA:    client = new ReplicationClient(replicator, handler, sourceDirFactory);
+            //JAVA:    
+            //JAVA:    // Publish two revisions without update, handler should be upgraded to latest
+            //JAVA:    replicator.publish(createRevision(3));
+            //JAVA:    replicator.publish(createRevision(4));
+            //JAVA:    client.updateNow();
+            //JAVA:  }
+            replicator.Publish(CreateRevision(1));
+            client.UpdateNow();
+
+            replicator.Publish(CreateRevision(2));
+            client.UpdateNow();
+
+            client.StopUpdateThread();
+            client.Dispose();
+            client = new ReplicationClient(replicator, handler, sourceDirFactory);
+
+            // Publish two revisions without update, handler should be upgraded to latest
+            replicator.Publish(CreateRevision(3));
+            replicator.Publish(CreateRevision(4));
+            client.UpdateNow();
+        }
+
+        //JAVA:  /*
+        //JAVA:   * This test verifies that the client and handler do not end up in a corrupt
+        //JAVA:   * index if exceptions are thrown at any point during replication. Either when
+        //JAVA:   * a client copies files from the server to the temporary space, or when the
+        //JAVA:   * handler copies them to the index directory.
+        //JAVA:   */
+        [Test]
+        public void TestConsistencyOnExceptions()
+        {
+            // so the handler's index isn't empty
+            replicator.Publish(CreateRevision(1));
+            client.UpdateNow();
+            client.Dispose();
+            callback.Dispose();
+
+            // Replicator violates write-once policy. It may be that the
+            // handler copies files to the index dir, then fails to copy a
+            // file and reverts the copy operation. On the next attempt, it
+            // will copy the same file again. There is nothing wrong with this
+            // in a real system, but it does violate write-once, and MDW
+            // doesn't like it. Disabling it means that we won't catch cases
+            // where the handler overwrites an existing index file, but
+            // there's nothing currently we can do about it, unless we don't
+            // use MDW.
+            //JAVA:    handlerDir.setPreventDoubleWrite(false);
+            handlerDir.PreventDoubleWrite = false;
+
+            // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
+            ISourceDirectoryFactory @in = sourceDirFactory;
+            AtomicInt32 failures = new AtomicInt32(AtLeast(10));
+
+            // wrap sourceDirFactory to return a MockDirWrapper so we can simulate errors
+            sourceDirFactory = new SourceDirectoryFactoryAnonymousInnerClass(this, @in, failures);
+            handler = new IndexReplicationHandler(handlerDir, () =>
+            {
+                if (Random().NextDouble() < 0.2 && failures.Get() > 0)
+                    throw new Exception("random exception from callback");
+                return null;
+            });
+            client = new ReplicationClientAnonymousInnerClass(this, replicator, handler, sourceDirFactory, failures);
+            client.StartUpdateThread(10, "index");
+
+            Directory baseHandlerDir = handlerDir.Delegate;
+            int numRevisions = AtLeast(20);
+            for (int i = 2; i < numRevisions; i++)
+            {
+                replicator.Publish(CreateRevision(i));
+                AssertHandlerRevision(i, baseHandlerDir);
+            }
+
+            // disable errors -- maybe randomness didn't exhaust all allowed failures,
+            // and we don't want e.g. CheckIndex to hit false errors. 
+            handlerDir.MaxSizeInBytes = 0;
+            handlerDir.RandomIOExceptionRate=0.0;
+            handlerDir.RandomIOExceptionRateOnOpen=0.0;
+        }
+
+        private class SourceDirectoryFactoryAnonymousInnerClass : ISourceDirectoryFactory
+        {
+            private long clientMaxSize = 100, handlerMaxSize = 100;
+            private double clientExRate = 1.0, handlerExRate = 1.0;
+
+            private readonly IndexReplicationClientTest test;
+            private readonly ISourceDirectoryFactory @in;
+            private readonly AtomicInt32 failures;
+
+            public SourceDirectoryFactoryAnonymousInnerClass(IndexReplicationClientTest test, ISourceDirectoryFactory @in, AtomicInt32 failures)
+            {
+                this.test = test;
+                this.@in = @in;
+                this.failures = failures;
+            }
+
+            public void CleanupSession(string sessionId)
+            {
+                @in.CleanupSession(sessionId);
+            }
+
+            public Directory GetDirectory(string sessionId, string source)
+            {
+                Directory dir = @in.GetDirectory(sessionId, source);
+                if (Random().nextBoolean() && failures.Get() > 0)
+                { // client should fail, return wrapped dir
+                    MockDirectoryWrapper mdw = new MockDirectoryWrapper(Random(), dir);
+                    mdw.RandomIOExceptionRateOnOpen = clientExRate;
+                    mdw.MaxSizeInBytes = clientMaxSize;
+                    mdw.RandomIOExceptionRate = clientExRate;
+                    mdw.CheckIndexOnClose = false;
+                    clientMaxSize *= 2;
+                    clientExRate /= 2;
+                    return mdw;
+                }
+
+                if (failures.Get() > 0 && Random().nextBoolean())
+                { // handler should fail
+                    test.handlerDir.MaxSizeInBytes = handlerMaxSize;
+                    test.handlerDir.RandomIOExceptionRateOnOpen = handlerExRate;
+                    test.handlerDir.RandomIOExceptionRate = handlerExRate;
+                    handlerMaxSize *= 2;
+                    handlerExRate /= 2;
+                }
+                else
+                {
+                    // disable errors
+                    test.handlerDir.MaxSizeInBytes = 0;
+                    test.handlerDir.RandomIOExceptionRate = 0;
+                    test.handlerDir.RandomIOExceptionRateOnOpen = 0.0;
+                }
+                return dir;
+            }
+        }
+
+        private class ReplicationClientAnonymousInnerClass : ReplicationClient
+        {
+            private readonly IndexReplicationClientTest test;
+            private readonly AtomicInt32 failures;
+
+            public ReplicationClientAnonymousInnerClass(IndexReplicationClientTest test, IReplicator replicator, IReplicationHandler handler, ISourceDirectoryFactory factory, AtomicInt32 failures)
+                : base(replicator, handler, factory)
+            {
+                this.test = test;
+                this.failures = failures;
+            }
+
+            protected override void HandleUpdateException(Exception exception)
+            {
+                if (exception is IOException)
+                {
+                    if (VERBOSE)
+                    {
+                        Console.WriteLine("hit exception during update: " + exception);
+                    }
+
+                    try
+                    {
+                        // test that the index can be read and also some basic statistics
+                        DirectoryReader reader = DirectoryReader.Open(test.handlerDir.Delegate);
+                        try
+                        {
+                            int numDocs = reader.NumDocs;
+                            int version = int.Parse(reader.IndexCommit.UserData[VERSION_ID], NumberStyles.HexNumber);
+                            assertEquals(numDocs, version);
+                        }
+                        finally
+                        {
+                            reader.Dispose();
+                        }
+                        // verify index consistency
+                        TestUtil.CheckIndex(test.handlerDir.Delegate);
+                    }
+                    //TODO: Java had this, but considering what it does do we need it?
+                    //JAVA: catch (IOException e)
+                    //JAVA: {
+                    //JAVA:     // exceptions here are bad, don't ignore them
+                    //JAVA:     throw new RuntimeException(e);
+                    //JAVA: }
+                    finally
+                    {
+                        // count-down number of failures
+                        failures.DecrementAndGet();
+                        Debug.Assert(failures.Get() >= 0, "handler failed too many times: " + failures.Get());
+                        if (VERBOSE)
+                        {
+                            if (failures.Get() == 0)
+                            {
+                                Console.WriteLine("no more failures expected");
+                            }
+                            else
+                            {
+                                Console.WriteLine("num failures left: " + failures.Get());
+                            }
+                        }
+                    }
+                } else {
+                    //JAVA:          if (t instanceof RuntimeException) throw (RuntimeException) t;
+                    //JAVA:          throw new RuntimeException(t);
+                    throw exception;
+                }
+            }
+        }
+      
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
new file mode 100644
index 0000000..de4dbb4
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
@@ -0,0 +1,177 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Linq;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Store;
+using Lucene.Net.Util;
+using NUnit.Framework;
+
+namespace Lucene.Net.Tests.Replicator
+{
+    /*
+	 * 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.
+	 */
+
+    public class IndexRevisionTest : ReplicatorTestCase
+    {
+        [Test]
+        public void TestNoSnapshotDeletionPolicy()
+        {
+            Directory dir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new KeepOnlyLastCommitDeletionPolicy();
+            IndexWriter writer = new IndexWriter(dir, conf);
+            try
+            {
+                assertNotNull(new IndexRevision(writer));
+                fail("should have failed when IndexDeletionPolicy is not Snapshot");
+            }
+            catch (ArgumentException)
+            {
+                // expected
+            }
+            finally
+            {
+                IOUtils.Dispose(writer, dir);
+            }
+        }
+
+        [Test]
+        public void TestNoCommit()
+        {
+            Directory dir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            IndexWriter writer = new IndexWriter(dir, conf);
+            try
+            {
+                assertNotNull(new IndexRevision(writer));
+                fail("should have failed when there are no commits to snapshot");
+            }
+            catch (InvalidOperationException)
+            {
+                // expected
+            }
+            finally
+            {
+                IOUtils.Dispose(writer, dir);
+            }
+        }
+
+        [Test]
+        public void TestRevisionRelease()
+        {
+            Directory dir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            IndexWriter writer = new IndexWriter(dir, conf);
+            try
+            {
+                writer.AddDocument(new Document());
+                writer.Commit();
+                IRevision rev1 = new IndexRevision(writer);
+                // releasing that revision should not delete the files
+                rev1.Release();
+                assertTrue(SlowFileExists(dir, IndexFileNames.SEGMENTS + "_1"));
+
+                rev1 = new IndexRevision(writer); // create revision again, so the files are snapshotted
+                writer.AddDocument(new Document());
+                writer.Commit();
+                assertNotNull(new IndexRevision(writer));
+                rev1.Release(); // this release should trigger the delete of segments_1
+                assertFalse(SlowFileExists(dir, IndexFileNames.SEGMENTS + "_1"));
+            }
+            finally
+            {
+                IOUtils.Dispose(writer, dir);
+            }
+        }
+
+        [Test]
+        public void TestSegmentsFileLast()
+        {
+            Directory dir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            IndexWriter writer = new IndexWriter(dir, conf);
+            try
+            {
+                writer.AddDocument(new Document());
+                writer.Commit();
+                IRevision rev = new IndexRevision(writer);
+                var sourceFiles = rev.SourceFiles;
+                assertEquals(1, sourceFiles.Count);
+                var files = sourceFiles.Values.First();
+                string lastFile = files.Last().FileName;
+                assertTrue(lastFile.StartsWith(IndexFileNames.SEGMENTS, StringComparison.Ordinal) && !lastFile.Equals(IndexFileNames.SEGMENTS_GEN));
+            }
+            finally
+            {
+                IOUtils.Dispose(writer, dir);
+            }
+        }
+
+        [Test]
+        public void TestOpen()
+        {
+            Directory dir = NewDirectory();
+            IndexWriterConfig conf = new IndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            IndexWriter writer = new IndexWriter(dir, conf);
+            try
+            {
+                writer.AddDocument(new Document());
+                writer.Commit();
+                IRevision rev = new IndexRevision(writer);
+                var sourceFiles = rev.SourceFiles;
+                string source = sourceFiles.Keys.First();
+                foreach (RevisionFile file in sourceFiles.Values.First())
+                {
+                    IndexInput src = dir.OpenInput(file.FileName, IOContext.READ_ONCE);
+                    System.IO.Stream @in = rev.Open(source, file.FileName);
+                    assertEquals(src.Length, @in.Length);
+                    byte[] srcBytes = new byte[(int) src.Length];
+                    byte[] inBytes = new byte[(int) src.Length];
+                    int offset = 0;
+                    if (Random().nextBoolean())
+                    {
+                        int skip = Random().Next(10);
+                        if (skip >= src.Length)
+                        {
+                            skip = 0;
+                        }
+                        //JAVA: in.skip(skip);
+                        byte[] skips = new byte[skip];
+                        @in.Read(skips, 0, skip);
+                        src.Seek(skip);
+                        offset = skip;
+                    }
+                    src.ReadBytes(srcBytes, offset, srcBytes.Length - offset);
+                    @in.Read(inBytes, offset, inBytes.Length - offset);
+                    assertArrayEquals(srcBytes, inBytes);
+                    IOUtils.Dispose(src, @in);
+                }
+            }
+            finally
+            {
+                IOUtils.Dispose(writer, dir);
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
new file mode 100644
index 0000000..9946457
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
@@ -0,0 +1,225 @@
+//STATUS: DRAFT - 4.8.0
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Replicator;
+using Lucene.Net.Support;
+using Lucene.Net.Support.C5;
+using Lucene.Net.Util;
+using NUnit.Framework;
+using Directory = Lucene.Net.Store.Directory;
+
+namespace Lucene.Net.Tests.Replicator
+{
+    /*
+	 * 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.
+	 */
+
+    public class LocalReplicatorTest : ReplicatorTestCase
+    {
+        private const string VERSION_ID = "version";
+
+        private LocalReplicator replicator;
+        private Directory sourceDirectory;
+        private IndexWriter sourceWriter;
+
+        public override void SetUp()
+        {
+            base.SetUp();
+
+            sourceDirectory = NewDirectory();
+            IndexWriterConfig conf = NewIndexWriterConfig(TEST_VERSION_CURRENT, null);
+            conf.IndexDeletionPolicy = new SnapshotDeletionPolicy(conf.IndexDeletionPolicy);
+            sourceWriter = new IndexWriter(sourceDirectory, conf);
+            replicator = new LocalReplicator();
+        }
+
+        public override void TearDown()
+        {
+            IOUtils.Dispose(replicator, sourceWriter, sourceDirectory);
+            base.TearDown();
+        }
+
+        private IRevision CreateRevision(int id)
+        {
+            sourceWriter.AddDocument(new Document());
+            //JAVA: sourceWriter.setCommitData(new HashMap<String, String>() {{
+            //JAVA:     put(VERSION_ID, Integer.toString(id, 16));
+            //JAVA: }
+            sourceWriter.SetCommitData(new Dictionary<string, string> {
+                { VERSION_ID, id.ToString() }
+            });
+            sourceWriter.Commit();
+            return new IndexRevision(sourceWriter);
+        }
+
+        [Test]
+        public void TestCheckForUpdateNoRevisions()
+        {
+            assertNull(replicator.CheckForUpdate(null));
+        }
+        
+        [Test]
+        public void TestObtainFileAlreadyClosed()
+        {
+            replicator.Publish(CreateRevision(1));
+            SessionToken res = replicator.CheckForUpdate(null);
+            assertNotNull(res);
+            assertEquals(1, res.SourceFiles.Count);
+            System.Collections.Generic.KeyValuePair<string, System.Collections.Generic.IList<RevisionFile>> entry = res.SourceFiles.First();
+            replicator.Dispose();
+            try
+            {
+                replicator.ObtainFile(res.Id, entry.Key, entry.Value.First().FileName);
+                fail("should have failed on AlreadyClosedException");
+            }
+            catch (ObjectDisposedException)
+            {
+                // expected
+            }
+        }
+
+        [Test]
+        public void TestPublishAlreadyClosed()
+        {
+            replicator.Dispose();
+            try
+            {
+                replicator.Publish(CreateRevision(2));
+                fail("should have failed on AlreadyClosedException");
+            }
+            catch (ObjectDisposedException)
+            {
+                // expected
+            }
+        }
+
+        [Test]
+        public void TestUpdateAlreadyClosed()
+        {
+            replicator.Dispose();
+            try
+            {
+                replicator.CheckForUpdate(null);
+                fail("should have failed on AlreadyClosedException");
+            }
+            catch (ObjectDisposedException)
+            {
+                // expected
+            }
+        }
+
+        [Test]
+        public void TestPublishSameRevision()
+        {
+            IRevision rev = CreateRevision(1);
+            replicator.Publish(rev);
+            SessionToken res = replicator.CheckForUpdate(null);
+            assertNotNull(res);
+            assertEquals(rev.Version, res.Version);
+            replicator.Release(res.Id);
+            replicator.Publish(new IndexRevision(sourceWriter));
+            res = replicator.CheckForUpdate(res.Version);
+            assertNull(res);
+
+            // now make sure that publishing same revision doesn't leave revisions
+            // "locked", i.e. that replicator releases revisions even when they are not
+            // kept
+            replicator.Publish(CreateRevision(2));
+            assertEquals(1, DirectoryReader.ListCommits(sourceDirectory).size());
+        }
+
+        [Test]
+        public void TestPublishOlderRev()
+        {
+            replicator.Publish(CreateRevision(1));
+            IRevision old = new IndexRevision(sourceWriter);
+            replicator.Publish(CreateRevision(2));
+            try
+            {
+                replicator.Publish(old);
+                fail("should have failed to publish an older revision");
+            }
+            catch (System.ArgumentException)
+            {
+                // expected
+            }
+            assertEquals(1, DirectoryReader.ListCommits(sourceDirectory).size());
+        }
+
+        [Test]
+        public void TestObtainMissingFile()
+        {
+            replicator.Publish(CreateRevision(1));
+            SessionToken res = replicator.CheckForUpdate(null);
+            try
+            {
+                replicator.ObtainFile(res.Id, res.SourceFiles.Keys.First(), "madeUpFile");
+                fail("should have failed obtaining an unrecognized file");
+            }
+            //JAVA: } catch (FileNotFoundException | NoSuchFileException e) { -> Could not find a "NoSuchFileException" ?NoSuchItemException
+            catch (Exception e) when (e is FileNotFoundException)//|| e is NoSuchItemException)
+            {
+                // expected
+            }
+        }
+
+        [Test]
+        public void TestSessionExpiration()
+        {
+            replicator.Publish(CreateRevision(1));
+            SessionToken session = replicator.CheckForUpdate(null);
+            replicator.ExpirationThreshold = 5; // expire quickly
+            Thread.Sleep(50); // sufficient for expiration
+            try
+            {
+                replicator.ObtainFile(session.Id, session.SourceFiles.Keys.First(), session.SourceFiles.Values.First().First().FileName);
+                fail("should have failed to obtain a file for an expired session");
+            }
+            catch (SessionExpiredException)
+            {
+                // expected
+            }
+        }
+
+        [Test]
+        public void TestUpdateToLatest()
+        {
+            replicator.Publish(CreateRevision(1));
+            IRevision rev = CreateRevision(2);
+            replicator.Publish(rev);
+            SessionToken res = replicator.CheckForUpdate(null);
+            assertNotNull(res);
+            assertEquals(0, rev.CompareTo(res.Version));
+        }
+
+        [Test]
+        public void TestRevisionRelease()
+        {
+            replicator.Publish(CreateRevision(1));
+            assertTrue(SlowFileExists(sourceDirectory, IndexFileNames.SEGMENTS + "_1"));
+            replicator.Publish(CreateRevision(2));
+            // now the files of revision 1 can be deleted
+            assertTrue(SlowFileExists(sourceDirectory, IndexFileNames.SEGMENTS + "_2"));
+            assertFalse("segments_1 should not be found in index directory after revision is released", SlowFileExists(sourceDirectory, IndexFileNames.SEGMENTS + "_1"));
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6da4dd20/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
new file mode 100644
index 0000000..60adc6e
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
@@ -0,0 +1,219 @@
+<?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>{418E9D8E-2369-4B52-8D2F-5A987213999B}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Lucene.Net.Tests.Replicator</RootNamespace>
+    <AssemblyName>Lucene.Net.Tests.Replicator</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.Hosting, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.AspNetCore.Hosting.Abstractions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.Abstractions.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.Abstractions.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.Hosting.Server.Abstractions.1.0.3\lib\net451\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.AspNetCore.Http, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.Http.1.0.3\lib\net451\Microsoft.AspNetCore.Http.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <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.Extensions, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.Http.Extensions.1.0.3\lib\net451\Microsoft.AspNetCore.Http.Extensions.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.AspNetCore.TestHost, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.TestHost.1.0.3\lib\net451\Microsoft.AspNetCore.TestHost.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.AspNetCore.WebUtilities, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.AspNetCore.WebUtilities.1.0.3\lib\net451\Microsoft.AspNetCore.WebUtilities.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Configuration.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.Abstractions.1.0.2\lib\netstandard1.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Configuration.EnvironmentVariables.1.0.2\lib\net451\Microsoft.Extensions.Configuration.EnvironmentVariables.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.DependencyInjection, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.1.0.2\lib\netstandard1.1\Microsoft.Extensions.DependencyInjection.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.0.2\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.FileProviders.Abstractions, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.FileProviders.Abstractions.1.0.1\lib\netstandard1.0\Microsoft.Extensions.FileProviders.Abstractions.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.FileProviders.Physical, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.FileProviders.Physical.1.0.1\lib\net451\Microsoft.Extensions.FileProviders.Physical.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.FileSystemGlobbing, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.FileSystemGlobbing.1.0.1\lib\net451\Microsoft.Extensions.FileSystemGlobbing.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Logging.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Logging.Abstractions.1.0.2\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.ObjectPool, Version=1.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.ObjectPool.1.0.1\lib\net451\Microsoft.Extensions.ObjectPool.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Options, Version=1.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.Options.1.0.2\lib\netstandard1.0\Microsoft.Extensions.Options.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.PlatformAbstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Extensions.PlatformAbstractions.1.0.0\lib\net451\Microsoft.Extensions.PlatformAbstractions.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="Microsoft.Net.Http.Headers, Version=1.0.3.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Microsoft.Net.Http.Headers.1.0.3\lib\netstandard1.1\Microsoft.Net.Http.Headers.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Buffers, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Buffers.4.0.0\lib\netstandard1.1\System.Buffers.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.ComponentModel.Composition" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Diagnostics.DiagnosticSource.4.0.0\lib\portable-net45+win8+wpa81\System.Diagnostics.DiagnosticSource.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Reflection.Metadata, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
+      <Private>True</Private>
+    </Reference>
+    <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="..\CommonAssemblyInfo.cs">
+      <Link>Properties\CommonAssemblyInfo.cs</Link>
+    </Compile>
+    <Compile Include="Http\HttpReplicatorTest.cs" />
+    <Compile Include="Http\ReplicationServlet.cs" />
+    <Compile Include="IndexAndTaxonomyReplicationClientTest.cs" />
+    <Compile Include="IndexAndTaxonomyRevisionTest.cs" />
+    <Compile Include="IndexReplicationClientTest.cs" />
+    <Compile Include="IndexRevisionTest.cs" />
+    <Compile Include="LocalReplicatorTest.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ReplicatorTestCase.cs" />
+    <Compile Include="SessionTokenTest.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
+      <Project>{48F7884A-9454-4E88-8413-9D35992CB440}</Project>
+      <Name>Lucene.Net.Facet</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.Replicator.AspNetCore\Lucene.Net.Replicator.AspNetCore.csproj">
+      <Project>{763ccb5a-e397-456a-af47-7c6e228b1852}</Project>
+      <Name>Lucene.Net.Replicator.AspNetCore</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.Replicator\Lucene.Net.Replicator.csproj">
+      <Project>{1F70D2DB-C1B3-4F78-9598-3E04E0C7EB06}</Project>
+      <Name>Lucene.Net.Replicator</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net.TestFramework\Lucene.Net.TestFramework.csproj">
+      <Project>{B2C0D749-CE34-4F62-A15E-00CB2FF5DDB3}</Project>
+      <Name>Lucene.Net.TestFramework</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\Lucene.Net\Lucene.Net.csproj">
+      <Project>{5D4AD9BE-1FFB-41AB-9943-25737971BF57}</Project>
+      <Name>Lucene.Net</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


[20/20] lucenenet git commit: Lucene.Net.Replicator: Moved Http/Abstractions to Support folder

Posted by ni...@apache.org.
Lucene.Net.Replicator: Moved Http/Abstractions to Support folder


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

Branch: refs/heads/replicator
Commit: 14055123039832ffe010a5c8b697a3c698c443c3
Parents: f308f83
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 18:34:43 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 18:34:43 2017 +0700

----------------------------------------------------------------------
 .../Http/Abstractions/IReplicationRequest.cs    | 44 -------------------
 .../Http/Abstractions/IReplicationResponse.cs   | 46 --------------------
 .../Lucene.Net.Replicator.csproj                |  4 +-
 .../Http/Abstractions/IReplicationRequest.cs    | 44 +++++++++++++++++++
 .../Http/Abstractions/IReplicationResponse.cs   | 46 ++++++++++++++++++++
 5 files changed, 92 insertions(+), 92 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/14055123/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
deleted file mode 100644
index e1c3de5..0000000
--- a/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationRequest.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-namespace Lucene.Net.Replicator.Http.Abstractions
-{
-    /*
-	 * 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>
-    /// 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/14055123/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
deleted file mode 100644
index 1865dd4..0000000
--- a/src/Lucene.Net.Replicator/Http/Abstractions/IReplicationResponse.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System.IO;
-
-namespace Lucene.Net.Replicator.Http.Abstractions
-{
-    /*
-	 * 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>
-    /// 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/14055123/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
index 7ea6243..ac73af4 100644
--- a/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
+++ b/src/Lucene.Net.Replicator/Lucene.Net.Replicator.csproj
@@ -65,8 +65,8 @@
   <ItemGroup>
     <Compile Include="Http\HttpClientBase.cs" />
     <Compile Include="Http\HttpReplicator.cs" />
-    <Compile Include="Http\Abstractions\IReplicationRequest.cs" />
-    <Compile Include="Http\Abstractions\IReplicationResponse.cs" />
+    <Compile Include="Support\Http\Abstractions\IReplicationRequest.cs" />
+    <Compile Include="Support\Http\Abstractions\IReplicationResponse.cs" />
     <Compile Include="Http\ReplicationService.cs" />
     <Compile Include="IndexAndTaxonomyReplicationHandler.cs" />
     <Compile Include="IndexAndTaxonomyRevision.cs" />

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/14055123/src/Lucene.Net.Replicator/Support/Http/Abstractions/IReplicationRequest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Support/Http/Abstractions/IReplicationRequest.cs b/src/Lucene.Net.Replicator/Support/Http/Abstractions/IReplicationRequest.cs
new file mode 100644
index 0000000..e1c3de5
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Support/Http/Abstractions/IReplicationRequest.cs
@@ -0,0 +1,44 @@
+namespace Lucene.Net.Replicator.Http.Abstractions
+{
+    /*
+	 * 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>
+    /// 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/14055123/src/Lucene.Net.Replicator/Support/Http/Abstractions/IReplicationResponse.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/Support/Http/Abstractions/IReplicationResponse.cs b/src/Lucene.Net.Replicator/Support/Http/Abstractions/IReplicationResponse.cs
new file mode 100644
index 0000000..1865dd4
--- /dev/null
+++ b/src/Lucene.Net.Replicator/Support/Http/Abstractions/IReplicationResponse.cs
@@ -0,0 +1,46 @@
+using System.IO;
+
+namespace Lucene.Net.Replicator.Http.Abstractions
+{
+    /*
+	 * 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>
+    /// 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


[17/20] lucenenet git commit: Lucene.Net.Replicator.SessionToken: Fixed constructor to accept IDataInput instead of DataInputStream

Posted by ni...@apache.org.
Lucene.Net.Replicator.SessionToken: Fixed constructor to accept IDataInput instead of DataInputStream


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

Branch: refs/heads/replicator
Commit: 6469c62db4ed1e26f63eb121711a5d06af9691da
Parents: f0b3cd5
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 07:47:52 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 07:47:52 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Replicator/SessionToken.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/6469c62d/src/Lucene.Net.Replicator/SessionToken.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Replicator/SessionToken.cs b/src/Lucene.Net.Replicator/SessionToken.cs
index 305729b..e360688 100644
--- a/src/Lucene.Net.Replicator/SessionToken.cs
+++ b/src/Lucene.Net.Replicator/SessionToken.cs
@@ -54,7 +54,7 @@ namespace Lucene.Net.Replicator
         /// Constructor which deserializes from the given <see cref="IDataInput"/>.
         /// </summary>
         /// <exception cref="System.IO.IOException"></exception>
-        public SessionToken(DataInputStream reader) // LUCENENET TODO: API : IDataInput
+        public SessionToken(IDataInput reader)
         {
             Id = reader.ReadUTF();
             Version = reader.ReadUTF();


[13/20] lucenenet git commit: Lucene.Net.Tests.Replicator: Fixed usings, license headers, and namespaces

Posted by ni...@apache.org.
Lucene.Net.Tests.Replicator: Fixed usings, license headers, and namespaces


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

Branch: refs/heads/replicator
Commit: 1e6ce74528af8a21b6ee58ece6c590a4e49b4cad
Parents: fd43c50
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 03:00:42 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 03:02:03 2017 +0700

----------------------------------------------------------------------
 .../Http/HttpReplicatorTest.cs                  | 32 ++++++++++------
 .../Http/ReplicationServlet.cs                  | 24 +++++++++---
 .../IndexAndTaxonomyReplicationClientTest.cs    | 39 +++++++++++++-------
 .../IndexAndTaxonomyRevisionTest.cs             | 12 ++----
 .../IndexReplicationClientTest.cs               | 34 ++++++++++++-----
 .../IndexRevisionTest.cs                        | 11 ++----
 .../LocalReplicatorTest.cs                      | 15 +++-----
 .../Lucene.Net.Tests.Replicator.csproj          |  5 ++-
 .../ReplicatorTestCase.cs                       |  6 +--
 .../SessionTokenTest.cs                         | 12 ++----
 10 files changed, 112 insertions(+), 78 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
index 6254be6..564eceb 100644
--- a/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/Http/HttpReplicatorTest.cs
@@ -1,23 +1,33 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
-using Lucene.Net.Replicator;
-using Lucene.Net.Replicator.Http;
 using Lucene.Net.Support;
 using Lucene.Net.Util;
-using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.TestHost;
-using Microsoft.Extensions.DependencyInjection;
 using NUnit.Framework;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
 using Directory = Lucene.Net.Store.Directory;
 
-namespace Lucene.Net.Tests.Replicator.Http
+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.
+     */
+
     public class HttpReplicatorTest : ReplicatorTestCase
     {
         private DirectoryInfo clientWorkDir;

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs b/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs
index 63420a6..77517e4 100644
--- a/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs
+++ b/src/Lucene.Net.Tests.Replicator/Http/ReplicationServlet.cs
@@ -1,13 +1,27 @@
-//STATUS: DRAFT - 4.8.0
-
-using System.Threading.Tasks;
 using Lucene.Net.Replicator.AspNetCore;
-using Lucene.Net.Replicator.Http;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AspNetCore.Hosting;
+using System.Threading.Tasks;
 
-namespace Lucene.Net.Tests.Replicator.Http
+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.
+     */
+
     public class ReplicationServlet
     {
         public void Configure(IApplicationBuilder app, IHostingEnvironment env, ReplicationService service)

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
index a6cdfbc..4b93b49 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyReplicationClientTest.cs
@@ -1,29 +1,40 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Lucene.Net.Documents;
+using Lucene.Net.Documents;
 using Lucene.Net.Facet;
 using Lucene.Net.Facet.Taxonomy;
 using Lucene.Net.Facet.Taxonomy.Directory;
 using Lucene.Net.Index;
-using Lucene.Net.Replicator;
 using Lucene.Net.Search;
 using Lucene.Net.Store;
 using Lucene.Net.Support;
 using Lucene.Net.Util;
 using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Threading;
 using Directory = Lucene.Net.Store.Directory;
 
-namespace Lucene.Net.Tests.Replicator
+namespace Lucene.Net.Replicator
 {
+    /*
+     * 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.
+     */
+
     [TestFixture]
     public class IndexAndTaxonomyReplicationClientTest : ReplicatorTestCase
     {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
index 9a54148..9290a5c 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexAndTaxonomyRevisionTest.cs
@@ -1,20 +1,16 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
 using Lucene.Net.Documents;
 using Lucene.Net.Facet;
 using Lucene.Net.Facet.Taxonomy;
 using Lucene.Net.Index;
-using Lucene.Net.Replicator;
 using Lucene.Net.Store;
 using Lucene.Net.Util;
 using NUnit.Framework;
+using System;
+using System.IO;
+using System.Linq;
 using Directory = Lucene.Net.Store.Directory;
 
-namespace Lucene.Net.Tests.Replicator
+namespace Lucene.Net.Replicator
 {
     /*
 	 * Licensed to the Apache Software Foundation (ASF) under one or more

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
index 9d28332..4e816a4 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexReplicationClientTest.cs
@@ -1,22 +1,36 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Globalization;
-using System.IO;
-using System.Threading;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
-using Lucene.Net.Replicator;
 using Lucene.Net.Store;
 using Lucene.Net.Support;
 using Lucene.Net.Util;
 using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Threading;
 using Directory = Lucene.Net.Store.Directory;
 
-namespace Lucene.Net.Tests.Replicator
+namespace Lucene.Net.Replicator
 {
+    /*
+     * 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.
+     */
+
     [TestFixture]
     public class IndexReplicationClientTest : ReplicatorTestCase
     {

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
index ee0108b..22d88be 100644
--- a/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/IndexRevisionTest.cs
@@ -1,17 +1,14 @@
-//STATUS: DRAFT - 4.8.0
-
-using System;
-using System.IO;
-using System.Linq;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
-using Lucene.Net.Replicator;
 using Lucene.Net.Store;
 using Lucene.Net.Util;
 using NUnit.Framework;
+using System;
+using System.IO;
+using System.Linq;
 using Directory = Lucene.Net.Store.Directory;
 
-namespace Lucene.Net.Tests.Replicator
+namespace Lucene.Net.Replicator
 {
     /*
 	 * Licensed to the Apache Software Foundation (ASF) under one or more

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
index d54e2e1..65f37bc 100644
--- a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
@@ -1,20 +1,15 @@
-//STATUS: DRAFT - 4.8.0
-
+using Lucene.Net.Documents;
+using Lucene.Net.Index;
+using Lucene.Net.Util;
+using NUnit.Framework;
 using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Threading;
-using Lucene.Net.Documents;
-using Lucene.Net.Index;
-using Lucene.Net.Replicator;
-using Lucene.Net.Support;
-using Lucene.Net.Support.C5;
-using Lucene.Net.Util;
-using NUnit.Framework;
 using Directory = Lucene.Net.Store.Directory;
 
-namespace Lucene.Net.Tests.Replicator
+namespace Lucene.Net.Replicator
 {
     /*
 	 * Licensed to the Apache Software Foundation (ASF) under one or more

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
index 60adc6e..41cb28d 100644
--- a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
+++ b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
@@ -7,7 +7,7 @@
     <ProjectGuid>{418E9D8E-2369-4B52-8D2F-5A987213999B}</ProjectGuid>
     <OutputType>Library</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>Lucene.Net.Tests.Replicator</RootNamespace>
+    <RootNamespace>Lucene.Net.Replicator</RootNamespace>
     <AssemblyName>Lucene.Net.Tests.Replicator</AssemblyName>
     <TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
@@ -208,6 +208,9 @@
       <Name>Lucene.Net</Name>
     </ProjectReference>
   </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </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.

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
index 58e6ea9..0e35b2c 100644
--- a/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
+++ b/src/Lucene.Net.Tests.Replicator/ReplicatorTestCase.cs
@@ -1,13 +1,11 @@
-//STATUS: PENDING - 4.8.0
-
-using System;
 using Lucene.Net.Replicator.Http;
 using Lucene.Net.Util;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.TestHost;
 using Microsoft.Extensions.DependencyInjection;
+using System;
 
-namespace Lucene.Net.Tests.Replicator
+namespace Lucene.Net.Replicator
 {
     /*
 	 * Licensed to the Apache Software Foundation (ASF) under one or more

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/1e6ce745/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs b/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
index 7c98f88..5f01824 100644
--- a/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/SessionTokenTest.cs
@@ -1,18 +1,14 @@
-//STATUS: DRAFT - 4.8.0
-
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
 using Lucene.Net.Documents;
 using Lucene.Net.Index;
-using Lucene.Net.Replicator;
-using Lucene.Net.Store;
 using Lucene.Net.Support.IO;
 using Lucene.Net.Util;
 using NUnit.Framework;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
 using Directory = Lucene.Net.Store.Directory;
 
-namespace Lucene.Net.Tests.Replicator
+namespace Lucene.Net.Replicator
 {
     /*
 	 * Licensed to the Apache Software Foundation (ASF) under one or more


[16/20] lucenenet git commit: Lucene.Net.Replicator: fixed compiler warnings

Posted by ni...@apache.org.
Lucene.Net.Replicator: fixed compiler warnings


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

Branch: refs/heads/replicator
Commit: f0b3cd50e12421b8df0b23fef67abdd6e9af40a5
Parents: 06ff981
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 05:33:51 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 05:33:51 2017 +0700

----------------------------------------------------------------------
 src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f0b3cd50/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
index 0a73674..3e0e978 100644
--- a/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
+++ b/src/Lucene.Net.Tests.Replicator/LocalReplicatorTest.cs
@@ -167,7 +167,9 @@ namespace Lucene.Net.Replicator
                 replicator.ObtainFile(res.Id, res.SourceFiles.Keys.First(), "madeUpFile");
                 fail("should have failed obtaining an unrecognized file");
             }
+#pragma warning disable 168
             catch (FileNotFoundException e)
+#pragma warning restore 168
             {
                 // expected
             }


[11/20] lucenenet git commit: Merge branch 'master' into Lucene.Net.Replicator

Posted by ni...@apache.org.
Merge branch 'master' into Lucene.Net.Replicator


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

Branch: refs/heads/replicator
Commit: 3b0e132bc3c279546c0b208433f86be8ac6e8549
Parents: 73f6a4e 29cbc13
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 02:42:40 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 02:42:40 2017 +0700

----------------------------------------------------------------------
 CONTRIBUTING.md                                 |    7 +-
 Lucene.Net.Portable.sln                         |   40 +
 Lucene.Net.sln                                  |  103 +
 README.md                                       |    9 +-
 .../CharFilter/MappingCharFilterFactory.cs      |    2 +-
 .../Analysis/ICU/ICUFoldingFilter.cs            |   32 +
 .../Analysis/ICU/ICUFoldingFilterFactory.cs     |   31 +
 .../Analysis/ICU/ICUNormalizer2CharFilter.cs    |  235 ++
 .../ICU/ICUNormalizer2CharFilterFactory.cs      |   60 +
 .../Analysis/ICU/ICUNormalizer2Filter.cs        |   60 +
 .../Analysis/ICU/ICUNormalizer2FilterFactory.cs |   59 +
 .../Analysis/ICU/ICUTransformFilter.cs          |  152 +
 .../Analysis/ICU/ICUTransformFilterFactory.cs   |   38 +
 .../ICU/Segmentation/BreakIteratorWrapper.cs    |  166 +
 .../ICU/Segmentation/CharArrayIterator.cs       |  134 +
 .../ICU/Segmentation/CompositeBreakIterator.cs  |  132 +
 .../Segmentation/DefaultICUTokenizerConfig.cs   |  127 +
 .../Analysis/ICU/Segmentation/ICUTokenizer.cs   |  229 ++
 .../ICU/Segmentation/ICUTokenizerConfig.cs      |   33 +
 .../ICU/Segmentation/ICUTokenizerFactory.cs     |  139 +
 .../Analysis/ICU/Segmentation/ScriptIterator.cs |  206 ++
 .../ICU/TokenAttributes/ScriptAttribute.cs      |   42 +
 .../ICU/TokenAttributes/ScriptAttributeImpl.cs  |   80 +
 .../Collation/ICUCollationAttributeFactory.cs   |   75 +
 .../Collation/ICUCollationDocValuesField.cs     |   65 +
 .../Collation/ICUCollationKeyAnalyzer.cs        |   96 +
 .../Collation/ICUCollationKeyFilter.cs          |   89 +
 .../Collation/ICUCollationKeyFilterFactory.cs   |  245 ++
 .../ICUCollatedTermAttributeImpl.cs             |   42 +
 .../Dict/BinaryDictionary.cs                    |  411 +++
 .../Dict/CharacterDefinition.cs                 |  124 +
 .../Dict/CharacterDefinition.dat                |  Bin 0 -> 65568 bytes
 .../Dict/ConnectionCosts.cs                     |   90 +
 .../Dict/ConnectionCosts.dat                    |  Bin 0 -> 2624540 bytes
 .../Dict/Dictionary.cs                          |  106 +
 .../Dict/TokenInfoDictionary$buffer.dat         |  Bin 0 -> 4337216 bytes
 .../Dict/TokenInfoDictionary$fst.dat            |  Bin 0 -> 1716198 bytes
 .../Dict/TokenInfoDictionary$posDict.dat        |  Bin 0 -> 54870 bytes
 .../Dict/TokenInfoDictionary$targetMap.dat      |  Bin 0 -> 392165 bytes
 .../Dict/TokenInfoDictionary.cs                 |   72 +
 .../Dict/TokenInfoFST.cs                        |  118 +
 .../Dict/UnknownDictionary$buffer.dat           |  Bin 0 -> 311 bytes
 .../Dict/UnknownDictionary$posDict.dat          |  Bin 0 -> 4111 bytes
 .../Dict/UnknownDictionary$targetMap.dat        |  Bin 0 -> 69 bytes
 .../Dict/UnknownDictionary.cs                   |  100 +
 .../Dict/UserDictionary.cs                      |  300 ++
 .../GraphvizFormatter.cs                        |  197 ++
 .../JapaneseAnalyzer.cs                         |  103 +
 .../JapaneseBaseFormFilter.cs                   |   65 +
 .../JapaneseBaseFormFilterFactory.cs            |   52 +
 .../JapaneseIterationMarkCharFilter.cs          |  500 +++
 .../JapaneseIterationMarkCharFilterFactory.cs   |   66 +
 .../JapaneseKatakanaStemFilter.cs               |  111 +
 .../JapaneseKatakanaStemFilterFactory.cs        |   61 +
 .../JapanesePartOfSpeechStopFilter.cs           |   61 +
 .../JapanesePartOfSpeechStopFilterFactory.cs    |   85 +
 .../JapaneseReadingFormFilter.cs                |   89 +
 .../JapaneseReadingFormFilterFactory.cs         |   57 +
 .../JapaneseTokenizer.cs                        | 1489 +++++++++
 .../JapaneseTokenizerFactory.cs                 |  109 +
 .../Lucene.Net.Analysis.Kuromoji.csproj         |  118 +
 .../Lucene.Net.Analysis.Kuromoji.project.json   |    8 +
 .../Lucene.Net.Analysis.Kuromoji.xproj          |   38 +
 .../Properties/AssemblyInfo.cs                  |   46 +
 src/Lucene.Net.Analysis.Kuromoji/Token.cs       |  194 ++
 .../TokenAttributes/BaseFormAttribute.cs        |   33 +
 .../TokenAttributes/BaseFormAttributeImpl.cs    |   55 +
 .../TokenAttributes/InflectionAttribute.cs      |   34 +
 .../TokenAttributes/InflectionAttributeImpl.cs  |   68 +
 .../TokenAttributes/PartOfSpeechAttribute.cs    |   30 +
 .../PartOfSpeechAttributeImpl.cs                |   59 +
 .../TokenAttributes/ReadingAttribute.cs         |   34 +
 .../TokenAttributes/ReadingAttributeImpl.cs     |   68 +
 .../Tools/BinaryDictionaryWriter.cs             |  377 +++
 .../Tools/CharacterDefinitionWriter.cs          |   96 +
 .../Tools/ConnectionCostsBuilder.cs             |   68 +
 .../Tools/ConnectionCostsWriter.cs              |   79 +
 .../Tools/DictionaryBuilder.cs                  |  101 +
 .../Tools/TokenInfoDictionaryBuilder.cs         |  230 ++
 .../Tools/TokenInfoDictionaryWriter.cs          |   51 +
 .../Tools/UnknownDictionaryBuilder.cs           |  146 +
 .../Tools/UnknownDictionaryWriter.cs            |   66 +
 .../Util/CSVUtil.cs                             |  124 +
 .../Util/ToStringUtil.cs                        | 1401 +++++++++
 src/Lucene.Net.Analysis.Kuromoji/project.json   |   60 +
 src/Lucene.Net.Analysis.Kuromoji/stoptags.txt   |  420 +++
 src/Lucene.Net.Analysis.Kuromoji/stopwords.txt  |  127 +
 .../Properties/AssemblyInfo.cs                  |    3 +
 src/Lucene.Net.Analysis.SmartCn/project.json    |    2 +-
 src/Lucene.Net.Benchmark/ByTask/Benchmark.cs    |  170 +
 .../ByTask/Feeds/AbstractQueryMaker.cs          |   85 +
 .../ByTask/Feeds/ContentItemsSource.cs          |  227 ++
 .../ByTask/Feeds/ContentSource.cs               |   38 +
 .../ByTask/Feeds/DemoHTMLParser.cs              |  259 ++
 .../ByTask/Feeds/DirContentSource.cs            |  259 ++
 .../ByTask/Feeds/DocData.cs                     |   73 +
 .../ByTask/Feeds/DocMaker.cs                    |  511 +++
 .../ByTask/Feeds/EnwikiContentSource.cs         |  395 +++
 .../ByTask/Feeds/EnwikiQueryMaker.cs            |  146 +
 .../ByTask/Feeds/FacetSource.cs                 |   47 +
 .../ByTask/Feeds/FileBasedQueryMaker.cs         |  121 +
 .../ByTask/Feeds/GeonamesLineParser.cs          |   53 +
 .../ByTask/Feeds/HTMLParser.cs                  |   42 +
 .../ByTask/Feeds/LineDocSource.cs               |  328 ++
 .../ByTask/Feeds/LongToEnglishContentSource.cs  |   72 +
 .../ByTask/Feeds/LongToEnglishQueryMaker.cs     |   89 +
 .../ByTask/Feeds/NoMoreDataException.cs         |   50 +
 .../ByTask/Feeds/QueryMaker.cs                  |   48 +
 .../ByTask/Feeds/RandomFacetSource.cs           |  109 +
 .../ByTask/Feeds/ReutersContentSource.cs        |  140 +
 .../ByTask/Feeds/ReutersQueryMaker.cs           |  126 +
 .../ByTask/Feeds/SimpleQueryMaker.cs            |   70 +
 .../Feeds/SimpleSloppyPhraseQueryMaker.cs       |   88 +
 .../ByTask/Feeds/SingleDocSource.cs             |   77 +
 .../ByTask/Feeds/SortableSingleDocSource.cs     |  114 +
 .../ByTask/Feeds/SpatialDocMaker.cs             |  249 ++
 .../ByTask/Feeds/SpatialFileQueryMaker.cs       |  131 +
 .../ByTask/Feeds/TrecContentSource.cs           |  350 +++
 .../ByTask/Feeds/TrecDocParser.cs               |  159 +
 .../ByTask/Feeds/TrecFBISParser.cs              |   68 +
 .../ByTask/Feeds/TrecFR94Parser.cs              |   69 +
 .../ByTask/Feeds/TrecFTParser.cs                |   58 +
 .../ByTask/Feeds/TrecGov2Parser.cs              |   57 +
 .../ByTask/Feeds/TrecLATimesParser.cs           |   75 +
 .../ByTask/Feeds/TrecParserByPath.cs            |   34 +
 src/Lucene.Net.Benchmark/ByTask/PerfRunData.cs  |  490 +++
 .../ByTask/Programmatic/Sample.cs               |   90 +
 src/Lucene.Net.Benchmark/ByTask/Stats/Points.cs |  108 +
 src/Lucene.Net.Benchmark/ByTask/Stats/Report.cs |   70 +
 .../ByTask/Stats/TaskStats.cs                   |  237 ++
 .../ByTask/Tasks/AddDocTask.cs                  |   93 +
 .../ByTask/Tasks/AddFacetedDocTask.cs           |   95 +
 .../ByTask/Tasks/AddIndexesTask.cs              |  104 +
 .../ByTask/Tasks/AnalyzerFactoryTask.cs         |  581 ++++
 .../ByTask/Tasks/BenchmarkHighlighter.cs        |   32 +
 .../ByTask/Tasks/ClearStatsTask.cs              |   44 +
 .../ByTask/Tasks/CloseIndexTask.cs              |   67 +
 .../ByTask/Tasks/CloseReaderTask.cs             |   49 +
 .../ByTask/Tasks/CloseTaxonomyIndexTask.cs      |   42 +
 .../ByTask/Tasks/CloseTaxonomyReaderTask.cs     |   47 +
 .../ByTask/Tasks/CommitIndexTask.cs             |   62 +
 .../ByTask/Tasks/CommitTaxonomyIndexTask.cs     |   48 +
 .../ByTask/Tasks/ConsumeContentSourceTask.cs    |   48 +
 .../ByTask/Tasks/CreateIndexTask.cs             |  239 ++
 .../ByTask/Tasks/CreateTaxonomyIndexTask.cs     |   42 +
 .../ByTask/Tasks/ForceMergeTask.cs              |   61 +
 .../ByTask/Tasks/NearRealtimeReaderTask.cs      |  132 +
 .../ByTask/Tasks/NewAnalyzerTask.cs             |  189 ++
 .../ByTask/Tasks/NewCollationAnalyzerTask.cs    |  149 +
 .../ByTask/Tasks/NewLocaleTask.cs               |   97 +
 .../ByTask/Tasks/NewRoundTask.cs                |   44 +
 .../ByTask/Tasks/OpenIndexTask.cs               |   88 +
 .../ByTask/Tasks/OpenReaderTask.cs              |  100 +
 .../ByTask/Tasks/OpenTaxonomyIndexTask.cs       |   41 +
 .../ByTask/Tasks/OpenTaxonomyReaderTask.cs      |   44 +
 .../ByTask/Tasks/PerfTask.cs                    |  380 +++
 .../ByTask/Tasks/PrintReaderTask.cs             |   60 +
 .../ByTask/Tasks/ReadTask.cs                    |  339 ++
 .../ByTask/Tasks/ReadTokensTask.cs              |  160 +
 .../ByTask/Tasks/ReopenReaderTask.cs            |   45 +
 .../ByTask/Tasks/RepAllTask.cs                  |   83 +
 .../ByTask/Tasks/RepSelectByPrefTask.cs         |   81 +
 .../ByTask/Tasks/RepSumByNameRoundTask.cs       |   83 +
 .../ByTask/Tasks/RepSumByNameTask.cs            |   81 +
 .../ByTask/Tasks/RepSumByPrefRoundTask.cs       |   79 +
 .../ByTask/Tasks/RepSumByPrefTask.cs            |   91 +
 .../ByTask/Tasks/ReportTask.cs                  |  189 ++
 .../ByTask/Tasks/ResetInputsTask.cs             |   43 +
 .../ByTask/Tasks/ResetSystemEraseTask.cs        |   42 +
 .../ByTask/Tasks/ResetSystemSoftTask.cs         |   41 +
 .../ByTask/Tasks/RollbackIndexTask.cs           |   52 +
 .../ByTask/Tasks/SearchTask.cs                  |   60 +
 .../ByTask/Tasks/SearchTravRetHighlightTask.cs  |  188 ++
 .../Tasks/SearchTravRetLoadFieldSelectorTask.cs |   85 +
 .../ByTask/Tasks/SearchTravRetTask.cs           |   44 +
 .../Tasks/SearchTravRetVectorHighlightTask.cs   |  191 ++
 .../ByTask/Tasks/SearchTravTask.cs              |   87 +
 .../ByTask/Tasks/SearchWithCollectorTask.cs     |   99 +
 .../ByTask/Tasks/SearchWithSortTask.cs          |  157 +
 .../ByTask/Tasks/SetPropTask.cs                 |   71 +
 .../ByTask/Tasks/TaskSequence.cs                |  664 ++++
 .../ByTask/Tasks/UpdateDocTask.cs               |   99 +
 .../ByTask/Tasks/WaitForMergesTask.cs           |   36 +
 .../ByTask/Tasks/WaitTask.cs                    |   89 +
 .../ByTask/Tasks/WarmTask.cs                    |   64 +
 .../ByTask/Tasks/WriteEnwikiLineDocTask.cs      |   72 +
 .../ByTask/Tasks/WriteLineDocTask.cs            |  238 ++
 .../ByTask/Utils/Algorithm.cs                   |  459 +++
 .../ByTask/Utils/AnalyzerFactory.cs             |  156 +
 src/Lucene.Net.Benchmark/ByTask/Utils/Config.cs |  559 ++++
 .../ByTask/Utils/FileUtils.cs                   |   46 +
 src/Lucene.Net.Benchmark/ByTask/Utils/Format.cs |  109 +
 .../ByTask/Utils/StreamUtils.cs                 |  132 +
 src/Lucene.Net.Benchmark/Constants.cs           |   33 +
 .../Lucene.Net.Benchmark.csproj                 |  275 ++
 .../Lucene.Net.Benchmark.project.json           |   13 +
 .../Lucene.Net.Benchmark.xproj                  |   39 +
 .../Properties/AssemblyInfo.cs                  |   30 +
 src/Lucene.Net.Benchmark/Quality/Judge.cs       |   55 +
 .../Quality/QualityBenchmark.cs                 |  159 +
 .../Quality/QualityQuery.cs                     |  107 +
 .../Quality/QualityQueryParser.cs               |   35 +
 .../Quality/QualityStats.cs                     |  339 ++
 .../Quality/Trec/QueryDriver.cs                 |   93 +
 .../Quality/Trec/Trec1MQReader.cs               |   92 +
 .../Quality/Trec/TrecJudge.cs                   |  186 ++
 .../Quality/Trec/TrecTopicsReader.cs            |  154 +
 .../Quality/Utils/DocNameExtractor.cs           |   89 +
 .../Quality/Utils/QualityQueriesFinder.cs       |  152 +
 .../Quality/Utils/SimpleQQParser.cs             |   76 +
 .../Quality/Utils/SubmissionReport.cs           |   98 +
 .../Support/EnglishNumberFormatExtensions.cs    |  186 ++
 .../Support/Sax/Attributes.cs                   |  219 ++
 .../Support/Sax/ContentHandler.cs               |  364 +++
 .../Support/Sax/DTDHandler.cs                   |  100 +
 .../Support/Sax/EntityResolver.cs               |  109 +
 .../Support/Sax/ErrorHandler.cs                 |  122 +
 .../Support/Sax/Ext/Attributes2.cs              |  108 +
 .../Support/Sax/Ext/Attributes2Impl.cs          |  277 ++
 .../Support/Sax/Ext/DeclHandler.cs              |  131 +
 .../Support/Sax/Ext/DefaultHandler2.cs          |  112 +
 .../Support/Sax/Ext/EntityResolver2.cs          |  178 ++
 .../Support/Sax/Ext/LexicalHandler.cs           |  180 ++
 .../Support/Sax/Ext/Locator2.cs                 |   64 +
 .../Support/Sax/Ext/Locator2Impl.cs             |   76 +
 .../Support/Sax/Helpers/AttributesImpl.cs       |  615 ++++
 .../Support/Sax/Helpers/DefaultHandler.cs       |  389 +++
 .../Support/Sax/Helpers/LocatorImpl.cs          |  131 +
 .../Support/Sax/Helpers/NamespaceSupport.cs     |  841 +++++
 .../Support/Sax/Helpers/XMLFilterImpl.cs        |  587 ++++
 .../Support/Sax/InputSource.cs                  |  242 ++
 src/Lucene.Net.Benchmark/Support/Sax/Locator.cs |  125 +
 .../Support/Sax/SAXException.cs                 |  165 +
 .../Support/Sax/SAXNotRecognizedException.cs    |   66 +
 .../Support/Sax/SAXNotSupportedException.cs     |   67 +
 .../Support/Sax/SAXParseException.cs            |  269 ++
 .../Support/Sax/XMLFilter.cs                    |   41 +
 .../Support/Sax/XMLReader.cs                    |  305 ++
 .../Support/StringExtensions.cs                 |   14 +
 .../Support/TagSoup/AutoDetector.cs             |   41 +
 .../Support/TagSoup/Element.cs                  |  215 ++
 .../Support/TagSoup/ElementType.cs              |  270 ++
 .../Support/TagSoup/HTMLScanner.cs              |  745 +++++
 .../Support/TagSoup/HTMLSchema.Generated.cs     | 2910 ++++++++++++++++++
 .../Support/TagSoup/HTMLSchema.tt               |   72 +
 .../Support/TagSoup/PYXScanner.cs               |  138 +
 .../Support/TagSoup/PYXWriter.cs                |  286 ++
 .../Support/TagSoup/Parser.cs                   | 1484 +++++++++
 .../Support/TagSoup/ScanHandler.cs              |  105 +
 .../Support/TagSoup/Scanner.cs                  |   53 +
 .../Support/TagSoup/Schema.cs                   |  159 +
 .../Support/TagSoup/XMLReader.cs                | 1567 ++++++++++
 .../Support/TagSoup/definitions/html.stml       |  249 ++
 .../Support/TagSoup/definitions/html.tssl       | 2762 +++++++++++++++++
 .../Support/TagSoup/stml/stml.rnc               |   49 +
 .../Support/TagSoup/stml/stml.xslt              |  150 +
 .../Support/TagSoup/tssl/tssl-models.xslt       |   47 +
 .../Support/TagSoup/tssl/tssl-validate.xslt     |   40 +
 .../Support/TagSoup/tssl/tssl.rnc               |   75 +
 .../Support/TagSoup/tssl/tssl.xslt              |  220 ++
 .../Utils/ExtractReuters.cs                     |  167 +
 .../Utils/ExtractWikipedia.cs                   |  178 ++
 src/Lucene.Net.Benchmark/project.json           |   54 +
 .../Utils/DatasetSplitter.cs                    |   28 +-
 .../SimpleText/SimpleTextStoredFieldsWriter.cs  |   89 +-
 src/Lucene.Net.Facet/FacetsConfig.cs            |    8 +-
 .../Taxonomy/FloatAssociationFacetField.cs      |    4 +-
 .../PostingsHighlight/PostingsHighlighter.cs    |    2 +-
 .../VectorHighlight/BaseFragmentsBuilder.cs     |    2 +-
 .../VectorHighlight/FieldTermStack.cs           |    2 +-
 src/Lucene.Net.ICU/Lucene.Net.ICU.csproj        |   18 +
 src/Lucene.Net.ICU/project.json                 |    9 +-
 src/Lucene.Net.Misc/Document/LazyDocument.cs    |  163 +-
 src/Lucene.Net.Spatial/project.json             |    4 +-
 .../Suggest/DocumentDictionary.cs               |    4 +-
 .../Analysis/BaseTokenStreamTestCase.cs         |    2 +-
 .../Analysis/CollationTestBase.cs               |   12 +-
 .../Lucene3x/PreFlexRWStoredFieldsWriter.cs     |  123 +-
 .../Index/BaseStoredFieldsFormatTestCase.cs     |   12 +-
 src/Lucene.Net.TestFramework/Index/DocHelper.cs |   14 +-
 .../Lucene.Net.TestFramework.csproj             |    1 -
 .../Support/ApiScanTestBase.cs                  |    4 +-
 .../Support/SystemProperties.cs                 |  173 --
 .../Util/LuceneTestCase.cs                      |    2 +
 src/Lucene.Net.TestFramework/Util/TestUtil.cs   |   36 +-
 src/Lucene.Net.TestFramework/project.json       |    1 +
 .../Icu/Segmentation/TestCharArrayIterator.cs   |  110 +
 .../Analysis/Icu/TestICUNormalizer2Filter.cs    |   92 +
 .../Icu/TestICUNormalizer2FilterFactory.cs      |   45 +
 .../Collation/TestICUCollationDocValuesField.cs |  121 +
 .../Collation/TestICUCollationKeyAnalyzer.cs    |  101 +
 .../Collation/TestICUCollationKeyFilter.cs      |  101 +
 .../TestICUCollationKeyFilterFactory.cs         |  331 ++
 .../Dict/TestTokenInfoDictionary.cs             |  114 +
 .../Dict/UserDictionaryTest.cs                  |   90 +
 .../Lucene.Net.Tests.Analysis.Kuromoji.csproj   |  108 +
 ...ene.Net.Tests.Analysis.Kuromoji.project.json |   11 +
 .../Lucene.Net.Tests.Analysis.Kuromoji.xproj    |   41 +
 .../Properties/AssemblyInfo.cs                  |   38 +
 .../StringMockResourceLoader.cs                 |   67 +
 .../Support/TestApiConsistency.cs               |  150 +
 .../Support/TestExceptionSerialization.cs       |   54 +
 .../TestExtendedMode.cs                         |   82 +
 .../TestJapaneseAnalyzer.cs                     |  229 ++
 .../TestJapaneseBaseFormFilter.cs               |   84 +
 .../TestJapaneseBaseFormFilterFactory.cs        |   60 +
 .../TestJapaneseIterationMarkCharFilter.cs      |  241 ++
 ...estJapaneseIterationMarkCharFilterFactory.cs |  108 +
 .../TestJapaneseKatakanaStemFilter.cs           |  100 +
 .../TestJapaneseKatakanaStemFilterFactory.cs    |   62 +
 ...TestJapanesePartOfSpeechStopFilterFactory.cs |   70 +
 .../TestJapaneseReadingFormFilter.cs            |  109 +
 .../TestJapaneseReadingFormFilterFactory.cs     |   59 +
 .../TestJapaneseTokenizer.cs                    |  846 +++++
 .../TestJapaneseTokenizerFactory.cs             |  134 +
 .../TestSearchMode.cs                           |   92 +
 .../Tools/TestBuildDictionary.cs                |   59 +
 .../Tools/UnknownDictionaryTest.cs              |   93 +
 .../Tools/custom-dictionary-input.zip           |  Bin 0 -> 5279887 bytes
 .../Util/TestToStringUtil.cs                    |  121 +
 .../bocchan.utf-8                               |    1 +
 .../project.json                                |   44 +
 .../search-segmentation-tests.txt               |  142 +
 .../userdict.txt                                |   10 +
 .../BenchmarkTestCase.cs                        |  129 +
 .../ByTask/Feeds/DocMakerTest.cs                |  193 ++
 .../ByTask/Feeds/EnwikiContentSourceTest.cs     |  193 ++
 .../ByTask/Feeds/LineDocSourceTest.cs           |  271 ++
 .../ByTask/Feeds/TestHtmlParser.cs              |  164 +
 .../ByTask/Feeds/TrecContentSourceTest.cs       |  431 +++
 .../ByTask/Feeds/trecdocs.zip                   |  Bin 0 -> 2514 bytes
 .../ByTask/Tasks/AddIndexesTaskTest.cs          |  153 +
 .../ByTask/Tasks/Alt/AltPackageTaskTest.cs      |   68 +
 .../ByTask/Tasks/Alt/AltTestTask.cs             |   35 +
 .../ByTask/Tasks/CommitIndexTaskTest.cs         |   63 +
 .../ByTask/Tasks/CountingHighlighterTestTask.cs |   85 +
 .../ByTask/Tasks/CountingSearchTestTask.cs      |   65 +
 .../ByTask/Tasks/CreateIndexTaskTest.cs         |  129 +
 .../ByTask/Tasks/PerfTaskTest.cs                |   81 +
 .../ByTask/Tasks/SearchWithSortTaskTest.cs      |   35 +
 .../ByTask/Tasks/WriteEnwikiLineDocTaskTest.cs  |  121 +
 .../ByTask/Tasks/WriteLineDocTaskTest.cs        |  436 +++
 .../ByTask/TestPerfTasksLogic.cs                | 1177 +++++++
 .../ByTask/TestPerfTasksParse.cs                |  178 ++
 .../ByTask/Utils/StreamUtilsTest.cs             |  149 +
 .../ByTask/Utils/TestConfig.cs                  |   37 +
 src/Lucene.Net.Tests.Benchmark/ByTask/conf.zip  |  Bin 0 -> 40878 bytes
 .../ByTask/reuters.first20.lines.txt            |   20 +
 .../test-mapping-ISOLatin1Accent-partial.txt    |   30 +
 .../Conf/ConfLoader.cs                          |   28 +
 .../Lucene.Net.Tests.Benchmark.csproj           |  130 +
 .../Lucene.Net.Tests.Benchmark.project.json     |   13 +
 .../Lucene.Net.Tests.Benchmark.xproj            |   42 +
 .../Properties/AssemblyInfo.cs                  |   21 +
 .../Quality/TestQualityRun.cs                   |  210 ++
 .../Quality/reuters.578.lines.txt.bz2           |  Bin 0 -> 208314 bytes
 .../Quality/trecQRels.txt                       |  723 +++++
 .../Quality/trecTopics.txt                      |  287 ++
 .../Support/TestApiConsistency.cs               |  150 +
 .../TestEnglishNumberFormatExtensions.cs        |   38 +
 .../Support/TestExceptionSerialization.cs       |   54 +
 src/Lucene.Net.Tests.Benchmark/project.json     |   56 +
 .../Highlight/HighlighterTest.cs                |    3 +-
 .../Lucene.Net.Tests.ICU.csproj                 |   12 +
 src/Lucene.Net.Tests.ICU/project.json           |    9 +
 src/Lucene.Net.Tests.Join/TestBlockJoin.cs      |    2 +-
 .../Index/Memory/MemoryIndexTest.cs             |    2 +-
 src/Lucene.Net.Tests.Spatial/SpatialExample.cs  |    2 +-
 src/Lucene.Net.Tests.Spatial/project.json       |    2 +-
 .../Suggest/DocumentDictionaryTest.cs           |    8 +-
 .../DocumentValueSourceDictionaryTest.cs        |   22 +-
 src/Lucene.Net.Tests/Document/TestDocument.cs   |    4 +-
 src/Lucene.Net.Tests/Document/TestField.cs      |  141 +-
 .../Index/TestBagOfPositions.cs                 |    2 +-
 .../Index/TestDocumentWriter.cs                 |    4 +-
 src/Lucene.Net.Tests/Index/TestFieldInfos.cs    |    2 +-
 src/Lucene.Net.Tests/Index/TestFieldsReader.cs  |   20 +-
 .../Index/TestIndexWriterExceptions.cs          |   67 +-
 .../Index/TestIndexableField.cs                 |   63 +-
 src/Lucene.Net.Tests/Index/TestSegmentReader.cs |    4 +-
 src/Lucene.Net.Tests/Lucene.Net.Tests.csproj    |    4 +
 .../Search/TestLiveFieldValues.cs               |    2 +-
 .../Search/TestNumericRangeQuery32.cs           |   24 +-
 .../Search/TestNumericRangeQuery64.cs           |   24 +-
 .../Support/IO/TestStreamTokenizer.cs           |  514 ++++
 .../Support/TestDictionaryExtensions.cs         |  411 +++
 .../Support/TestStringBuilderExtensions.cs      |  292 +-
 .../Support/TestStringTokenizer.cs              |  353 +++
 .../Support/hyts_PropertiesTest.properties      |   29 +
 src/Lucene.Net.Tests/project.json               |    3 +-
 src/Lucene.Net/Analysis/NumericTokenStream.cs   |    4 +-
 .../CompressingStoredFieldsWriter.cs            |  137 +-
 .../Lucene40/Lucene40StoredFieldsWriter.cs      |   78 +-
 src/Lucene.Net/Codecs/StoredFieldsWriter.cs     |    4 +-
 src/Lucene.Net/Document/BinaryDocValuesField.cs |    2 +-
 src/Lucene.Net/Document/DoubleField.cs          |   10 +-
 src/Lucene.Net/Document/Field.cs                |  470 ++-
 src/Lucene.Net/Document/FloatField.cs           |   10 +-
 src/Lucene.Net/Document/IntField.cs             |   10 +-
 src/Lucene.Net/Document/LongField.cs            |   10 +-
 .../Document/NumericDocValuesField.cs           |    2 +-
 src/Lucene.Net/Document/SortedDocValuesField.cs |    2 +-
 .../Document/SortedSetDocValuesField.cs         |    2 +-
 src/Lucene.Net/Document/StoredField.cs          |    8 +-
 src/Lucene.Net/Index/DocFieldProcessor.cs       |    4 +-
 src/Lucene.Net/Index/DocInverterPerField.cs     |    2 +-
 src/Lucene.Net/Index/DocValuesProcessor.cs      |    9 +-
 .../Index/FreqProxTermsWriterPerField.cs        |    2 +-
 src/Lucene.Net/Index/IndexableField.cs          |  119 +-
 src/Lucene.Net/Index/StoredFieldsProcessor.cs   |    2 +-
 .../Index/TermVectorsConsumerPerField.cs        |   26 +-
 src/Lucene.Net/Lucene.Net.csproj                |    9 +-
 .../Search/SearcherLifetimeManager.cs           |   18 +-
 src/Lucene.Net/Store/NativeFSLockFactory.cs     |  236 +-
 src/Lucene.Net/Support/AssemblyUtils.cs         |  138 +
 src/Lucene.Net/Support/Character.cs             |   76 +
 src/Lucene.Net/Support/Collections.cs           |    9 +
 src/Lucene.Net/Support/DictionaryExtensions.cs  |  409 ++-
 .../Support/Document/DocumentExtensions.cs      |   17 +
 src/Lucene.Net/Support/Document/Field.cs        |  412 +++
 .../Document/IndexableFieldExtensions.cs        |   99 +
 src/Lucene.Net/Support/IO/FileSupport.cs        |    5 +-
 src/Lucene.Net/Support/IO/StreamTokenizer.cs    |  738 +++++
 src/Lucene.Net/Support/OS.cs                    |   74 -
 .../Support/StringBuilderExtensions.cs          |   70 +
 src/Lucene.Net/Support/StringExtensions.cs      |   30 +
 src/Lucene.Net/Support/StringTokenizer.cs       |  438 +--
 src/Lucene.Net/Support/SystemConsole.cs         |  411 +++
 src/Lucene.Net/Support/SystemProperties.cs      |  175 ++
 src/Lucene.Net/Support/Time.cs                  |    9 +
 src/Lucene.Net/Util/Constants.cs                |  212 +-
 src/Lucene.Net/Util/PrintStreamInfoStream.cs    |   12 +-
 src/Lucene.Net/Util/SPIClassIterator.cs         |  115 +-
 src/Lucene.Net/project.json                     |    3 +-
 ...nalysisKuromojiBuildDictionaryCommandTest.cs |  104 +
 .../Commands/Benchmark/BenchmarkCommandTest.cs  |   50 +
 .../BenchmarkExtractReutersCommandTest.cs       |   61 +
 .../BenchmarkExtractWikipediaCommandTest.cs     |   66 +
 .../BenchmarkFindQualityQueriesCommandTest.cs   |   65 +
 .../Benchmark/BenchmarkRunCommandTest.cs        |   60 +
 .../BenchmarkRunTrecEvalCommandTest.cs          |   63 +
 .../lucene-cli/Resources/Strings.Designer.cs    |  246 ++
 src/tools/lucene-cli/Resources/Strings.resx     |   92 +
 src/tools/lucene-cli/commands/RootCommand.cs    |    4 +-
 .../commands/analysis/AnalysisCommand.cs        |    2 +-
 .../AnalysisKuromojiBuildDictionaryCommand.cs   |   96 +
 .../commands/benchmark/BenchmarkCommand.cs      |   51 +
 .../BenchmarkExtractReutersCommand.cs           |   52 +
 .../BenchmarkExtractWikipediaCommand.cs         |   72 +
 .../BenchmarkFindQualityQueriesCommand.cs       |   51 +
 .../BenchmarkRunTrecEvalCommand.cs              |   78 +
 .../benchmark-run/BenchmarkRunCommand.cs        |   50 +
 .../benchmark-sample/BenchmarkSampleCommand.cs  |   53 +
 .../commands/demo/DemoConfiguration.cs          |    1 +
 src/tools/lucene-cli/docs/analysis/index.md     |    1 +
 .../docs/analysis/kuromoji-build-dictionary.md  |   60 +
 .../docs/benchmark/extract-reuters.md           |   31 +
 .../docs/benchmark/extract-wikipedia.md         |   35 +
 .../docs/benchmark/find-quality-queries.md      |   27 +
 src/tools/lucene-cli/docs/benchmark/index.md    |   14 +
 .../lucene-cli/docs/benchmark/run-trec-eval.md  |   51 +
 src/tools/lucene-cli/docs/benchmark/run.md      |   31 +
 src/tools/lucene-cli/docs/benchmark/sample.md   |   29 +
 src/tools/lucene-cli/project.json               |    5 +-
 464 files changed, 63454 insertions(+), 1276 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/3b0e132b/Lucene.Net.sln
----------------------------------------------------------------------
diff --cc Lucene.Net.sln
index 73e8562,08a00a0..470a270
--- a/Lucene.Net.sln
+++ b/Lucene.Net.sln
@@@ -106,11 -106,13 +106,18 @@@ Project("{FAE04EC0-301F-11D3-BF4B-00C04
  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}"
+ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Analysis.Kuromoji", "src\Lucene.Net.Analysis.Kuromoji\Lucene.Net.Analysis.Kuromoji.csproj", "{8408625A-2508-46D5-8519-045183C43724}"
+ EndProject
+ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Analysis.Kuromoji", "src\Lucene.Net.Tests.Analysis.Kuromoji\Lucene.Net.Tests.Analysis.Kuromoji.csproj", "{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}"
+ EndProject
+ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Benchmark", "src\Lucene.Net.Benchmark\Lucene.Net.Benchmark.csproj", "{EDC77CB4-597F-4818-8C83-3C006D12C384}"
+ EndProject
+ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Benchmark", "src\Lucene.Net.Tests.Benchmark\Lucene.Net.Tests.Benchmark.csproj", "{9257F543-44E2-4DB6-8B27-A8A354C13E5B}"
  EndProject
  Global
  	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@@ -1065,78 -1067,102 +1072,174 @@@
  		{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
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug|x86.ActiveCfg = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug|x86.Build.0 = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug35|x86.ActiveCfg = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Debug35|x86.Build.0 = Debug|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release|Any CPU.Build.0 = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release|x86.ActiveCfg = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release|x86.Build.0 = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release35|Any CPU.Build.0 = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release35|x86.ActiveCfg = Release|Any CPU
+ 		{8408625A-2508-46D5-8519-045183C43724}.Release35|x86.Build.0 = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug|x86.ActiveCfg = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug|x86.Build.0 = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug35|x86.ActiveCfg = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Debug35|x86.Build.0 = Debug|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release|Any CPU.Build.0 = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release|x86.ActiveCfg = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release|x86.Build.0 = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release35|Any CPU.Build.0 = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release35|x86.ActiveCfg = Release|Any CPU
+ 		{34A2BCE8-1351-43BD-A365-F50E7C0B2C49}.Release35|x86.Build.0 = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug|x86.ActiveCfg = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug|x86.Build.0 = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug35|x86.ActiveCfg = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Debug35|x86.Build.0 = Debug|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release|Any CPU.Build.0 = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release|x86.ActiveCfg = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release|x86.Build.0 = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release35|Any CPU.Build.0 = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release35|x86.ActiveCfg = Release|Any CPU
+ 		{EDC77CB4-597F-4818-8C83-3C006D12C384}.Release35|x86.Build.0 = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug|x86.Build.0 = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug35|Any CPU.ActiveCfg = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug35|Any CPU.Build.0 = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug35|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug35|Mixed Platforms.Build.0 = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug35|x86.ActiveCfg = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Debug35|x86.Build.0 = Debug|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release|Any CPU.Build.0 = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release|x86.ActiveCfg = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release|x86.Build.0 = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release35|Any CPU.ActiveCfg = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release35|Any CPU.Build.0 = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release35|Mixed Platforms.ActiveCfg = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release35|Mixed Platforms.Build.0 = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release35|x86.ActiveCfg = Release|Any CPU
+ 		{9257F543-44E2-4DB6-8B27-A8A354C13E5B}.Release35|x86.Build.0 = Release|Any CPU
  	EndGlobalSection
  	GlobalSection(SolutionProperties) = preSolution
  		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/3b0e132b/src/Lucene.Net/Lucene.Net.csproj
----------------------------------------------------------------------
diff --cc src/Lucene.Net/Lucene.Net.csproj
index 50b1b14,7234e15..92eea4f
--- a/src/Lucene.Net/Lucene.Net.csproj
+++ b/src/Lucene.Net/Lucene.Net.csproj
@@@ -394,8 -394,10 +394,11 @@@
      <Compile Include="Index\TwoStoredFieldsConsumers.cs" />
      <Compile Include="Index\UpgradeIndexMergePolicy.cs" />
      <Compile Include="LucenePackage.cs" />
+     <Compile Include="Support\AssemblyUtils.cs" />
      <Compile Include="Support\Document\DocumentExtensions.cs" />
 +    <Compile Include="Support\EnumerableExtensions.cs" />
+     <Compile Include="Support\Document\Field.cs" />
+     <Compile Include="Support\Document\IndexableFieldExtensions.cs" />
      <Compile Include="Support\IO\Compression\LZOCompressor.cs" />
      <Compile Include="Properties\AssemblyInfo.cs" />
      <Compile Include="Search\AutomatonQuery.cs" />


[19/20] lucenenet git commit: Lucene.Net.Tests.Replicator: Added TestApiConsistency and TestExceptionSerialization tests

Posted by ni...@apache.org.
Lucene.Net.Tests.Replicator: Added TestApiConsistency and TestExceptionSerialization tests


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

Branch: refs/heads/replicator
Commit: f308f83f6ba12818e6dd514ac418334ee9398421
Parents: e83f40f
Author: Shad Storhaug <sh...@shadstorhaug.com>
Authored: Thu Aug 17 18:29:49 2017 +0700
Committer: Shad Storhaug <sh...@shadstorhaug.com>
Committed: Thu Aug 17 18:29:49 2017 +0700

----------------------------------------------------------------------
 .../Lucene.Net.Tests.Replicator.csproj          |   6 +
 .../Support/TestApiConsistency.cs               | 150 +++++++++++++++++++
 .../Support/TestExceptionSerialization.cs       |  54 +++++++
 3 files changed, 210 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f308f83f/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
index cb21da7..780f618 100644
--- a/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
+++ b/src/Lucene.Net.Tests.Replicator/Lucene.Net.Tests.Replicator.csproj
@@ -29,6 +29,9 @@
     <ErrorReport>prompt</ErrorReport>
     <WarningLevel>4</WarningLevel>
   </PropertyGroup>
+  <PropertyGroup>
+    <DefineConstants>$(DefineConstants);FEATURE_SERIALIZABLE</DefineConstants>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="System" />
     <Reference Include="System.ComponentModel.Composition" />
@@ -54,6 +57,8 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ReplicatorTestCase.cs" />
     <Compile Include="SessionTokenTest.cs" />
+    <Compile Include="Support\TestApiConsistency.cs" />
+    <Compile Include="Support\TestExceptionSerialization.cs" />
   </ItemGroup>
   <ItemGroup>
     <ProjectReference Include="..\Lucene.Net.Facet\Lucene.Net.Facet.csproj">
@@ -83,6 +88,7 @@
   <ItemGroup>
     <None Include="Lucene.Net.Tests.Replicator.project.json" />
   </ItemGroup>
+  <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.

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f308f83f/src/Lucene.Net.Tests.Replicator/Support/TestApiConsistency.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Support/TestApiConsistency.cs b/src/Lucene.Net.Tests.Replicator/Support/TestApiConsistency.cs
new file mode 100644
index 0000000..600bb3b
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Support/TestApiConsistency.cs
@@ -0,0 +1,150 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+*/
+
+using Lucene.Net.Attributes;
+using Lucene.Net.Support;
+using NUnit.Framework;
+using System;
+
+namespace Lucene.Net.Replicator
+{
+    /// <summary>
+    /// LUCENENET specific tests for ensuring API conventions are followed
+    /// </summary>
+    public class TestApiConsistency : ApiScanTestBase
+    {
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestProtectedFieldNames(Type typeFromTargetAssembly)
+        {
+            base.TestProtectedFieldNames(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestPrivateFieldNames(Type typeFromTargetAssembly)
+        {
+            base.TestPrivateFieldNames(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestPublicFields(Type typeFromTargetAssembly)
+        {
+            base.TestPublicFields(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestMethodParameterNames(Type typeFromTargetAssembly)
+        {
+            base.TestMethodParameterNames(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestInterfaceNames(Type typeFromTargetAssembly)
+        {
+            base.TestInterfaceNames(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestClassNames(Type typeFromTargetAssembly)
+        {
+            base.TestClassNames(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForPropertiesWithNoGetter(Type typeFromTargetAssembly)
+        {
+            base.TestForPropertiesWithNoGetter(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForPropertiesThatReturnArray(Type typeFromTargetAssembly)
+        {
+            base.TestForPropertiesThatReturnArray(typeFromTargetAssembly);
+        }
+
+#if !NETSTANDARD
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForMethodsThatReturnWritableArray(Type typeFromTargetAssembly)
+        {
+            base.TestForMethodsThatReturnWritableArray(typeFromTargetAssembly);
+        }
+#endif
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForPublicMembersContainingComparer(Type typeFromTargetAssembly)
+        {
+            base.TestForPublicMembersContainingComparer(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForPublicMembersNamedSize(Type typeFromTargetAssembly)
+        {
+            base.TestForPublicMembersNamedSize(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForPublicMembersContainingNonNetNumeric(Type typeFromTargetAssembly)
+        {
+            base.TestForPublicMembersContainingNonNetNumeric(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForTypesContainingNonNetNumeric(Type typeFromTargetAssembly)
+        {
+            base.TestForTypesContainingNonNetNumeric(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForPublicMembersWithNullableEnum(Type typeFromTargetAssembly)
+        {
+            base.TestForPublicMembersWithNullableEnum(typeFromTargetAssembly);
+        }
+
+        // LUCENENET NOTE: This test is only for identifying members who were changed from
+        // ICollection, IList or ISet to IEnumerable during the port (that should be changed back)
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForMembersAcceptingOrReturningIEnumerable(Type typeFromTargetAssembly)
+        {
+            base.TestForMembersAcceptingOrReturningIEnumerable(typeFromTargetAssembly);
+        }
+
+        [Test, LuceneNetSpecific]
+        [TestCase(typeof(Lucene.Net.Replicator.IReplicator))]
+        public override void TestForMembersAcceptingOrReturningListOrDictionary(Type typeFromTargetAssembly)
+        {
+            base.TestForMembersAcceptingOrReturningListOrDictionary(typeFromTargetAssembly);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/f308f83f/src/Lucene.Net.Tests.Replicator/Support/TestExceptionSerialization.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Tests.Replicator/Support/TestExceptionSerialization.cs b/src/Lucene.Net.Tests.Replicator/Support/TestExceptionSerialization.cs
new file mode 100644
index 0000000..59535e3
--- /dev/null
+++ b/src/Lucene.Net.Tests.Replicator/Support/TestExceptionSerialization.cs
@@ -0,0 +1,54 @@
+#if FEATURE_SERIALIZABLE
+using Lucene.Net.Attributes;
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Lucene.Net.Support
+{
+    /*
+     * 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.
+     */
+
+    [TestFixture]
+    public class TestExceptionSerialization : ExceptionSerializationTestBase
+    {
+        public static IEnumerable<object> ExceptionTestData
+        {
+            get
+            {
+                var exceptionTypes = typeof(Lucene.Net.Replicator.IReplicator).Assembly.GetTypes().Where(t => typeof(Exception).IsAssignableFrom(t)).Cast<object>();
+
+                // If the assembly has no exceptions, just provide Exception so the test will pass
+                if (!exceptionTypes.Any())
+                {
+                    return new Type[] { typeof(Exception) };
+                }
+
+                return exceptionTypes;
+            }
+        }
+
+        [Test, LuceneNetSpecific]
+        public void AllExceptionsInLuceneNamespaceCanSerialize([ValueSource("ExceptionTestData")]Type luceneException)
+        {
+            var instance = TryInstantiate(luceneException);
+            Assert.That(TypeCanSerialize(instance), string.Format("Unable to serialize {0}", luceneException.FullName));
+        }
+    }
+}
+#endif
\ No newline at end of file