diff --git a/README.md b/README.md
index 78fbfb7..9177ee8 100644
--- a/README.md
+++ b/README.md
@@ -121,7 +121,7 @@ In addition to our `com.noctarius.snowcast.Snowcast` factory, a custom epoch mus
```java
Calendar calendar = GregorianCalendar.getInstance();
-calendar.set( 2014, Calendar.JANUARY, 1, 0, 0, 0 );
+calendar.set( 2017, Calendar.JANUARY, 1, 0, 0, 0 );
SnowcastEpoch epoch = SnowcastEpoch.byCalendar( calendar );
```
@@ -151,62 +151,13 @@ Destroying a sequencer is a cluster operation and will destroy all sequencers re
### Hazelcast Configuration
-snowcast 2.0 uses a custom service that is automatically registered with Hazelcast on startup. It supports Hazelcast 3.7.x and 3.8.x. To get started with snowcast simply provide the according JAR file in the classpath of the application. No additional step's necessary. For older snowcast versions see below.
-
-For snowcast 1.0; Hazelcast requires custom services to be configured upfront using either the Configuration API or by utilizing the, XML based, declarative configuration.
+snowcast uses a custom service that is automatically registered with Hazelcast on startup. Snowcast 2.0 supports Hazelcast 3.7.x and 3.8.x. snowcast 2.1 supports 3.9.x. To get started with snowcast simply provide the according JAR file in the classpath of the application. No additional step's necessary. For older snowcast versions see below.
snowcast offers three different ways to register the snowcast service with Hazelcast by providing support for the two already named ones and additionally is equipped with a hack to lazily registers itself as a Hazelcast service on first acquisition. This way is not meant to be used in production, the reason will be shown in a bit.
-#### Using the Configuration API
-
-As of snowcast 2.0 no manual configuration is required anymore. This chapter, however, stays for reference of snowcast 1.0.
-
-The simplest way to configure snowcast is using the Hazelcast Configuration API. snowcast provides the user with a helper class to configure all necessary options.
-
-If no other configuration is necessary let the snowcast helper create the `com.hazelcast.config.Config` instance for you, using the same way as Hazelcast itself would do it, and retrieve a pre-configured `Config` ready to be used to create a Hazelcast instance.
-
-```java
-Config config = SnowcastNodeConfigurator.buildSnowcastAwareConfig();
-HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance( config );
-```
-
-If there is already a `Config` instance this can be passed in and configured to use snowcast.
-
-```java
-Config config = new Config();
-config = SnowcastNodeConfigurator.buildSnowcastAwareConfig( config );
-HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance( config );
-```
-
-#### Using the Declarative Configuration
-
-As of snowcast 2.0 no manual configuration is required anymore. This chapter, however, stays for reference of snowcast 1.0.
-
-For people configuring Hazelcast using the XML based configuration only, snowcast also supports a configuration based on declarative configuration. As a disadvantage using the declarative configuration the internal classname of the service is bound to the configuration. Whenever the classname might change for any reason instantiating Hazelcast might fail for an non-obvious reason. Using the [Configuration API](#using-the-configuration-api) is recommended.
-
-```xml
-
-
-
-
- noctarius::SequencerService
- com.noctarius.snowcast.impl.NodeSequencerService
-
-
-
-```
-
-That way the snowcast service is registered into Hazelcast.
-
-#### Lazy Configuration Hack (removed)
-
-The previously available "Lazy Configuration Hack" has been removed from snowcast 1.0.0.
-
### Hazelcast Client Configuration
-snowcast 2.0 snapshots currently support Hazelcast 3.7.x, 3.8.x. The underlying communication system is automatically registered.
+snowcast 2.0 snapshots currently support Hazelcast 3.7.x, 3.8.x. snowcast 2.1 supports Hazelcast 3.9.x. The underlying communication system is automatically registered.
For older versions, snowcast 1.0 supports Hazelcast 3.4.x as well as Hazelcast 3.5.x and automatically registers a matching communication system.
@@ -229,7 +180,7 @@ snowcast is deployed as a Apache Maven artifact. All release candidates as well
com.noctarius.snowcast
snowcast
- 1.0.0
+ 2.1.0
```
@@ -254,7 +205,7 @@ The Maven coordinates for the snowcast artifacts are:
com.noctarius.snowcast
snowcast
- 2.0.0-SNAPSHOT
+ 2.1.0-SNAPSHOT
```
@@ -341,7 +292,7 @@ HazelcastInstance hazelcastClient = getHazelcastClient();
Snowcast snowcast = SnowcastSystem.snowcast( hazelcastClient );
Calendar calendar = GregorianCalendar.getInstance();
-calendar.set( 2014, Calendar.JANUARY, 1, 0, 0, 0 );
+calendar.set( 2017, Calendar.JANUARY, 1, 0, 0, 0 );
SnowcastEpoch epoch = SnowcastEpoch.byCalendar( calendar );
SnowcastSequencer sequencer = snowcast.createSequencer( "sequencerName", epoch );
diff --git a/pom.xml b/pom.xml
index d15a4ae..06d85a6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
4.0.0
com.noctarius.snowcast
snowcast
- 2.0.0-SNAPSHOT
+ 2.1.0-SNAPSHOT
snowcast is an auto-configuration, distributed, scalable ID generator on top of Hazelcast
2014
http://github.com/noctarius/snowcast
@@ -70,7 +70,7 @@
- 3.7.4
+ 3.9
${maven.build.timestamp}
yyyy-MM-dd HH:mm
@@ -90,13 +90,13 @@
com.hazelcast
hazelcast-client-protocol
- 1.4.0-7
+ 1.5.0
provided
com.hazelcast
hazelcast-code-generator
- 1.4.0-7
+ 1.5.0
provided
@@ -258,7 +258,7 @@
*.impl.*
true
- http://docs.hazelcast.org/docs/3.7/javadoc/
+ http://docs.hazelcast.org/docs/3.8/javadoc/
@@ -360,7 +360,7 @@
org.apache.maven.plugins
maven-gpg-plugin
- 1.1
+ 1.4
sign-artifacts
diff --git a/src/main/java/com/noctarius/snowcast/SnowcastSystem.java b/src/main/java/com/noctarius/snowcast/SnowcastSystem.java
index 39a63bc..f20ea79 100644
--- a/src/main/java/com/noctarius/snowcast/SnowcastSystem.java
+++ b/src/main/java/com/noctarius/snowcast/SnowcastSystem.java
@@ -17,17 +17,16 @@
package com.noctarius.snowcast;
import com.hazelcast.core.HazelcastInstance;
+import com.hazelcast.instance.HazelcastInstanceImpl;
import com.hazelcast.instance.HazelcastInstanceProxy;
-import com.hazelcast.nio.ClassLoaderUtil;
+import com.noctarius.snowcast.impl.ClientSnowcastFactory;
import com.noctarius.snowcast.impl.NodeSnowcastFactory;
-import com.noctarius.snowcast.impl.SequencerService;
+import java.util.Map;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.ThreadSafe;
import javax.validation.constraints.Max;
-import java.lang.reflect.Method;
-import java.util.Map;
import static com.noctarius.snowcast.impl.ExceptionMessages.BACKUP_COUNT_TOO_HIGH;
import static com.noctarius.snowcast.impl.ExceptionMessages.BACKUP_COUNT_TOO_LOW;
@@ -126,18 +125,13 @@ public static Snowcast snowcast(@Nonnull HazelcastInstance hazelcastInstance,
}
// Node setup
- if (hazelcastInstance instanceof HazelcastInstanceProxy) {
+ if (hazelcastInstance instanceof HazelcastInstanceProxy || hazelcastInstance instanceof HazelcastInstanceImpl) {
snowcast = NodeSnowcastFactory.snowcast(hazelcastInstance, (short) backupCount);
}
// Client setup
if (snowcast == null) {
- snowcast = execute(() -> {
- String className = SequencerService.class.getPackage().getName() + ".ClientSnowcastFactory";
- Class> clazz = ClassLoaderUtil.loadClass(null, className);
- Method snowcastMethod = clazz.getMethod("snowcast", HazelcastInstance.class, short.class);
- return (Snowcast) snowcastMethod.invoke(clazz, hazelcastInstance, (short) backupCount);
- });
+ snowcast = execute(() -> ClientSnowcastFactory.snowcast(hazelcastInstance, (short) backupCount));
}
userContext.put(USER_CONTEXT_LOOKUP_NAME, snowcast);
diff --git a/src/main/java/com/noctarius/snowcast/impl/ClientCodec.java b/src/main/java/com/noctarius/snowcast/impl/ClientCodec.java
index 4f05ec4..b89d059 100644
--- a/src/main/java/com/noctarius/snowcast/impl/ClientCodec.java
+++ b/src/main/java/com/noctarius/snowcast/impl/ClientCodec.java
@@ -18,12 +18,8 @@
import com.hazelcast.client.impl.HazelcastClientInstanceImpl;
import com.hazelcast.client.impl.protocol.ClientMessage;
-import com.hazelcast.client.impl.protocol.codec.SnowcastAttachLogicalNodeCodec;
-import com.hazelcast.client.impl.protocol.codec.SnowcastCreateSequencerDefinitionCodec;
-import com.hazelcast.client.impl.protocol.codec.SnowcastDestroySequencerDefinitionCodec;
-import com.hazelcast.client.impl.protocol.codec.SnowcastDetachLogicalNodeCodec;
-import com.hazelcast.client.impl.protocol.codec.SnowcastRegisterChannelCodec;
-import com.hazelcast.client.impl.protocol.codec.SnowcastRemoveChannelCodec;
+import com.hazelcast.client.impl.protocol.codec.*;
+import com.hazelcast.client.spi.impl.ClientInvocation;
import com.hazelcast.core.Partition;
import com.hazelcast.core.PartitionService;
import com.noctarius.snowcast.SnowcastEpoch;
@@ -32,11 +28,11 @@
final class ClientCodec {
- private final ClientInvocator clientInvocator;
+ private final HazelcastClientInstanceImpl client;
private final PartitionService partitionService;
- ClientCodec(HazelcastClientInstanceImpl client, ClientInvocator clientInvocator) {
- this.clientInvocator = clientInvocator;
+ ClientCodec(HazelcastClientInstanceImpl client) {
+ this.client = client;
this.partitionService = client.getPartitionService();
}
@@ -106,7 +102,8 @@ private int partitionId(@Nonnull String sequencerName) {
private ClientMessage invoke(@Nonnull String sequencerName, @Nonnull ClientMessage request) {
return ExceptionUtils.execute(() -> {
int partitionId = partitionId(sequencerName);
- return clientInvocator.invoke(partitionId, request).get();
+ ClientInvocation clientInvocation = new ClientInvocation(client, request, "snowcast", partitionId);
+ return clientInvocation.invoke().get();
});
}
diff --git a/src/main/java/com/noctarius/snowcast/impl/ClientInvocator.java b/src/main/java/com/noctarius/snowcast/impl/ClientInvocator.java
deleted file mode 100644
index 79b3762..0000000
--- a/src/main/java/com/noctarius/snowcast/impl/ClientInvocator.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2015-2017, Christoph Engelbert (aka noctarius) and
- * contributors. All rights reserved.
- *
- * Licensed 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.
- */
-package com.noctarius.snowcast.impl;
-
-import com.hazelcast.client.impl.protocol.ClientMessage;
-import com.hazelcast.core.ICompletableFuture;
-
-import javax.annotation.Nonnegative;
-import javax.annotation.Nonnull;
-
-interface ClientInvocator {
-
- @Nonnull
- ICompletableFuture invoke(@Nonnegative int partitionId, @Nonnull ClientMessage request);
-
-}
diff --git a/src/main/java/com/noctarius/snowcast/impl/ClientSequencer.java b/src/main/java/com/noctarius/snowcast/impl/ClientSequencer.java
index 16336b4..5739e99 100644
--- a/src/main/java/com/noctarius/snowcast/impl/ClientSequencer.java
+++ b/src/main/java/com/noctarius/snowcast/impl/ClientSequencer.java
@@ -42,9 +42,9 @@ public class ClientSequencer
private final ClientSequencerService sequencerService;
ClientSequencer(@Nonnull ClientSequencerService sequencerService, @Nonnull SequencerDefinition definition,
- @Nonnull ClientCodec clientCodec) {
+ @Nonnull ClientCodec clientCodec, @Nonnull ClientContext clientContext) {
- super(SnowcastConstants.SERVICE_NAME, definition.getSequencerName());
+ super(SnowcastConstants.SERVICE_NAME, definition.getSequencerName(), clientContext);
this.sequencerService = sequencerService;
this.sequencerContext = new ClientSequencerContext(definition, clientCodec);
}
diff --git a/src/main/java/com/noctarius/snowcast/impl/ClientSequencerConstructorFunction.java b/src/main/java/com/noctarius/snowcast/impl/ClientSequencerConstructorFunction.java
index fb42cbe..4d28293 100644
--- a/src/main/java/com/noctarius/snowcast/impl/ClientSequencerConstructorFunction.java
+++ b/src/main/java/com/noctarius/snowcast/impl/ClientSequencerConstructorFunction.java
@@ -16,14 +16,15 @@
*/
package com.noctarius.snowcast.impl;
-import com.hazelcast.client.spi.ClientProxy;
+import com.hazelcast.client.impl.HazelcastClientInstanceImpl;
+import com.hazelcast.client.impl.protocol.ClientMessage;
+import com.hazelcast.client.impl.protocol.codec.ClientCreateProxyCodec;
import com.hazelcast.client.spi.ProxyManager;
+import com.hazelcast.client.spi.impl.ClientInvocation;
+import com.hazelcast.nio.Address;
import com.hazelcast.util.ConstructorFunction;
import javax.annotation.Nonnull;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.reflect.Method;
final class ClientSequencerConstructorFunction
implements ConstructorFunction {
@@ -33,42 +34,38 @@ final class ClientSequencerConstructorFunction
private final ClientCodec clientCodec;
private final ProxyManager proxyManager;
private final ClientSequencerService sequencerService;
- private final MethodHandle proxyManagerInitialize;
+ private final HazelcastClientInstanceImpl client;
- ClientSequencerConstructorFunction(@Nonnull ProxyManager proxyManager, @Nonnull ClientSequencerService sequencerService,
+ ClientSequencerConstructorFunction(@Nonnull HazelcastClientInstanceImpl client,
+ @Nonnull ProxyManager proxyManager,
+ @Nonnull ClientSequencerService sequencerService,
@Nonnull ClientCodec clientCodec) {
-
+ this.client = client;
this.clientCodec = clientCodec;
this.proxyManager = proxyManager;
this.sequencerService = sequencerService;
- this.proxyManagerInitialize = getInitializeMethod();
}
@Nonnull
@Override
public SequencerProvision createNew(@Nonnull SequencerDefinition definition) {
TRACER.trace("create new provision for definition %s", definition);
- ClientSequencer sequencer = new ClientSequencer(sequencerService, definition, clientCodec);
- initializeProxy(sequencer);
+ ClientSequencer sequencer = new ClientSequencer(sequencerService, definition, clientCodec, proxyManager.getContext());
+
+ Address initializationTarget = proxyManager.findNextAddressToSendCreateRequest();
+ if (initializationTarget == null) {
+ throw new RuntimeException("Not able to find a member to create proxy on!");
+ } else {
+ ClientMessage clientMessage = ClientCreateProxyCodec.encodeRequest(
+ definition.getSequencerName(), sequencer.getServiceName(), initializationTarget);
+ ExceptionUtils.execute(() -> {
+ new ClientInvocation(client, clientMessage, sequencer.getServiceName(), initializationTarget)
+ .invoke().get();
+ return null;
+ });
+ sequencer.onInitialize();
+ }
sequencer.attachLogicalNode();
return new SequencerProvision(definition, sequencer);
}
-
- private void initializeProxy(@Nonnull ClientSequencer sequencer) {
- //ACCESSIBILITY_HACK
- ExceptionUtils.execute(() -> {
- TRACER.trace("initialize sequencer proxy %s", sequencer);
- return proxyManagerInitialize.invoke(proxyManager, sequencer);
- });
- }
-
- @Nonnull
- private MethodHandle getInitializeMethod() {
- return ExceptionUtils.execute(() -> {
- MethodHandles.Lookup lookup = MethodHandles.lookup();
- Method method = ProxyManager.class.getDeclaredMethod("initialize", ClientProxy.class);
- method.setAccessible(true);
- return lookup.unreflect(method);
- });
- }
}
diff --git a/src/main/java/com/noctarius/snowcast/impl/ClientSequencerService.java b/src/main/java/com/noctarius/snowcast/impl/ClientSequencerService.java
index 8187bb7..ef0c9bb 100644
--- a/src/main/java/com/noctarius/snowcast/impl/ClientSequencerService.java
+++ b/src/main/java/com/noctarius/snowcast/impl/ClientSequencerService.java
@@ -16,17 +16,19 @@
*/
package com.noctarius.snowcast.impl;
+import com.hazelcast.client.impl.HazelcastClientInstanceImpl;
import com.hazelcast.client.spi.ProxyManager;
+import com.hazelcast.util.ConstructorFunction;
import com.noctarius.snowcast.SnowcastEpoch;
import com.noctarius.snowcast.SnowcastSequenceState;
import com.noctarius.snowcast.SnowcastSequencer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
import static com.noctarius.snowcast.impl.ExceptionMessages.ILLEGAL_SEQUENCER_TYPE;
import static com.noctarius.snowcast.impl.ExceptionUtils.exception;
@@ -36,14 +38,15 @@ class ClientSequencerService
private static final Tracer TRACER = TracingUtils.tracer(ClientSequencerService.class);
- private final ClientSequencerConstructorFunction sequencerConstructor;
+ private final ConstructorFunction sequencerConstructor;
private final ClientCodec clientCodec;
private final ConcurrentMap provisions;
- ClientSequencerService(@Nonnull ProxyManager proxyManager, @Nonnull ClientCodec clientCodec) {
- this.sequencerConstructor = new ClientSequencerConstructorFunction(proxyManager, this, clientCodec);
+ ClientSequencerService(@Nonnull HazelcastClientInstanceImpl client, @Nonnull ProxyManager proxyManager,
+ @Nonnull ClientCodec clientCodec) {
+ this.sequencerConstructor = new ClientSequencerConstructorFunction(client, proxyManager, this, clientCodec);
this.provisions = new ConcurrentHashMap<>();
this.clientCodec = clientCodec;
}
diff --git a/src/main/java/com/noctarius/snowcast/impl/ClientSnowcast.java b/src/main/java/com/noctarius/snowcast/impl/ClientSnowcast.java
index 1bc533f..1346799 100644
--- a/src/main/java/com/noctarius/snowcast/impl/ClientSnowcast.java
+++ b/src/main/java/com/noctarius/snowcast/impl/ClientSnowcast.java
@@ -28,11 +28,8 @@
import javax.annotation.Nonnull;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
-import java.lang.reflect.Field;
import static com.noctarius.snowcast.impl.ExceptionMessages.RETRIEVE_CLIENT_ENGINE_FAILED;
-import static com.noctarius.snowcast.impl.ExceptionMessages.UNKNOWN_HAZELCAST_VERSION;
-import static com.noctarius.snowcast.impl.ExceptionUtils.exception;
import static com.noctarius.snowcast.impl.InternalSequencerUtils.printStartupMessage;
import static com.noctarius.snowcast.impl.SnowcastConstants.DEFAULT_MAX_LOGICAL_NODES_13_BITS;
@@ -45,10 +42,9 @@ class ClientSnowcast
ClientSnowcast(@Nonnull HazelcastInstance hazelcastInstance, @Nonnegative @Max(Short.MAX_VALUE) short backupCount) {
this.backupCount = backupCount;
HazelcastClientInstanceImpl client = getHazelcastClient(hazelcastInstance);
- ClientInvocator clientInvocator = buildClientInvocator(client);
- ClientCodec clientCodec = new ClientCodec(client, clientInvocator);
+ ClientCodec clientCodec = new ClientCodec(client);
ProxyManager proxyManager = client.getProxyManager();
- this.sequencerService = new ClientSequencerService(proxyManager, clientCodec);
+ this.sequencerService = new ClientSequencerService(client, proxyManager, clientCodec);
printStartupMessage(true);
}
@@ -62,7 +58,6 @@ public SnowcastSequencer createSequencer(@Nonnull String sequencerName, @Nonnull
@Override
public SnowcastSequencer createSequencer(@Nonnull String sequencerName, @Nonnull SnowcastEpoch epoch,
@Min(128) @Max(8192) int maxLogicalNodeCount) {
-
return sequencerService.createSequencer(sequencerName, epoch, maxLogicalNodeCount, backupCount);
}
@@ -73,20 +68,14 @@ public void destroySequencer(@Nonnull SnowcastSequencer sequencer) {
@Nonnull
private HazelcastClientInstanceImpl getHazelcastClient(@Nonnull HazelcastInstance hazelcastInstance) {
- //ACCESSIBILITY_HACK
return ExceptionUtils.execute(() -> {
- // Ugly hack due to lack in SPI
- Field clientField = HazelcastClientProxy.class.getDeclaredField("client");
- clientField.setAccessible(true);
- return (HazelcastClientInstanceImpl) clientField.get(hazelcastInstance);
+ if (hazelcastInstance instanceof HazelcastClientInstanceImpl) {
+ return (HazelcastClientInstanceImpl) hazelcastInstance;
+ }
+ if (hazelcastInstance instanceof HazelcastClientProxy) {
+ return ((HazelcastClientProxy) hazelcastInstance).client;
+ }
+ throw new InstantiationException();
}, RETRIEVE_CLIENT_ENGINE_FAILED);
}
-
- @Nonnull
- private ClientInvocator buildClientInvocator(HazelcastClientInstanceImpl client) {
- if (InternalSequencerUtils.getHazelcastVersion() != SnowcastConstants.HazelcastVersion.Unknown) {
- return new Hazelcast37ClientInvocator(client);
- }
- throw exception(UNKNOWN_HAZELCAST_VERSION);
- }
}
diff --git a/src/main/java/com/noctarius/snowcast/impl/ExceptionUtils.java b/src/main/java/com/noctarius/snowcast/impl/ExceptionUtils.java
index cea789b..1be4367 100644
--- a/src/main/java/com/noctarius/snowcast/impl/ExceptionUtils.java
+++ b/src/main/java/com/noctarius/snowcast/impl/ExceptionUtils.java
@@ -19,9 +19,12 @@
import com.noctarius.snowcast.SnowcastException;
import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
import java.util.function.Function;
import java.util.function.Supplier;
+import static com.hazelcast.util.ExceptionUtil.rethrow;
+
public class ExceptionUtils {
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
@@ -44,7 +47,13 @@ public static Supplier