Skip to content

Commit

Permalink
Merge pull request #7 from ebjwc/gh-6
Browse files Browse the repository at this point in the history
Allow to pass EurekaClient to EurekaOneDiscoveryStrategyFactory using code
  • Loading branch information
googlielmo committed Oct 19, 2017
2 parents ca41a11 + fb31415 commit 6dbe9d2
Show file tree
Hide file tree
Showing 9 changed files with 283 additions and 68 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,18 @@ which is `hazelcast`. Therefore, `self-registration` property is overridden and

> `IMPORTANT`: `hazelcast.name` property is crucial for clients to discover cluster members.
#### Reusing existing Eureka Client instance
If your application provides already configured `EurekaClient` instance e.g. if you are using Spring Cloud, you can reuse your existing client:

```
EurekaClient eurekaClient = ...
EurekaOneDiscoveryStrategyFactory.setEurekaClient(eurekaClient);
```

When using reused client as above, discovery implementation will **not** send Eureka Server any status changes regarding
application state. Also, if you need to inject `Eureka client` externally, you have to configure discovery programmatically
as shown above code snippet.

## Debugging

When needed, Hazelcast can log the events for the instances that exist in a region. To see what has happened or to
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/com/hazelcast/eureka/one/DefaultUpdater.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright (c) 2008-2017, Hazelcast, Inc. 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.hazelcast.eureka.one;

import com.google.common.base.Preconditions;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.InstanceInfo;

/**
*
*/
class DefaultUpdater implements StatusChangeStrategy {
@Override
public void update(ApplicationInfoManager manager, InstanceInfo.InstanceStatus status) {
Preconditions.checkNotNull(manager);
Preconditions.checkNotNull(status);

manager.setInstanceStatus(status);
}

@Override
public boolean shouldRegister() {
return true;
}
}
163 changes: 103 additions & 60 deletions src/main/java/com/hazelcast/eureka/one/EurekaOneDiscoveryStrategy.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@

package com.hazelcast.eureka.one;

import static com.hazelcast.eureka.one.EurekaOneProperties.EUREKA_ONE_SYSTEM_PREFIX;
import static com.hazelcast.eureka.one.EurekaOneProperties.NAMESPACE;
import static com.hazelcast.eureka.one.EurekaOneProperties.SELF_REGISTRATION;

import java.io.IOException;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import com.google.common.annotations.VisibleForTesting;
import com.hazelcast.logging.ILogger;
import com.hazelcast.logging.NoLogFactory;
Expand All @@ -26,82 +41,121 @@
import com.hazelcast.util.UuidUtil;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.CloudInstanceConfig;
import com.netflix.appinfo.MyDataCenterInstanceConfig;
import com.netflix.appinfo.DataCenterInfo;
import com.netflix.appinfo.EurekaInstanceConfig;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.appinfo.DataCenterInfo;
import com.netflix.appinfo.MyDataCenterInstanceConfig;
import com.netflix.appinfo.providers.EurekaConfigBasedInstanceInfoProvider;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.discovery.DefaultEurekaClientConfig;
import com.netflix.discovery.DiscoveryClient;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.shared.Application;

import java.io.IOException;
import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import static com.hazelcast.eureka.one.EurekaOneProperties.EUREKA_ONE_SYSTEM_PREFIX;
import static com.hazelcast.eureka.one.EurekaOneProperties.NAMESPACE;
import static com.hazelcast.eureka.one.EurekaOneProperties.SELF_REGISTRATION;

