Skip to content

Commit

Permalink
Some initial progress on Consul client
Browse files Browse the repository at this point in the history
  • Loading branch information
graemerocher committed Jan 24, 2018
1 parent 421035f commit 22a6ba3
Show file tree
Hide file tree
Showing 42 changed files with 1,019 additions and 145 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.particleframework.core.convert;

import org.particleframework.core.type.Argument;

import java.util.Optional;
import java.util.function.Function;

Expand Down Expand Up @@ -72,7 +74,17 @@ public interface ConversionService<Impl extends ConversionService> {
default <T> Optional<T> convert(Object object, Class<T> targetType) {
return convert(object, targetType, ConversionContext.DEFAULT);
}

/**
* Attempts to convert the given object to the given target type. If conversion fails or is not possible an empty {@link Optional} is returned
*
* @param object The object to convert
* @param targetType The target type
* @param <T> The generic type
* @return The optional
*/
default <T> Optional<T> convert(Object object, Argument<T> targetType) {
return convert(object, ConversionContext.of(targetType));
}
/**
* Attempts to convert the given object to the given target type. If conversion fails or is not possible an empty {@link Optional} is returned
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ default Optional<T> convert(S object, Class<T> targetType) {
* @return The converter instance
*/
static <ST, TT> TypeConverter<ST, TT> of(Class<ST> sourceType, Class<TT> targetType, Function<ST, TT> converter) {
return (object, targetType1, context) -> Optional.of(converter.apply(object));
return (object, targetType1, context) -> Optional.ofNullable(converter.apply(object));
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.particleframework.core.util;

import javax.annotation.Nullable;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -77,7 +78,7 @@ public static boolean isNotEmpty(Object[] array) {
* @param array The array
* @return The string representation
*/
public static String toString(Object...array) {
public static String toString(@Nullable Object...array) {
String delimiter = ",";
return toString(delimiter, array);
}
Expand All @@ -89,7 +90,7 @@ public static String toString(Object...array) {
* @param array The array
* @return The string representation
*/
public static String toString(String delimiter, Object... array) {
public static String toString(String delimiter, @Nullable Object... array) {
if(isEmpty(array)) {
return "";
}
Expand Down
4 changes: 4 additions & 0 deletions discovery-client/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dependencies {
compileOnly project(":inject-java")
compile project(":http-client")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2018 original authors
*
* 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 org.particleframework.discovery.consul;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import java.net.URL;
import java.util.Map;
import java.util.Optional;

/**
* A catalog entry in Consul. See https://www.consul.io/api/catalog.html
*
* @author graemerocher
* @since 1.0
*/
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public class CatalogEntry extends NodeEntry {
private ServiceEntry service;

/**
* Create a new catalog entry
* @param nodeId The node ID
* @param address The node address
*/
@JsonCreator
public CatalogEntry(@JsonProperty("Node") String nodeId, @JsonProperty("Address") URL address) {
super(nodeId, address);
}

@Override
public CatalogEntry datacenter(String datacenter) {
return (CatalogEntry) super.datacenter(datacenter);
}

@Override
public CatalogEntry taggedAddresses(Map<String, String> taggedAddresses) {
return (CatalogEntry) super.taggedAddresses(taggedAddresses);
}

@Override
public CatalogEntry nodeMetadata(Map<String, String> nodeMetadata) {
return (CatalogEntry) super.nodeMetadata(nodeMetadata);
}

/**
* https://www.consul.io/api/catalog.html#service
*
* @return The service
*/
public Optional<ServiceEntry> getService() {
return Optional.ofNullable(service);
}

public CatalogEntry service(ServiceEntry service) {
this.service = service;
return this;
}

public void setService(ServiceEntry service) {
this.service = service;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2018 original authors
*
* 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 org.particleframework.discovery.consul;

import org.particleframework.http.HttpResponse;
import org.particleframework.http.annotation.Get;
import org.particleframework.http.annotation.Put;
import org.particleframework.http.client.Client;
import org.reactivestreams.Publisher;

import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;

/**
* A non-blocking HTTP client for consul
*
* @author Graeme Rocher
* @since 1.0
*/
@Client(id = ConsulClient.SERVICE_ID, path = "/v1")
public interface ConsulClient {
String SERVICE_ID = "consul";
/**
* Register a new {@link CatalogEntry}. See https://www.consul.io/api/catalog.html
* @param entry The entry to register
*
* @return
*/
@Put("/catalog/register")
Publisher<HttpResponse<?>> register(@NotNull CatalogEntry entry);

/**
* Gets all of the nodes
*
* @return All the nodes
*/
@Get("/catalog/nodes")
Publisher<CatalogEntry> getNodes();

/**
* Gets all the nodes for the given data center
*
* @param datacenter The data center
* @return A publisher that emits the nodes
*/
@Get("/catalog/nodes?dc={datacenter}")
Publisher<CatalogEntry> getNodes(@NotNull String datacenter);

/**
* Gets all of the service names and optional tags
*
* @return A Map where the keys are service names and the values are service tags
*/
@Get("/catalog/services")
Publisher<Map<String, List<String>>> getServiceNames();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2018 original authors
*
* 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 org.particleframework.discovery.consul;

import org.particleframework.context.annotation.ConfigurationProperties;

//import javax.validation.constraints.NotNull;
import java.util.Optional;

/**
* Configuration for consul
*
* @author graemerocher
* @since 1.0
*/
@ConfigurationProperties("consul")
public class ConsulConfiguration {

private String host = "localhost";

private int port = 8500;

private String consulToken;

/**
* @return The token to include in all requests as the {@code X-Consul-Token} header
*/
public Optional<String> getConsulToken() {
return Optional.ofNullable(consulToken);
}

public void setConsulToken(String consulToken) {
this.consulToken = consulToken;
}

/**
* @return The agent host name. Defaults to 'localhost'.
**/
public String getHost() {
return host;
}

/**
* @return The agent port. Defaults to 'localhost'.
**/
public int getPort() {
return port;
}

public void setHost(String host) {
this.host = host;
}

public void setPort(int port) {
this.port = port;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright 2018 original authors
*
* 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 org.particleframework.discovery.consul;

import org.particleframework.http.client.ServerSelector;
import org.particleframework.http.client.ServerSelectorProvider;
import org.particleframework.http.client.exceptions.HttpClientException;

import javax.inject.Singleton;
import java.net.MalformedURLException;
import java.net.URL;

/**
* A selector that discovers the consul URI from configuration
*
* @author graemerocher
* @since 1.0
*/
@Singleton
public class ConsulServerSelectorProvider implements ServerSelectorProvider{

private final ConsulConfiguration configuration;

public ConsulServerSelectorProvider(ConsulConfiguration configuration) {
this.configuration = configuration;
}

@Override
public String getId() {
return ConsulClient.SERVICE_ID;
}

@Override
public ServerSelector getSelector() {
return discriminator -> {
String spec = "http://" + configuration.getHost() + ":" + configuration.getPort();
try {
return new URL(spec);
} catch (MalformedURLException e) {
throw new HttpClientException("Invalid Consul URL: " + spec, e);
}
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright 2018 original authors
*
* 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 org.particleframework.discovery.consul;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.annotation.JsonNaming;

import java.net.URL;

/**
* @author graemerocher
* @since 1.0
*/
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
public class HealthEntry extends CatalogEntry{
/**
* Create a new catalog entry
*
* @param nodeId The node ID
* @param address The node address
*/
@JsonCreator
public HealthEntry(@JsonProperty("Node") String nodeId, @JsonProperty("Address") URL address) {
super(nodeId, address);
}
}
Loading

0 comments on commit 22a6ba3

Please sign in to comment.