class EurekaOneDiscoveryStrategy
final class EurekaOneDiscoveryStrategy
extends AbstractDiscoveryStrategy {

@VisibleForTesting static final String DEFAULT_NAMESPACE = "hazelcast";
@VisibleForTesting static final int NUM_RETRIES = 5;
private static final int VERIFICATION_WAIT_TIMEOUT = 5;
private static final int DISCOVERY_RETRY_TIMEOUT = 1;
static final class EurekaOneDiscoveryStrategyBuilder {
private EurekaClient eurekaClient;
private ApplicationInfoManager applicationInfoManager;
private DiscoveryNode discoveryNode;
private ILogger logger = new NoLogFactory().getLogger(EurekaOneDiscoveryStrategy.class.getName());
private Map<String, Comparable> properties = Collections.emptyMap();
private StatusChangeStrategy changeStrategy;

EurekaOneDiscoveryStrategyBuilder setEurekaClient(final EurekaClient eurekaClient) {
this.eurekaClient = eurekaClient;
if (eurekaClient != null) {
this.applicationInfoManager = eurekaClient.getApplicationInfoManager();
this.changeStrategy = new NoopUpdater();
}
return this;
}

private final EurekaClient eurekaClient;
private final ApplicationInfoManager applicationInfoManager;
EurekaOneDiscoveryStrategyBuilder setApplicationInfoManager(
final ApplicationInfoManager applicationInfoManager) {
this.applicationInfoManager = applicationInfoManager;
return this;
}

private final boolean selfRegistration;
private final boolean clientMode;
EurekaOneDiscoveryStrategyBuilder setDiscoveryNode(final DiscoveryNode discoveryNode) {
this.discoveryNode = discoveryNode;
return this;
}

private final String namespace;
EurekaOneDiscoveryStrategyBuilder setILogger(final ILogger logger) {
this.logger = logger;
return this;
}

@VisibleForTesting
EurekaOneDiscoveryStrategy(EurekaClient eurekaClient,
ApplicationInfoManager manager,
boolean clientMode) {
super(new NoLogFactory().getLogger(EurekaOneDiscoveryStrategy.class.getName()),
Collections.<String, Comparable>emptyMap());
EurekaOneDiscoveryStrategyBuilder setProperties(final Map<String, Comparable> properties) {
this.properties = properties;
return this;
}

@VisibleForTesting
EurekaOneDiscoveryStrategyBuilder setStatusChangeStrategy(StatusChangeStrategy statusChangeStrategy) {
this.changeStrategy = statusChangeStrategy;
return this;
}

this.selfRegistration = getOrDefault(EUREKA_ONE_SYSTEM_PREFIX, SELF_REGISTRATION, true);
this.namespace = getOrDefault(EUREKA_ONE_SYSTEM_PREFIX, NAMESPACE, DEFAULT_NAMESPACE);
EurekaOneDiscoveryStrategy build() {
if (null == changeStrategy) {
changeStrategy = new DefaultUpdater();
}

this.clientMode = clientMode;
if (null == discoveryNode) {
changeStrategy = new NoopUpdater();
}

this.eurekaClient = eurekaClient;
this.applicationInfoManager = manager;
return new EurekaOneDiscoveryStrategy(this);
}
}

EurekaOneDiscoveryStrategy(DiscoveryNode localNode, ILogger logger, Map<String, Comparable> properties) {
super(logger, properties);
@VisibleForTesting
static final String DEFAULT_NAMESPACE = "hazelcast";
@VisibleForTesting
static final int NUM_RETRIES = 5;
private static final int VERIFICATION_WAIT_TIMEOUT = 5;
private static final int DISCOVERY_RETRY_TIMEOUT = 1;

private final EurekaClient eurekaClient;
private final ApplicationInfoManager applicationInfoManager;

private final String namespace;
private StatusChangeStrategy statusChangeStrategy;

private EurekaOneDiscoveryStrategy(final EurekaOneDiscoveryStrategyBuilder builder) {
super(builder.logger, builder.properties);

this.selfRegistration = getOrDefault(EUREKA_ONE_SYSTEM_PREFIX, SELF_REGISTRATION, true);
this.namespace = getOrDefault(EUREKA_ONE_SYSTEM_PREFIX, NAMESPACE, "hazelcast");
boolean selfRegistration = getOrDefault(EUREKA_ONE_SYSTEM_PREFIX, SELF_REGISTRATION, true);
// override registration if requested
if (!selfRegistration) {
statusChangeStrategy = new NoopUpdater();
} else {
this.statusChangeStrategy = builder.changeStrategy;
}

this.clientMode = localNode == null;
if (builder.applicationInfoManager == null) {
this.applicationInfoManager = initializeApplicationInfoManager(builder.discoveryNode);
} else {
this.applicationInfoManager = builder.applicationInfoManager;
}

this.applicationInfoManager = initializeApplicationInfoManager(localNode);
this.eurekaClient = new DiscoveryClient(applicationInfoManager, new EurekaOneAwareConfig(this.namespace));
if (builder.eurekaClient == null) {
this.eurekaClient = new DiscoveryClient(applicationInfoManager, new EurekaOneAwareConfig(this.namespace));
} else {
this.eurekaClient = builder.eurekaClient;
}
}

private ApplicationInfoManager initializeApplicationInfoManager(DiscoveryNode localNode) {
EurekaInstanceConfig instanceConfig = buildInstanceConfig(localNode);

InstanceInfo instanceInfo = new EurekaConfigBasedInstanceInfoProvider(instanceConfig).get();
ApplicationInfoManager manager = new ApplicationInfoManager(instanceConfig, instanceInfo);
eurekaStatusChange(manager, InstanceInfo.InstanceStatus.STARTING);
statusChangeStrategy.update(manager, InstanceInfo.InstanceStatus.STARTING);

return manager;
}
Expand Down Expand Up @@ -173,13 +227,13 @@ public Iterable<DiscoveryNode> discoverNodes() {

@Override
public void start() {
eurekaStatusChange(InstanceInfo.InstanceStatus.UP);
statusChangeStrategy.update(applicationInfoManager, InstanceInfo.InstanceStatus.UP);
verifyEurekaRegistration();
}

@Override
public void destroy() {
eurekaStatusChange(InstanceInfo.InstanceStatus.DOWN);
statusChangeStrategy.update(applicationInfoManager, InstanceInfo.InstanceStatus.DOWN);
if (null != eurekaClient) {
eurekaClient.shutdown();
}
Expand All @@ -195,17 +249,6 @@ private InetAddress mapAddress(InstanceInfo instance) {
return null;
}

private void eurekaStatusChange(InstanceInfo.InstanceStatus status) {
eurekaStatusChange(applicationInfoManager, status);
}

private void eurekaStatusChange(ApplicationInfoManager applicationInfoManager, InstanceInfo.InstanceStatus status) {
if (clientMode || !selfRegistration) {
return;
}
applicationInfoManager.setInstanceStatus(status);
}

@VisibleForTesting
void verifyEurekaRegistration() {
String applicationName = applicationInfoManager.getEurekaInstanceConfig().getAppname();
Expand Down Expand Up @@ -239,7 +282,7 @@ private class EurekaOneAwareConfig extends DefaultEurekaClientConfig {

@Override
public boolean shouldRegisterWithEureka() {
return !clientMode && selfRegistration;
return statusChangeStrategy.shouldRegister();
}
}

Expand All @@ -253,7 +296,7 @@ private static final class DelegatingInstanceConfig
private DelegatingInstanceConfig(EurekaInstanceConfig instanceConfig, DiscoveryNode localNode) {
this.instanceConfig = instanceConfig;
this.localNode = localNode;
this.uuid = UuidUtil.newSecureUuidString();
this.uuid = UuidUtil.newSecureUuidString();
}

public String getInstanceId() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@

import com.google.common.collect.Lists;
import com.hazelcast.config.properties.PropertyDefinition;
import com.hazelcast.eureka.one.EurekaOneDiscoveryStrategy.EurekaOneDiscoveryStrategyBuilder;
import com.hazelcast.logging.ILogger;
import com.hazelcast.spi.discovery.DiscoveryNode;
import com.hazelcast.spi.discovery.DiscoveryStrategy;
import com.hazelcast.spi.discovery.DiscoveryStrategyFactory;
import com.netflix.discovery.EurekaClient;

import java.util.Collection;
import java.util.Map;
Expand All @@ -37,17 +39,30 @@ public class EurekaOneDiscoveryStrategyFactory
EurekaOneProperties.SELF_REGISTRATION,
EurekaOneProperties.NAMESPACE);

private static EurekaClient eurekaClient;

public Class<? extends DiscoveryStrategy> getDiscoveryStrategyType() {
return EurekaOneDiscoveryStrategy.class;
}

public DiscoveryStrategy newDiscoveryStrategy(DiscoveryNode discoveryNode, ILogger logger,
Map<String, Comparable> properties) {

return new EurekaOneDiscoveryStrategy(discoveryNode, logger, properties);
EurekaOneDiscoveryStrategyBuilder builder = new EurekaOneDiscoveryStrategyBuilder();
builder.setDiscoveryNode(discoveryNode).setILogger(logger).setProperties(properties)
.setEurekaClient(eurekaClient);
return builder.build();
}

public Collection<PropertyDefinition> getConfigurationProperties() {
return PROPERTY_DEFINITIONS;
}

/**
* Allows to use already configured {@link EurekaClient} instead of creating new one.
*
* @param eurekaClient {@link EurekaClient} instance
*/
public static void setEurekaClient(EurekaClient eurekaClient) {
EurekaOneDiscoveryStrategyFactory.eurekaClient = eurekaClient;
}
}
35 changes: 35 additions & 0 deletions src/main/java/com/hazelcast/eureka/one/NoopUpdater.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2008-2017, Hazelcast, Inc. 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.hazelcast.eureka.one;

import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.InstanceInfo;

/**
*
*/
class NoopUpdater implements StatusChangeStrategy {

@Override
public void update(ApplicationInfoManager manager, InstanceInfo.InstanceStatus status) {
}

@Override
public boolean shouldRegister() {
return false;
}
}

0 comments on commit 6dbe9d2

Please sign in to comment.