diff --git a/cdi-microservice-provider/src/main/java/io/silverware/microservices/annotations/MicroserviceVersion.java b/cdi-microservice-provider/src/main/java/io/silverware/microservices/annotations/MicroserviceVersion.java new file mode 100644 index 0000000..a3f79b7 --- /dev/null +++ b/cdi-microservice-provider/src/main/java/io/silverware/microservices/annotations/MicroserviceVersion.java @@ -0,0 +1,57 @@ +/* + * -----------------------------------------------------------------------\ + * SilverWare + * + * Copyright (C) 2010 - 2016 the original author or 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 io.silverware.microservices.annotations; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation can be used in two different scenarios: + * + * These versions are used in the lookup of the Microservices in the cluster. + * See @{@link io.silverware.microservices.providers.cdi.util.VersionResolver} + * See @{@link io.silverware.microservices.util.VersionComparator} + * + * @author Slavomír Krupa (slavomir.krupa@gmail.com) + */ +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@Target({ ElementType.TYPE }) +public @interface MicroserviceVersion { + + /** + * Gets the API version of the Microservice. + */ + String api() default ""; + + /** + * Gets the implementation version of the Microservice. + * If not defined then {@link io.silverware.microservices.providers.cdi.util.VersionResolver} continues in search for microservice version. + */ + String implementation() default ""; +} diff --git a/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProvider.java b/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProvider.java index 010a905..1eb8b6d 100644 --- a/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProvider.java +++ b/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProvider.java @@ -23,6 +23,7 @@ import io.silverware.microservices.MicroserviceMetaData; import io.silverware.microservices.annotations.Microservice; import io.silverware.microservices.annotations.MicroserviceReference; +import io.silverware.microservices.annotations.MicroserviceVersion; import io.silverware.microservices.providers.MicroserviceProvider; import io.silverware.microservices.providers.cdi.builtin.Configuration; import io.silverware.microservices.providers.cdi.builtin.CurrentContext; @@ -32,6 +33,7 @@ import io.silverware.microservices.providers.cdi.internal.MicroservicesInitEvent; import io.silverware.microservices.silver.CdiSilverService; import io.silverware.microservices.util.Utils; +import io.silverware.microservices.util.VersionComparator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -44,7 +46,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; - import javax.annotation.Priority; import javax.enterprise.context.Dependent; import javax.enterprise.context.spi.CreationalContext; @@ -58,6 +59,8 @@ /** * @author Martin Večeřa + * Changes in version resolution in lookupMicroservice + * @author Slavomir Krupa (slavomir.krupa@gmail.com) */ public class CdiMicroserviceProvider implements MicroserviceProvider, CdiSilverService { @@ -134,15 +137,18 @@ public void run() { @Override @SuppressWarnings("checkstyle:JavadocMethod") public Set lookupMicroservice(final MicroserviceMetaData microserviceMetaData) { + // name can not be null - contract of MicroserviceMetaData final String name = microserviceMetaData.getName(); final Class type = microserviceMetaData.getType(); final Set qualifiers = microserviceMetaData.getQualifiers(); + final String apiVersion = microserviceMetaData.getApiVersion(); final Set matchingBeansByName = new HashSet<>(); final Set matchingBeansByType = new HashSet<>(); boolean wasAlternative = false; /* We are in search for a CDI bean that meets the provided meta-data. + If there is a MicroserviceVersion annotation and it is not matching the version in metadata we skip that bean automatically. Input and corresponding output is as follows: * name specified in MicroserviceReference or derived from data type (both class or interface) * beans having the same name in Microservice annotation @@ -157,33 +163,39 @@ public Set lookupMicroservice(final MicroserviceMetaData microserviceMet for (final Bean bean : beans) { if (bean.getBeanClass().isAnnotationPresent(Microservice.class) && !(bean instanceof MicroserviceProxyBean)) { final Bean theBean = beanManager.resolve(Collections.singleton(bean)); + + if (theBean.getBeanClass().isAnnotationPresent(MicroserviceVersion.class)) { + final MicroserviceVersion versionAnnotation = theBean.getBeanClass().getAnnotation(MicroserviceVersion.class); + String implementationVersion = versionAnnotation.implementation(); + if (!VersionComparator.forVersion(implementationVersion).satisfies(apiVersion)) { + continue; + } + } final Microservice microserviceAnnotation = theBean.getBeanClass().getAnnotation(Microservice.class); - if (name != null) { - if ((!microserviceAnnotation.value().isEmpty() && name.equals(microserviceAnnotation.value())) || - (microserviceAnnotation.value().isEmpty() && name.equals(theBean.getName()))) { - matchingBeansByName.add(beanManager.getReference(theBean, type, beanManager.createCreationalContext(theBean))); - } else if (type.isAssignableFrom(theBean.getBeanClass())) { - final Set qualifiersToCompare = new HashSet<>(theBean.getQualifiers()); - qualifiers.stream().forEach(qualifiersToCompare::remove); - - if (qualifiersToCompare.size() == 0) { - - if (bean.isAlternative()) { - if (!wasAlternative) { - matchingBeansByType.clear(); - matchingBeansByType.add(beanManager.getReference(theBean, type, beanManager.createCreationalContext(theBean))); - wasAlternative = true; - } else { - matchingBeansByType.add(beanManager.getReference(theBean, type, beanManager.createCreationalContext(theBean))); - throw new IllegalStateException(String.format("There are more than alternate beans matching the query: %s. The beans are: %s.", microserviceMetaData.toString(), matchingBeansByType.toString())); - } + if ((!microserviceAnnotation.value().isEmpty() && name.equals(microserviceAnnotation.value())) || + (microserviceAnnotation.value().isEmpty() && name.equals(theBean.getName()))) { + matchingBeansByName.add(beanManager.getReference(theBean, type, beanManager.createCreationalContext(theBean))); + } else if (type.isAssignableFrom(theBean.getBeanClass())) { + final Set qualifiersToCompare = new HashSet<>(theBean.getQualifiers()); + qualifiers.stream().forEach(qualifiersToCompare::remove); + + if (qualifiersToCompare.size() == 0) { + + if (bean.isAlternative()) { + if (!wasAlternative) { + matchingBeansByType.clear(); + matchingBeansByType.add(beanManager.getReference(theBean, type, beanManager.createCreationalContext(theBean))); + wasAlternative = true; + } else { + matchingBeansByType.add(beanManager.getReference(theBean, type, beanManager.createCreationalContext(theBean))); + throw new IllegalStateException(String.format("There are more than alternate beans matching the query: %s. The beans are: %s.", microserviceMetaData.toString(), matchingBeansByType.toString())); + } + } else { + if (!wasAlternative) { + matchingBeansByType.add(beanManager.getReference(theBean, type, beanManager.createCreationalContext(theBean))); } else { - if (!wasAlternative) { - matchingBeansByType.add(beanManager.getReference(theBean, type, beanManager.createCreationalContext(theBean))); - } else { - // ignore this bean - } + // ignore this bean } } } @@ -223,7 +235,7 @@ public T lookupBean(final Class type) { @Override public T findByType(final Class type) { final BeanManager beanManager = (BeanManager) this.context.getProperties().get(BEAN_MANAGER); - final Set beans = new HashSet(); + final Set beans = new HashSet<>(); final Set> definitions = beanManager.getBeans(type); final Bean bean = beanManager.resolve(definitions); final CreationalContext creationalContext = beanManager.createCreationalContext(bean); @@ -259,7 +271,7 @@ public Object log(final InvocationContext ic) throws Exception { } } - @SuppressWarnings({"unused", "checkstyle:JavadocType"}) + @SuppressWarnings({ "unused", "checkstyle:JavadocType" }) @Microservice public static class SilverWareConfiguration implements Configuration { @@ -275,7 +287,7 @@ public void eventObserver(@Observes final MicroservicesInitEvent event) { } } - @SuppressWarnings({"unused", "unchecked", "checkstyle:JavadocType"}) + @SuppressWarnings({ "unused", "unchecked", "checkstyle:JavadocType" }) @Microservice public static class SilverWareStorage implements Storage { @@ -305,7 +317,7 @@ public void eventObserver(@Observes final MicroservicesInitEvent event) { } } - @SuppressWarnings({"unused", "checkstyle:JavadocMethod"}) + @SuppressWarnings({ "unused", "checkstyle:JavadocMethod" }) @Microservice public static class SilverWareCurrentContext implements CurrentContext { diff --git a/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/internal/DefaultMethodHandler.java b/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/internal/DefaultMethodHandler.java index 2cb14fc..f1bec1c 100644 --- a/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/internal/DefaultMethodHandler.java +++ b/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/internal/DefaultMethodHandler.java @@ -19,6 +19,12 @@ */ package io.silverware.microservices.providers.cdi.internal; +import io.silverware.microservices.MicroserviceMetaData; +import io.silverware.microservices.annotations.MicroserviceReference; +import io.silverware.microservices.providers.cdi.util.VersionResolver; +import io.silverware.microservices.silver.services.LookupStrategy; +import io.silverware.microservices.silver.services.LookupStrategyFactory; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -28,11 +34,6 @@ import java.util.stream.Collectors; import javax.annotation.Priority; -import io.silverware.microservices.MicroserviceMetaData; -import io.silverware.microservices.annotations.MicroserviceReference; -import io.silverware.microservices.silver.services.LookupStrategy; -import io.silverware.microservices.silver.services.LookupStrategyFactory; - /** * Default microservice method handler which is invoked as the last one and makes an actual call on the service instance. */ @@ -49,7 +50,7 @@ protected DefaultMethodHandler(final MicroserviceProxyBean proxyBean) throws Exc this.proxyBean = proxyBean; final Set qualifiers = proxyBean.getQualifiers().stream().filter(qualifier -> !qualifier.annotationType().getName().equals(MicroserviceReference.class.getName())).collect(Collectors.toSet()); - final MicroserviceMetaData metaData = new MicroserviceMetaData(proxyBean.getMicroserviceName(), proxyBean.getServiceInterface(), qualifiers, proxyBean.getAnnotations()); + final MicroserviceMetaData metaData = VersionResolver.createMicroserviceMetadata(proxyBean.getMicroserviceName(), proxyBean.getServiceInterface(), qualifiers, proxyBean.getAnnotations()); this.lookupStrategy = LookupStrategyFactory.getStrategy(proxyBean.getContext(), metaData, proxyBean.getAnnotations()); } diff --git a/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/internal/MicroservicesCDIExtension.java b/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/internal/MicroservicesCDIExtension.java index baf0de3..6b3324d 100644 --- a/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/internal/MicroservicesCDIExtension.java +++ b/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/internal/MicroservicesCDIExtension.java @@ -24,6 +24,7 @@ import io.silverware.microservices.annotations.Microservice; import io.silverware.microservices.annotations.MicroserviceReference; import io.silverware.microservices.providers.cdi.MicroserviceContext; +import io.silverware.microservices.providers.cdi.util.VersionResolver; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -86,10 +87,8 @@ public MicroservicesCDIExtension(final Context context) { /** * {@link javax.enterprise.inject.spi.BeforeBeanDiscovery} CDI event observer. * - * @param beforeEvent - * CDI Event instance. - * @param beanManager - * CDI Bean Manager instance. + * @param beforeEvent CDI Event instance. + * @param beanManager CDI Bean Manager instance. */ public void beforeBeanDiscovery(@Observes final BeforeBeanDiscovery beforeEvent, final BeanManager beanManager) { if (log.isDebugEnabled()) { @@ -100,10 +99,8 @@ public void beforeBeanDiscovery(@Observes final BeforeBeanDiscovery beforeEvent, /** * {@link javax.enterprise.inject.spi.ProcessBean} CDI event observer. * - * @param processBean - * CDI Event instance. - * @param beanManager - * CDI Bean Manager instance. + * @param processBean CDI Event instance. + * @param beanManager CDI Bean Manager instance. */ public void processBean(@Observes final ProcessBean processBean, final BeanManager beanManager) { final Bean bean = processBean.getBean(); @@ -156,8 +153,7 @@ private Set preProcessQualifiers(final Set qualifiers) { /** * {@link javax.enterprise.inject.spi.ProcessBean} CDI event observer. * - * @param afterEvent - * CDI Event instance. + * @param afterEvent CDI Event instance. */ public void afterBeanDiscovery(@Observes final AfterBeanDiscovery afterEvent) { afterEvent.addContext(new MicroserviceContext()); @@ -216,6 +212,7 @@ private void addClientProxyBean(final String microserviceName, final Class be /** * Gets the number of discovered injection points. + * * @return The number of discovered injection points. */ public long getInjectionPointsCount() { @@ -224,13 +221,14 @@ public long getInjectionPointsCount() { /** * Gets a new {@link MicroserviceMetaData} descriptor based on the provided CDI bean. + * * @param microserviceName The Microservice name. - * @param bean The CDI Bean. + * @param bean The CDI Bean. * @return Microservice meta-data. */ private MicroserviceMetaData getMicroserviceMetaData(final String microserviceName, final Bean bean) { - return new MicroserviceMetaData(microserviceName, bean.getBeanClass(), bean.getQualifiers(), new HashSet<>( - Arrays.asList(bean.getBeanClass().getAnnotations()))); + return VersionResolver.createMicroserviceMetadata(microserviceName, bean.getBeanClass(), bean.getQualifiers(), new HashSet<>( + Arrays.asList(bean.getBeanClass().getAnnotations()))); } /** diff --git a/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/util/VersionResolver.java b/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/util/VersionResolver.java new file mode 100644 index 0000000..fe56917 --- /dev/null +++ b/cdi-microservice-provider/src/main/java/io/silverware/microservices/providers/cdi/util/VersionResolver.java @@ -0,0 +1,184 @@ +/* + * -----------------------------------------------------------------------\ + * SilverWare + * + * Copyright (C) 2010 - 2013 the original author or 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 io.silverware.microservices.providers.cdi.util; + +import io.silverware.microservices.MicroserviceMetaData; +import io.silverware.microservices.annotations.MicroserviceVersion; +import io.silverware.microservices.util.Utils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * This class is used for resolving of api and implementation versions. + * The resolution process takes the first version which is provided for the microservice from following list + *
    + *
  1. MicroserviceVersion annotation on bean
  2. + *
  3. MicroserviceVersion annotation on class
  4. + *
  5. MicroserviceVersion annotation on interfaces
  6. + *
  7. MicroserviceVersion annotation on parent classes
  8. + *
  9. Manifest version
  10. + *
+ * If no version was obtained using this process null will be returned. + * See @{@link MicroserviceVersion} + * See @{@link io.silverware.microservices.util.VersionComparator} + * + * @author Slavomír Krupa (slavomir.krupa@gmail.com) + */ +public final class VersionResolver { + public static final java.util.function.Predicate IS_ANNOTATION_MICROSERVICE_VERSION = annotation -> MicroserviceVersion.class.isAssignableFrom(annotation.getClass()); + /** + * Logger. + */ + private static final Logger log = LogManager.getLogger(VersionResolver.class); + + public static final String SPECIFICATION_VERSION = "Specification-Version"; + public static final String IMPLEMENTATION_VERSION = "Implementation-Version"; + + private VersionResolver() { + } + + /** + * Create a instance of a Microservice meta data which represents discovered Microservice. + * + * @param name + * The name of the discovered Microservice. + * @param type + * The type of the discovered Microservice. + * @param qualifiers + * The qualifiers of the discovered Microservice. + * @param annotations + * The annotations of the discovered Microservice. + */ + public static MicroserviceMetaData createMicroserviceMetadata(final String name, final Class type, final Set qualifiers, final Set annotations) { + String apiVersion = resolveApiVersion(type, annotations); + String implVersion = resolveImplementationVersion(type, annotations); + return new MicroserviceMetaData(name, type, qualifiers, annotations, apiVersion, implVersion); + + } + + /** + * Use the process mentioned in @{@link VersionResolver} to obtain api version. + * + * @param clazz + * The class I want to obtain version of. + * @param annotations + * list of a annotations from service + * @return The class specification version from manifest, null if there is no version information present or the manifest file does not exists. + */ + public static String resolveApiVersion(final Class clazz, final Set annotations) { + return resolveVersion(clazz, annotations, MicroserviceVersion::api, SPECIFICATION_VERSION); + } + + /** + * Use the process mentioned in @{@link VersionResolver} to obtain implementation version. + * + * @param clazz + * The class I want to obtain version of. + * @param annotations + * list of a annotations from service + * @return The class specification version from manifest, null if there is no version information present or the manifest file does not exists. + */ + public static String resolveImplementationVersion(final Class clazz, final Set annotations) { + return resolveVersion(clazz, annotations, MicroserviceVersion::implementation, IMPLEMENTATION_VERSION); + } + + private static String resolveVersion(final Class clazz, final Set annotations, Function lambda, final String versionType) { + String version = null; + if (annotations != null) { + version = resolveVersionFromAnnotations(annotations.stream(), lambda); + } + if (version == null && clazz.getAnnotations() != null) { + version = resolveVersionFromAnnotations(Arrays.stream(clazz.getAnnotations()), lambda); + } + if (version == null) { + version = resolveVersionFromInterfacesClasses(clazz, lambda); + } + if (version == null) { + version = resolveVersionFromSuperClasses(clazz, lambda); + } + if (version == null) { + version = getClassVersionFromManifest(clazz, versionType); + } + return version; + } + + private static String resolveVersionFromSuperClasses(final Class clazz, final Function lambda) { + Class classToProcess = clazz.getSuperclass(); + String version = null; + while (classToProcess != null && !classToProcess.equals(Object.class) && version == null) { + version = resolveVersionFromAnnotations(Arrays.stream(classToProcess.getAnnotations()), lambda); + classToProcess = classToProcess.getSuperclass(); + } + return version; + } + + private static String resolveVersionFromInterfacesClasses(final Class clazz, Function lambda) { + Class[] interfaces = clazz.getInterfaces(); + List versions = Arrays.stream(interfaces) + .map(i -> resolveVersionFromAnnotations(Arrays.stream(i.getAnnotations()), lambda)) + .collect(Collectors.toList()); + if (versions.size() > 1) { + throw new IllegalArgumentException("Microservice version annotation present at more interfaces."); + } + return versions.isEmpty() ? null : versions.get(0); + + } + + private static String resolveVersionFromAnnotations(Stream annotations, Function lambda) { + if (annotations != null) { + Optional annotation = annotations.filter(IS_ANNOTATION_MICROSERVICE_VERSION).findFirst(); + if (annotation.isPresent()) { + return lambda.apply((MicroserviceVersion) annotation.get()); + } + } + return null; + } + + /** + * Gets the class implementation version from manifest. + * + * @param clazz + * The class I want to obtain version of. + * @return The class specification version from manifest, null if there is no version information present or the manifest file does not exists. + */ + private static String getClassVersionFromManifest(final Class clazz, final String versionType) { + try { + return Utils.getManifestEntry(clazz, versionType); + } catch (IOException ioe) { + if (log.isDebugEnabled()) { + log.debug("Cannot obtain version for class {}.", clazz.getName()); + } + } + + return null; + } + +} diff --git a/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderAlternativesTest.java b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderAlternativesTest.java index 73a1e12..da03601 100644 --- a/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderAlternativesTest.java +++ b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderAlternativesTest.java @@ -22,17 +22,17 @@ import io.silverware.microservices.annotations.Microservice; import io.silverware.microservices.annotations.MicroserviceReference; import io.silverware.microservices.util.BootUtil; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.testng.Assert; import org.testng.annotations.Test; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; import javax.enterprise.event.Observes; import javax.enterprise.inject.Alternative; -import javax.enterprise.inject.spi.BeanManager; import javax.inject.Inject; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; /** * @author Martin Večeřa @@ -52,7 +52,7 @@ public void testQualifiers() throws Exception { CdiMicroserviceProviderTestUtil.waitForBeanManager(bootUtil); - Assert.assertTrue(semaphore.tryAcquire(100, TimeUnit.MINUTES), "Timed-out while waiting for platform startup."); + Assert.assertTrue(semaphore.tryAcquire(1, TimeUnit.MINUTES), "Timed-out while waiting for platform startup."); Assert.assertEquals(result, "alternatealternate"); platform.interrupt(); diff --git a/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderBasicTest.java b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderBasicTest.java index cb94a9c..b998fd6 100644 --- a/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderBasicTest.java +++ b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderBasicTest.java @@ -22,17 +22,17 @@ import io.silverware.microservices.annotations.Microservice; import io.silverware.microservices.annotations.MicroserviceReference; import io.silverware.microservices.util.BootUtil; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.testng.Assert; import org.testng.annotations.Test; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; import javax.annotation.PostConstruct; import javax.enterprise.event.Observes; -import javax.enterprise.inject.spi.BeanManager; import javax.inject.Inject; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; /** * @author Martin Večeřa @@ -58,7 +58,7 @@ public void testCdi() throws Exception { //testMicroserviceB = (TestMicroserviceB) CdiMicroserviceProvider.getMicroserviceProxy(bootUtil.getContext(), TestMicroserviceB.class); - Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.MINUTES), "Timed-out while waiting for platform startup."); + Assert.assertTrue(semaphore.tryAcquire(1, TimeUnit.MINUTES), "Timed-out while waiting for platform startup."); Assert.assertTrue(postConstructCalled); Assert.assertEquals(result, "micrononame"); diff --git a/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderSpecializationTest.java b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderSpecializationTest.java index bc50a0e..428a1b1 100644 --- a/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderSpecializationTest.java +++ b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderSpecializationTest.java @@ -22,22 +22,22 @@ import io.silverware.microservices.annotations.Microservice; import io.silverware.microservices.annotations.MicroserviceReference; import io.silverware.microservices.util.BootUtil; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.testng.Assert; import org.testng.annotations.Test; -import javax.enterprise.event.Observes; -import javax.enterprise.inject.Specializes; -import javax.enterprise.inject.spi.BeanManager; -import javax.inject.Inject; -import javax.inject.Qualifier; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import javax.enterprise.event.Observes; +import javax.enterprise.inject.Specializes; +import javax.inject.Inject; +import javax.inject.Qualifier; /** * @author Martin Večeřa @@ -57,7 +57,7 @@ public void testQualifiers() throws Exception { CdiMicroserviceProviderTestUtil.waitForBeanManager(bootUtil); - Assert.assertTrue(semaphore.tryAcquire(10, TimeUnit.MINUTES), "Timed-out while waiting for platform startup."); + Assert.assertTrue(semaphore.tryAcquire(1, TimeUnit.MINUTES), "Timed-out while waiting for platform startup."); Assert.assertEquals(result, "specialspecial"); platform.interrupt(); diff --git a/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderVersionsLessNumbersTest.java b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderVersionsLessNumbersTest.java new file mode 100644 index 0000000..1f72b07 --- /dev/null +++ b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderVersionsLessNumbersTest.java @@ -0,0 +1,117 @@ +/* + * -----------------------------------------------------------------------\ + * SilverWare + *   + * Copyright (C) 2010 - 2013 the original author or 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 io.silverware.microservices.providers.cdi; + +import io.silverware.microservices.annotations.Microservice; +import io.silverware.microservices.annotations.MicroserviceReference; +import io.silverware.microservices.annotations.MicroserviceVersion; +import io.silverware.microservices.util.BootUtil; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import javax.enterprise.event.Observes; +import javax.inject.Inject; + +/** + * Test for versions with missing minor/patch versions. + * + * @author Slavomir Krupa (slavomir.krupa@gmail.com) + */ +public class CdiMicroserviceProviderVersionsLessNumbersTest { + + private static final Semaphore semaphore = new Semaphore(0); + private static String result = ""; + + @Test + public void testVersionsResolutionAdvanced() throws Exception { + final BootUtil bootUtil = new BootUtil(); + final Thread platform = bootUtil.getMicroservicePlatform(this.getClass().getPackage().getName()); + platform.start(); + + CdiMicroserviceProviderTestUtil.waitForBeanManager(bootUtil); + + Assert.assertTrue(semaphore.tryAcquire(1, TimeUnit.MINUTES), "Timed-out while waiting for platform startup."); + Assert.assertEquals(result, "hello2bye1"); + + platform.interrupt(); + platform.join(); + } + + @Microservice("advanced") + public static class TestVersionMicroserviceLess { + + @Inject + @MicroserviceReference + private HelloVersion2Less micro1; + + @Inject + @MicroserviceReference + private ByeVersion1Less micro2; + + public void eventObserver(@Observes MicroservicesStartedEvent event) { + result += micro1.hello(); + result += micro2.bye(); + semaphore.release(); + } + } + + @MicroserviceVersion(api = "^2") + public interface HelloVersion2Less { + String hello(); + } + + @MicroserviceVersion(api = "~1") + public interface ByeVersion1Less { + String bye(); + } + + @Microservice + @MicroserviceVersion(implementation = "1.6") + public static class Version1LessMicroBeanLess implements HelloVersion2Less, ByeVersion1Less { + + @Override + public String hello() { + return "hello1"; + } + + @Override + public String bye() { + return "bye1"; + } + } + + @Microservice + @MicroserviceVersion(implementation = "2.4-SNAPSHOT") + public static class Version2LessLessMicroBean implements HelloVersion2Less, ByeVersion1Less { + + @Override + public String hello() { + return "hello2"; + } + + @Override + public String bye() { + return "bye2"; + } + } +} \ No newline at end of file diff --git a/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderVersionsTest.java b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderVersionsTest.java new file mode 100644 index 0000000..a48ff3a --- /dev/null +++ b/cdi-microservice-provider/src/test/java/io/silverware/microservices/providers/cdi/CdiMicroserviceProviderVersionsTest.java @@ -0,0 +1,117 @@ +/* + * -----------------------------------------------------------------------\ + * SilverWare + *   + * Copyright (C) 2010 - 2016 the original author or 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 io.silverware.microservices.providers.cdi; + +import io.silverware.microservices.annotations.Microservice; +import io.silverware.microservices.annotations.MicroserviceReference; +import io.silverware.microservices.annotations.MicroserviceVersion; +import io.silverware.microservices.util.BootUtil; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import javax.enterprise.event.Observes; +import javax.inject.Inject; + +/** + * Basic test for versioning. + * + * @author Slavomir Krupa (slavomir.krupa@gmail.com) + */ +public class CdiMicroserviceProviderVersionsTest { + + private static final Semaphore semaphore = new Semaphore(0); + private static String result = ""; + + @Test + public void testBasicVersionResolution() throws Exception { + final BootUtil bootUtil = new BootUtil(); + final Thread platform = bootUtil.getMicroservicePlatform(this.getClass().getPackage().getName()); + platform.start(); + + CdiMicroserviceProviderTestUtil.waitForBeanManager(bootUtil); + + Assert.assertTrue(semaphore.tryAcquire(1, TimeUnit.MINUTES), "Timed-out while waiting for platform startup."); + Assert.assertEquals(result, "hello2bye1"); + + platform.interrupt(); + platform.join(); + } + + @Microservice("basic") + public static class TestVersionMicroservice { + + @Inject + @MicroserviceReference + private HelloVersion2 micro1; + + @Inject + @MicroserviceReference + private ByeVersion1 micro2; + + public void eventObserver(@Observes MicroservicesStartedEvent event) { + result += micro1.hello(); + result += micro2.bye(); + semaphore.release(); + } + } + + @MicroserviceVersion(api = "2.2.2") + public interface HelloVersion2 { + String hello(); + } + + @MicroserviceVersion(api = "1.1.1") + public interface ByeVersion1 { + String bye(); + } + + @Microservice + @MicroserviceVersion(implementation = "1.1.1") + public static class Version1MicroBean implements HelloVersion2, ByeVersion1 { + + @Override + public String hello() { + return "hello1"; + } + + @Override + public String bye() { + return "bye1"; + } + } + + @Microservice + @MicroserviceVersion(implementation = "2.2.2") + public static class Version2MicroBean implements HelloVersion2, ByeVersion1 { + + @Override + public String hello() { + return "hello2"; + } + + @Override + public String bye() { + return "bye2"; + } + } +} \ No newline at end of file diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/ClusterMicroserviceProvider.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/ClusterMicroserviceProvider.java index 4cd5726..99ecae9 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/ClusterMicroserviceProvider.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/ClusterMicroserviceProvider.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,18 +19,24 @@ */ package io.silverware.microservices.providers.cluster; +import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.INITIALIZATION_ERROR; +import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.JGROUPS_ERROR; +import static java.util.Collections.emptySet; + import io.silverware.microservices.Context; import io.silverware.microservices.MicroserviceMetaData; import io.silverware.microservices.providers.MicroserviceProvider; -import io.silverware.microservices.providers.cluster.internal.FutureListenerHelper; import io.silverware.microservices.providers.cluster.internal.JgroupsMessageReceiver; import io.silverware.microservices.providers.cluster.internal.JgroupsMessageSender; import io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException; import io.silverware.microservices.providers.cluster.internal.message.KnownImplementation; import io.silverware.microservices.providers.cluster.internal.message.response.MicroserviceSearchResponse; +import io.silverware.microservices.providers.cluster.internal.util.FutureListenerHelper; import io.silverware.microservices.silver.ClusterSilverService; import io.silverware.microservices.silver.cluster.RemoteServiceHandlesStore; import io.silverware.microservices.silver.cluster.ServiceHandle; + +import com.google.common.base.Stopwatch; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jgroups.Address; @@ -48,11 +54,9 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.INITIALIZATION_ERROR; -import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.JGROUPS_ERROR; -import static java.util.Collections.emptySet; - /** + * This provider provides a remote method invocation via JGroups. + * * @author Slavomir Krupa (slavomir.krupa@gmail.com) * @author Martin Večeřa */ @@ -62,20 +66,20 @@ public class ClusterMicroserviceProvider implements MicroserviceProvider, Cluste private Context context; private RemoteServiceHandlesStore remoteServiceHandlesStore; - private Map> alreadyQueriedAdresses = new HashMap<>(); + private Map> alreadyQueriedAddresses = new HashMap<>(); private JgroupsMessageSender sender; private MessageDispatcher messageDispatcher; private Long timeout = 500L; - @Override public void initialize(final Context context) { try { + final Stopwatch stopwatch = Stopwatch.createStarted(); // do some basic initialization this.context = context; this.remoteServiceHandlesStore = context.getRemoteServiceHandlesStore(); - this.alreadyQueriedAdresses = new HashMap<>(); + this.alreadyQueriedAddresses = new HashMap<>(); context.getProperties().putIfAbsent(CLUSTER_GROUP, "SilverWare"); context.getProperties().putIfAbsent(CLUSTER_CONFIGURATION, "udp.xml"); context.getProperties().putIfAbsent(CLUSTER_LOOKUP_TIMEOUT, timeout); @@ -92,6 +96,8 @@ public void initialize(final Context context) { log.info("Setting cluster group: {} ", clusterGroup); channel.connect(clusterGroup); receiver.setMyAddress(channel.getAddress()); + stopwatch.stop(); + log.info("Initialization of ClusterMicroserviceProvider took {} ms. ", stopwatch.elapsed(TimeUnit.MILLISECONDS)); } catch (Exception e) { log.error("Cluster microservice initialization failed.", e); throw new SilverWareClusteringException(INITIALIZATION_ERROR, e); @@ -124,31 +130,33 @@ public void run() { @Override public Set lookupMicroservice(final MicroserviceMetaData metaData) { try { - Set
addressesForMetadata = alreadyQueriedAdresses.getOrDefault(metaData, new HashSet<>()); + Set
addressesForMetadata = alreadyQueriedAddresses.getOrDefault(metaData, new HashSet<>()); this.sender.sendToClusterAsync(metaData, addressesForMetadata, - new FutureListenerHelper(rspList -> { - try { - RspList responseRspList = rspList.get(10, TimeUnit.SECONDS); - if (log.isTraceEnabled()) { - log.trace("Response retrieved! {}", responseRspList); - } - Collection> result = responseRspList.values(); - if (log.isTraceEnabled()) { - log.trace("Size of a responses is : {} ", responseRspList.getResults().size()); - } - Set remoteServiceHandles = result.stream() - .filter(rsp -> rsp.wasReceived() && rsp.getValue().getResult().canBeUsed()) - .map((rsp) -> new RemoteServiceHandle(rsp.getSender(), rsp.getValue().getHandle(), sender, metaData)) - .collect(Collectors.toSet()); - // this is to save jgroups traffic for a given metadata - addressesForMetadata.addAll(responseRspList.values().stream().map(Rsp::getSender).collect(Collectors.toSet())); - alreadyQueriedAdresses.put(metaData, addressesForMetadata); - this.remoteServiceHandlesStore.addHandles(metaData, remoteServiceHandles); - } catch (Throwable e) { - log.error("Error while looking up microservices.", e); - } - - })); + new FutureListenerHelper(rspList -> { + try { + RspList responseRspList = rspList.get(10, TimeUnit.SECONDS); + if (log.isTraceEnabled()) { + log.trace("Response retrieved! {}", responseRspList); + } + Collection> result = responseRspList.values(); + if (log.isTraceEnabled()) { + log.trace("Size of a responses is : {} ", responseRspList.getResults().size()); + } + result.stream().filter(Rsp::hasException).forEach(rsp -> log.error("Exception was thrown during lookup on node: " + rsp.getSender(), rsp.getException())); + + Set remoteServiceHandles = result.stream() + .filter(rsp -> rsp.wasReceived() && !rsp.hasException() && rsp.getValue().getResult().canBeUsed()) + .map((rsp) -> new RemoteServiceHandle(rsp.getSender(), rsp.getValue().getHandle(), sender, metaData)) + .collect(Collectors.toSet()); + // this is to save jgroups traffic for a given metadata + addressesForMetadata.addAll(responseRspList.values().stream().map(Rsp::getSender).collect(Collectors.toSet())); + alreadyQueriedAddresses.put(metaData, addressesForMetadata); + this.remoteServiceHandlesStore.addHandles(metaData, remoteServiceHandles); + } catch (Throwable e) { + log.error("Error while looking up microservices.", e); + } + + })); // If this is first query for the metadata we should wait for a response if (addressesForMetadata.isEmpty()) { Thread.sleep(timeout); @@ -166,5 +174,4 @@ public Set lookupLocalMicroservice(final MicroserviceMetaData metaData) return emptySet(); } - } \ No newline at end of file diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/RemoteServiceHandle.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/RemoteServiceHandle.java index 02b8434..5238562 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/RemoteServiceHandle.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/RemoteServiceHandle.java @@ -29,11 +29,14 @@ import io.silverware.microservices.silver.cluster.ServiceHandle; import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.jgroups.Address; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.INVOCATION_EXCEPTION; import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.PROCESSING_ERROR; /** @@ -43,6 +46,8 @@ */ public class RemoteServiceHandle implements ServiceHandle, MethodHandler { + private static final Logger log = LogManager.getLogger(ClusterMicroserviceProvider.class); + private final Address address; private final int handle; private final JgroupsMessageSender sender; @@ -91,9 +96,16 @@ public Object invoke(Context context, String method, Class[] paramTypes, Object[ return type; } Invocation invocation = new Invocation(handle, method, paramTypes, params); - MicroserviceRemoteCallResponse response = sender.sendToAddressSync(address, new MicroserviceRemoteCallRequest(invocation)); - return response.getMessageCallResult(); - + try { + MicroserviceRemoteCallResponse response = sender.sendToAddressSync(address, new MicroserviceRemoteCallRequest(invocation)); + return response.getMessageCallResult(); + } catch (SilverWareClusteringException e) { + log.error(e); + if (e.getReason() == INVOCATION_EXCEPTION) { + throw (Exception) e.getCause(); + } + throw e; + } } diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/HttpServiceProxy.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/HttpServiceProxy.java index 411582d..88db2b5 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/HttpServiceProxy.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/HttpServiceProxy.java @@ -22,6 +22,7 @@ import io.silverware.microservices.Context; import io.silverware.microservices.silver.cluster.LocalServiceHandle; import io.silverware.microservices.silver.cluster.ServiceHandle; + import javassist.util.proxy.MethodHandler; import javassist.util.proxy.ProxyFactory; @@ -51,19 +52,19 @@ private HttpServiceProxy(final Context context, final ServiceHandle serviceHandl public static T getProxy(final Context context, final LocalServiceHandle serviceHandle) { try { ProxyFactory factory = new ProxyFactory(); - if (serviceHandle.getQuery().getType().isInterface()) { - factory.setInterfaces(new Class[] { serviceHandle.getQuery().getType() }); + if (serviceHandle.getMetaData().getType().isInterface()) { + factory.setInterfaces(new Class[]{serviceHandle.getMetaData().getType()}); } else { - factory.setSuperclass(serviceHandle.getQuery().getType()); + factory.setSuperclass(serviceHandle.getMetaData().getType()); } return (T) factory.create(new Class[0], new Object[0], new HttpServiceProxy(context, serviceHandle)); } catch (Exception e) { - throw new IllegalStateException("Cannot create Http proxy for class " + serviceHandle.getQuery().getType().getName() + ": ", e); + throw new IllegalStateException("Cannot create Http proxy for class " + serviceHandle.getMetaData().getType().getName() + ": ", e); } } @Override public Object invoke(final Object o, final Method method, final Method method1, final Object[] objects) throws Throwable { - return serviceHandle.invoke(context, method.getName(),method.getParameterTypes(), objects); + return serviceHandle.invoke(context, method.getName(), method.getParameterTypes(), objects); } } diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageReceiver.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageReceiver.java index bc7154c..18fe8bf 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageReceiver.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageReceiver.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,9 +19,14 @@ */ package io.silverware.microservices.providers.cluster.internal; +import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.PROCESSING_ERROR; +import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.RECIPIENT_SAME_AS_SENDER; +import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.UNEXPECTED_CONTENT; + import io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException; import io.silverware.microservices.providers.cluster.internal.message.responder.Responder; import io.silverware.microservices.silver.cluster.RemoteServiceHandlesStore; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jgroups.Address; @@ -35,10 +40,6 @@ import java.util.Set; import java.util.stream.Collectors; -import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.PROCESSING_ERROR; -import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.RECIPIENT_SAME_AS_SENDER; -import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.UNEXPECTED_CONTENT; - /** * Class responsible for retrieving messages * @@ -87,7 +88,6 @@ public void viewAccepted(final View view) { log.info("Cluster view change: " + view); } - @Override public Object handle(Message msg) throws Exception { if (msg.getSrc() != null && msg.getSrc().equals(myAddress)) { diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageSender.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageSender.java index c26ec83..695d923 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageSender.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageSender.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,11 +47,9 @@ public class JgroupsMessageSender { */ private static final Logger log = LogManager.getLogger(JgroupsMessageSender.class); - private static final RequestOptions SYNC_OPTIONS = RequestOptions.SYNC(); private static final RequestOptions ASYNC_OPTIONS = RequestOptions.ASYNC(); - private final MessageDispatcher dispatcher; private Set
filteredAdresses; @@ -67,8 +65,6 @@ private Set
getFilteredAdresses() { this.filteredAdresses = new HashSet<>(); // add my address filteredAdresses.add(this.dispatcher.getChannel().getAddress()); - // add cluster address - filteredAdresses.add(this.dispatcher.getChannel().getView().getCreator()); } return this.filteredAdresses; } @@ -76,7 +72,8 @@ private Set
getFilteredAdresses() { /** * Send multicast message to all nodes in cluster * - * @param content content of message + * @param content + * content of message */ public RspList sendToClusterSync(Serializable content) throws Exception { return this.dispatcher.castMessage(getMembersAdresses(), new Message(null, content), SYNC_OPTIONS); @@ -85,8 +82,10 @@ public RspList sendToClusterSync(Serializable content) throws Exception { /** * Send async multicast message to all nodes in cluster * - * @param content content of message - * @param listener listener which will be called when result will be available + * @param content + * content of message + * @param listener + * listener which will be called when result will be available */ public void sendToClusterAsync(Serializable content, Set
addressesToSkip, FutureListener> listener) throws Exception { List
othertMembersAdresses = getOthertMembersAdresses().stream().filter(address -> !addressesToSkip.contains(address)).collect(Collectors.toList()); @@ -102,8 +101,10 @@ public void sendToClusterAsync(Serializable content, Set
addressesT /** * Send async multicast message to all nodes in cluster * - * @param content content of message - * @param listener listener which will be called when result will be available + * @param content + * content of message + * @param listener + * listener which will be called when result will be available */ public void sendToClusterAsync(Serializable content, FutureListener> listener) throws Exception { sendToClusterAsync(content, Collections.emptySet(), listener); @@ -121,7 +122,8 @@ private List
getOthertMembersAdresses() { /** * Send unicast message for specific address * - * @param content content of message + * @param content + * content of message */ public void sendToAddressAsync(Address address, Serializable content) throws Exception { this.dispatcher.sendMessage(new Message(address, Util.objectToByteBuffer(content)), ASYNC_OPTIONS); @@ -130,11 +132,11 @@ public void sendToAddressAsync(Address address, Serializable content) throws Exc /** * Send unicast message for specific address * - * @param content content of message + * @param content + * content of message */ public T sendToAddressSync(Address address, Serializable content) throws Exception { return this.dispatcher.sendMessage(new Message(address, Util.objectToByteBuffer(content)), SYNC_OPTIONS); } - } diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/exception/SilverWareClusteringException.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/exception/SilverWareClusteringException.java index e685136..cc81cd2 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/exception/SilverWareClusteringException.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/exception/SilverWareClusteringException.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -74,9 +74,9 @@ public UUID getId() { @Override public String toString() { return "SilverWareClusteringException{" + - "reason=" + reason + - ", id=" + id + - ", super=" + super.toString() + - '}'; + "reason=" + reason + + ", id=" + id + + ", super=" + super.toString() + + '}'; } } diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/KnownImplementation.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/KnownImplementation.java index 5e959fe..98bc7a5 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/KnownImplementation.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/KnownImplementation.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -43,7 +43,6 @@ public enum KnownImplementation { MICROSERVICE_REMOTE_CALL(MicroserviceRemoteCallResponse.class, MicroserviceRemoteCallRequest.class, MicroServiceRemoteCallResponder.class, MicroServiceRemoteCallResponder::new), MICROSERVICE_REMOTE_SEARCH(MicroserviceSearchResponse.class, MicroserviceMetaData.class, MicroserviceSearchResponder.class, MicroserviceSearchResponder::new); - private final Class responseClass; private final Class messageClass; private final Class responderClass; @@ -69,7 +68,6 @@ public Class getResponderClass() { return responderClass; } - public static Map initializeReponders(Context context) { return KNOWN_IMPLEMENTATIONS.stream().collect(Collectors.toMap(KnownImplementation::getMessageClass, v -> v.responderFactory.apply(context))); } diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/request/MicroserviceRemoteCallRequest.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/request/MicroserviceRemoteCallRequest.java index c65d79e..1fd5b1b 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/request/MicroserviceRemoteCallRequest.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/request/MicroserviceRemoteCallRequest.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/request/RequestMessage.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/request/RequestMessage.java index 558f126..5337085 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/request/RequestMessage.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/request/RequestMessage.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/AbstractResponder.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/AbstractResponder.java index ca940c3..2d1af1a 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/AbstractResponder.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/AbstractResponder.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ package io.silverware.microservices.providers.cluster.internal.message.responder; import io.silverware.microservices.Context; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jgroups.Address; @@ -28,8 +29,10 @@ /** * Provides basic functionality and logging of messages. * - * @param message content type - * @param message response type + * @param + * message content type + * @param + * message response type * @author Slavomír Krupa (slavomir.krupa@gmail.com) */ public abstract class AbstractResponder implements Responder { @@ -40,7 +43,6 @@ public abstract class AbstractResponder implements Responder { protected static Logger log = LogManager.getLogger(AbstractResponder.class); protected Context context; - public AbstractResponder(Context context) { this.context = context; @@ -48,7 +50,9 @@ public AbstractResponder(Context context) { @Override public final R processMessage(Message msg) { - log.trace("Processing msg: " + msg); + if (log.isDebugEnabled()) { + log.debug("Processing msg: " + msg); + } return doProcessMessage(msg.getSrc(), (C) msg.getObject()); } diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/MicroServiceRemoteCallResponder.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/MicroServiceRemoteCallResponder.java index c184b6e..8621853 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/MicroServiceRemoteCallResponder.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/MicroServiceRemoteCallResponder.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,13 @@ */ package io.silverware.microservices.providers.cluster.internal.message.responder; +import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.INVOCATION_EXCEPTION; + import io.silverware.microservices.Context; import io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException; -import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.INVOCATION_EXCEPTION; import io.silverware.microservices.providers.cluster.internal.message.request.MicroserviceRemoteCallRequest; import io.silverware.microservices.providers.cluster.internal.message.response.MicroserviceRemoteCallResponse; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jgroups.Address; diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/MicroserviceSearchResponder.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/MicroserviceSearchResponder.java index 2e11fea..5e2e5f2 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/MicroserviceSearchResponder.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/MicroserviceSearchResponder.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,17 +19,20 @@ */ package io.silverware.microservices.providers.cluster.internal.message.responder; +import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.MULTIPLE_IMPLEMENTATIONS_FOUND; + import io.silverware.microservices.Context; import io.silverware.microservices.MicroserviceMetaData; import io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException; -import static io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException.SilverWareClusteringError.MULTIPLE_IMPLEMENTATIONS_FOUND; import io.silverware.microservices.providers.cluster.internal.message.response.MicroserviceSearchResponse; import io.silverware.microservices.silver.cluster.LocalServiceHandle; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jgroups.Address; import java.util.List; +import java.util.stream.Collectors; /** * This class is responsible for retrieving correct microservices @@ -43,26 +46,32 @@ public class MicroserviceSearchResponder extends AbstractResponder serviceHandles = context.assureHandles(metaData); + MicroserviceSearchResponse doProcessMessage(Address source, MicroserviceMetaData query) { + List serviceHandles = filterVersionCompatible(context.assureHandles(query), query); + if (serviceHandles.size() > 1) { log.error("Multiple implementations found."); throw new SilverWareClusteringException(MULTIPLE_IMPLEMENTATIONS_FOUND); } if (serviceHandles.isEmpty()) { - log.trace("No services found for metadata: {} ", metaData); + if (log.isTraceEnabled()) { + log.trace("No services found for metadata: {} ", query); + } return new MicroserviceSearchResponse(null, MicroserviceSearchResponse.Result.NOT_FOUND); - } else { - log.trace("{} services found for {}", serviceHandles.size(), metaData); - return new MicroserviceSearchResponse(serviceHandles.get(0).getHandle(), MicroserviceSearchResponse.Result.FOUND); + } else if (log.isTraceEnabled()) { + log.trace("{} services found for {}", serviceHandles.size(), query); } + return new MicroserviceSearchResponse(serviceHandles.get(0).getHandle(), MicroserviceSearchResponse.Result.FOUND); + + } + private List filterVersionCompatible(List localServiceHandles, MicroserviceMetaData query) { + return localServiceHandles.stream().filter(handle -> handle.getMetaData().satisfies(query)).collect(Collectors.toList()); } } diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/Responder.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/Responder.java index f724ef0..ffc4cef 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/Responder.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/responder/Responder.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,7 +24,8 @@ /** * Interface specifying processor class for responses * - * @param response class + * @param + * response class * @author Slavomír Krupa (slavomir.krupa@gmail.com) */ public interface Responder { diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/MicroserviceRemoteCallResponse.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/MicroserviceRemoteCallResponse.java index b042dcf..0a370f4 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/MicroserviceRemoteCallResponse.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/MicroserviceRemoteCallResponse.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/MicroserviceSearchResponse.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/MicroserviceSearchResponse.java index b8a05f9..ca4ad25 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/MicroserviceSearchResponse.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/MicroserviceSearchResponse.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/ResponseMessage.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/ResponseMessage.java index 6728067..53c2594 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/ResponseMessage.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/message/response/ResponseMessage.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/FutureListenerHelper.java b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/util/FutureListenerHelper.java similarity index 91% rename from cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/FutureListenerHelper.java rename to cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/util/FutureListenerHelper.java index 4d71992..c10b1b6 100644 --- a/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/FutureListenerHelper.java +++ b/cluster-microservice-provider/src/main/java/io/silverware/microservices/providers/cluster/internal/util/FutureListenerHelper.java @@ -17,9 +17,10 @@ * limitations under the License. * -----------------------------------------------------------------------/ */ -package io.silverware.microservices.providers.cluster.internal; +package io.silverware.microservices.providers.cluster.internal.util; import io.silverware.microservices.providers.cluster.internal.message.response.MicroserviceSearchResponse; + import org.jgroups.util.FutureListener; import org.jgroups.util.RspList; @@ -33,7 +34,7 @@ * @author Slavomír Krupa (slavomir.krupa@gmail.com) */ public class FutureListenerHelper implements FutureListener> { - private Consumer>> consumer; + private final Consumer>> consumer; public FutureListenerHelper(Consumer>> consumer) { this.consumer = consumer; diff --git a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/ClusterMicroserviceProviderTest.java b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/ClusterMicroserviceProviderTest.java index f55de9c..83fb61c 100644 --- a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/ClusterMicroserviceProviderTest.java +++ b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/ClusterMicroserviceProviderTest.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,15 +19,14 @@ */ package io.silverware.microservices.providers.cluster; -import io.silverware.microservices.providers.cluster.internal.JgroupsMessageSender; import static io.silverware.microservices.providers.cluster.internal.RemoteServiceHandleStoreTest.META_DATA; +import static org.assertj.core.api.Assertions.assertThat; + +import io.silverware.microservices.providers.cluster.internal.JgroupsMessageSender; import io.silverware.microservices.providers.cluster.internal.message.response.MicroserviceSearchResponse; import io.silverware.microservices.silver.cluster.RemoteServiceHandlesStore; import io.silverware.microservices.silver.cluster.ServiceHandle; -import mockit.Expectations; -import mockit.Injectable; -import mockit.Tested; -import static org.assertj.core.api.Assertions.assertThat; + import org.jgroups.Address; import org.jgroups.util.FutureListener; import org.jgroups.util.RspList; @@ -35,9 +34,14 @@ import java.util.Set; +import mockit.Expectations; +import mockit.Injectable; +import mockit.Tested; + /** * Test for ClusterMicroserviceProvider - * @author Slavomír Krupa (slavomir.krupa@gmail.com) + * + * @author Slavomír Krupa (slavomir.krupa@gmail.com) */ public class ClusterMicroserviceProviderTest { @@ -50,20 +54,18 @@ public class ClusterMicroserviceProviderTest { @Injectable private JgroupsMessageSender sender; - @Test public void testLookupMicroservice() throws Exception { Set mockHandles = Util.createSetFrom(Util.createHandle("1"), Util.createHandle("2")); Set services = Util.createSetFrom(new Object(), new Object()); - new Expectations() {{ sender.sendToClusterAsync(META_DATA, (Set
) any, (FutureListener>) any); times = 1; result = mockHandles; // TODO: 9/9/16 test this again -// store.addHandles(META_DATA, mockHandles); -// times = 1; + // store.addHandles(META_DATA, mockHandles); + // times = 1; store.getServices(META_DATA); result = services; times = 1; @@ -77,8 +79,8 @@ public void testLookupMicroservice() throws Exception { public void testLookupLocalMicroservice() throws Exception { Set objects = clusterMicroserviceProvider.lookupLocalMicroservice(META_DATA); assertThat(objects) - .isNotNull() - .isEmpty(); + .isNotNull() + .isEmpty(); } } \ No newline at end of file diff --git a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/Util.java b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/Util.java index 90cf5f7..775e0ba 100644 --- a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/Util.java +++ b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/Util.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -40,5 +40,4 @@ public static Set createSetFrom(T... components) { return new HashSet<>(Arrays.asList(components)); } - } diff --git a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageReceiverTest.java b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageReceiverTest.java index 45c5ee2..eb03099 100644 --- a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageReceiverTest.java +++ b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageReceiverTest.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,12 +19,12 @@ */ package io.silverware.microservices.providers.cluster.internal; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + import io.silverware.microservices.providers.cluster.internal.exception.SilverWareClusteringException; import io.silverware.microservices.providers.cluster.internal.message.responder.Responder; import io.silverware.microservices.silver.cluster.RemoteServiceHandlesStore; -import mockit.Capturing; -import mockit.Verifications; -import static org.assertj.core.api.Assertions.assertThatThrownBy; + import org.jgroups.Message; import org.jgroups.blocks.MessageDispatcher; import org.testng.annotations.BeforeMethod; @@ -33,6 +33,9 @@ import java.util.HashMap; import java.util.UUID; +import mockit.Capturing; +import mockit.Verifications; + /** * Test for a receiver * @@ -54,7 +57,6 @@ public class JgroupsMessageReceiverTest { @BeforeMethod public void setUp() throws Exception { - } @Test @@ -78,7 +80,6 @@ public void testAddResponder() throws Exception { }}; } - @Test public void testReceiveWithUnknownClassThrowsException() throws Exception { HashMap classResponderHashMap = generateRespondersMap(); diff --git a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageSenderTest.java b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageSenderTest.java index 210d992..02e3dda 100644 --- a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageSenderTest.java +++ b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/JgroupsMessageSenderTest.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,12 +19,9 @@ */ package io.silverware.microservices.providers.cluster.internal; -import mockit.Capturing; -import mockit.Deencapsulation; -import mockit.Expectations; -import mockit.Verifications; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; + import org.jgroups.Address; import org.jgroups.Message; import org.jgroups.blocks.MessageDispatcher; @@ -37,6 +34,11 @@ import java.util.List; import java.util.UUID; +import mockit.Capturing; +import mockit.Deencapsulation; +import mockit.Expectations; +import mockit.Verifications; + /** * Test for JgroupsMessageSender * @@ -44,7 +46,6 @@ */ public class JgroupsMessageSenderTest { - @Capturing private MessageDispatcher dispatcher; private JgroupsMessageSender jgroupsMessageSender; @@ -112,5 +113,4 @@ public void testSendToAddressSync() throws Exception { } - } diff --git a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/RemoteServiceHandleStoreTest.java b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/RemoteServiceHandleStoreTest.java index cc8dba3..654ad85 100644 --- a/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/RemoteServiceHandleStoreTest.java +++ b/cluster-microservice-provider/src/test/java/io/silverware/microservices/providers/cluster/internal/RemoteServiceHandleStoreTest.java @@ -2,7 +2,7 @@ * -----------------------------------------------------------------------\ * SilverWare *   - * Copyright (C) 2010 - 2013 the original author or authors. + * Copyright (C) 2010 - 2016 the original author or authors. *   * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,11 +19,14 @@ */ package io.silverware.microservices.providers.cluster.internal; +import static org.assertj.core.api.Assertions.assertThat; + import io.silverware.microservices.MicroserviceMetaData; import io.silverware.microservices.providers.cluster.Util; import io.silverware.microservices.silver.cluster.LocalServiceHandle; import io.silverware.microservices.silver.cluster.RemoteServiceHandlesStore; import io.silverware.microservices.silver.cluster.ServiceHandle; + import org.testng.annotations.Test; import java.lang.annotation.Annotation; @@ -31,21 +34,19 @@ import java.util.HashSet; import java.util.Set; -import static org.assertj.core.api.Assertions.assertThat; - /** * Basic Unit tests for remote handles store * * @author Slavomír Krupa (slavomir.krupa@gmail.com) */ public class RemoteServiceHandleStoreTest { + private static final String VERSION = "1.0.0"; private static final Set ANNOTATIONS = new HashSet<>(Arrays.asList(RemoteServiceHandleStoreTest.class.getClass().getAnnotations())); - public static final MicroserviceMetaData META_DATA = new MicroserviceMetaData(RemoteServiceHandleStoreTest.class.getName(), RemoteServiceHandleStoreTest.class, ANNOTATIONS, ANNOTATIONS); + public static final MicroserviceMetaData META_DATA = new MicroserviceMetaData(RemoteServiceHandleStoreTest.class.getName(), RemoteServiceHandleStoreTest.class, ANNOTATIONS, ANNOTATIONS, VERSION, VERSION); public static final LocalServiceHandle SERVICE_HANDLE = Util.createHandle("host"); - @Test public void addSingleHandle() { RemoteServiceHandlesStore store = new RemoteServiceHandlesStore(); diff --git a/http-invoker-microservice-provider/src/test/java/io/silverware/microservices/providers/http/invoker/HttpInvokerMicroserviceProviderTest.java b/http-invoker-microservice-provider/src/test/java/io/silverware/microservices/providers/http/invoker/HttpInvokerMicroserviceProviderTest.java index 521a06c..cde4b7b 100644 --- a/http-invoker-microservice-provider/src/test/java/io/silverware/microservices/providers/http/invoker/HttpInvokerMicroserviceProviderTest.java +++ b/http-invoker-microservice-provider/src/test/java/io/silverware/microservices/providers/http/invoker/HttpInvokerMicroserviceProviderTest.java @@ -1,7 +1,5 @@ package io.silverware.microservices.providers.http.invoker; -import com.cedarsoftware.util.io.JsonReader; -import com.cedarsoftware.util.io.JsonWriter; import io.silverware.microservices.MicroserviceMetaData; import io.silverware.microservices.annotations.Microservice; import io.silverware.microservices.providers.cdi.CdiMicroserviceProvider; @@ -13,6 +11,9 @@ import io.silverware.microservices.silver.cluster.LocalServiceHandle; import io.silverware.microservices.util.BootUtil; import io.silverware.microservices.util.Utils; + +import com.cedarsoftware.util.io.JsonReader; +import com.cedarsoftware.util.io.JsonWriter; import org.testng.Assert; import org.testng.annotations.Test; @@ -31,6 +32,7 @@ * @author Martin Večeřa */ public class HttpInvokerMicroserviceProviderTest { + private static final String VERSION = "1.0.0"; private HttpInvokerSilverService httpInvokerSilverService = null; @@ -60,7 +62,7 @@ public void testHttpInvoker() throws Exception { con.setDoOutput(true); con.connect(); - final MicroserviceMetaData metaData = new MicroserviceMetaData("sumService", SumService.class, Collections.emptySet()); + final MicroserviceMetaData metaData = new MicroserviceMetaData("sumService", SumService.class, Collections.emptySet(), Collections.emptySet(), VERSION, VERSION); JsonWriter jsonWriter = new JsonWriter(con.getOutputStream()); jsonWriter.write(metaData); @@ -72,7 +74,7 @@ public void testHttpInvoker() throws Exception { con.disconnect(); final LocalServiceHandle handle = handles.get(0); - long l = (Long) handle.invoke(bootUtil.getContext(), "sum", new Class[] {short.class, int.class}, new Object[] {(short) 3, 4}); + long l = (Long) handle.invoke(bootUtil.getContext(), "sum", new Class[] { short.class, int.class }, new Object[] { (short) 3, 4 }); Assert.assertEquals(l, 7L); con = (HttpURLConnection) new URL(urlBase + "invoke").openConnection(); @@ -81,7 +83,7 @@ public void testHttpInvoker() throws Exception { con.setDoOutput(true); con.connect(); - Invocation invocation = new Invocation(handles.get(0).getHandle(), "sum", new Class[] {short.class, int.class}, new Object[] {(short) 3, 4}); + Invocation invocation = new Invocation(handles.get(0).getHandle(), "sum", new Class[] { short.class, int.class }, new Object[] { (short) 3, 4 }); jsonWriter = new JsonWriter(con.getOutputStream()); jsonWriter.write(invocation); jsonReader = new JsonReader(con.getInputStream()); @@ -97,7 +99,7 @@ public void testHttpInvoker() throws Exception { con.setDoOutput(true); con.connect(); - invocation = new Invocation(handles.get(0).getHandle(), "allTypes", new Class[] {byte.class, short.class, int.class, long.class, float.class, double.class, boolean.class, char.class}, new Object[] {Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, Float.MIN_VALUE, Double.MIN_VALUE, true, 'c'}); + invocation = new Invocation(handles.get(0).getHandle(), "allTypes", new Class[] { byte.class, short.class, int.class, long.class, float.class, double.class, boolean.class, char.class }, new Object[] { Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, Float.MIN_VALUE, Double.MIN_VALUE, true, 'c' }); jsonWriter = new JsonWriter(con.getOutputStream()); jsonWriter.write(invocation); @@ -114,7 +116,7 @@ public void testHttpInvoker() throws Exception { con.setDoOutput(true); con.connect(); - invocation = new Invocation(handles.get(0).getHandle(), "allTypes2", new Class[] {Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Boolean.class, Character.class}, new Object[] {Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, Float.MIN_VALUE, Double.MIN_VALUE, true, 'c'}); + invocation = new Invocation(handles.get(0).getHandle(), "allTypes2", new Class[] { Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Boolean.class, Character.class }, new Object[] { Byte.MAX_VALUE, Short.MAX_VALUE, Integer.MAX_VALUE, Long.MAX_VALUE, Float.MIN_VALUE, Double.MIN_VALUE, true, 'c' }); jsonWriter = new JsonWriter(con.getOutputStream()); jsonWriter.write(invocation); @@ -133,7 +135,7 @@ public void testHttpInvoker() throws Exception { MagicBox box = new MagicBox(); - invocation = new Invocation(handles.get(0).getHandle(), "doMagic", new Class[] {MagicBox.class}, new Object[] {box}); + invocation = new Invocation(handles.get(0).getHandle(), "doMagic", new Class[] { MagicBox.class }, new Object[] { box }); jsonWriter = new JsonWriter(con.getOutputStream()); jsonWriter.write(invocation); diff --git a/microservices-bom/pom.xml b/microservices-bom/pom.xml index 3d39623..4a1e06c 100644 --- a/microservices-bom/pom.xml +++ b/microservices-bom/pom.xml @@ -76,6 +76,7 @@ 1.8 3.5.2 3.0.17.Final + 2.0.1 1.8 @@ -350,6 +351,11 @@ resteasy-client ${version.org.jboss.resteasy} + + com.vdurmont + semver4j + ${version.sem.ver} + diff --git a/microservices/pom.xml b/microservices/pom.xml index 591bde7..ccf31c3 100644 --- a/microservices/pom.xml +++ b/microservices/pom.xml @@ -21,6 +21,15 @@ com.cedarsoftware json-io + + com.vdurmont + semver4j + + + org.assertj + assertj-core + test + diff --git a/microservices/src/main/java/io/silverware/microservices/Context.java b/microservices/src/main/java/io/silverware/microservices/Context.java index 0034e27..3a1a8ec 100644 --- a/microservices/src/main/java/io/silverware/microservices/Context.java +++ b/microservices/src/main/java/io/silverware/microservices/Context.java @@ -25,6 +25,7 @@ import io.silverware.microservices.silver.SilverService; import io.silverware.microservices.silver.cluster.LocalServiceHandle; import io.silverware.microservices.silver.cluster.RemoteServiceHandlesStore; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -204,7 +205,7 @@ public Set getAllProviders(final Class c * @return A list of {@link LocalServiceHandle Service Handles} that meet the specified query. */ public List assureHandles(final MicroserviceMetaData metaData) { - List result = inboundHandles.stream().filter(serviceHandle -> serviceHandle.getQuery().equals(metaData)).collect(Collectors.toList()); + List result = inboundHandles.stream().filter(serviceHandle -> serviceHandle.getMetaData().equals(metaData)).collect(Collectors.toList()); Set microservices = lookupLocalMicroservice(metaData); Set haveHandles = result.stream().map(LocalServiceHandle::getProxy).collect(Collectors.toSet()); microservices.removeAll(haveHandles); diff --git a/microservices/src/main/java/io/silverware/microservices/MicroserviceMetaData.java b/microservices/src/main/java/io/silverware/microservices/MicroserviceMetaData.java index f0781a5..5000573 100644 --- a/microservices/src/main/java/io/silverware/microservices/MicroserviceMetaData.java +++ b/microservices/src/main/java/io/silverware/microservices/MicroserviceMetaData.java @@ -19,18 +19,18 @@ */ package io.silverware.microservices; -import com.cedarsoftware.util.io.JsonReader; -import com.cedarsoftware.util.io.JsonWriter; import io.silverware.microservices.silver.HttpInvokerSilverService; import io.silverware.microservices.silver.cluster.ServiceHandle; -import io.silverware.microservices.util.Utils; +import io.silverware.microservices.util.VersionComparator; + +import com.cedarsoftware.util.io.JsonReader; +import com.cedarsoftware.util.io.JsonWriter; import java.io.Serializable; import java.lang.annotation.Annotation; import java.net.HttpURLConnection; import java.net.URL; import java.util.Arrays; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -64,7 +64,7 @@ public final class MicroserviceMetaData implements Serializable { /** * Microservice specification version. */ - private final String specVersion; + private final String apiVersion; /** * Microservice implementation version. @@ -75,72 +75,24 @@ public final class MicroserviceMetaData implements Serializable { * Create a representation of a discovered Microservice. * * @param name - * The name of the discovered Microservice. - * @param type - * The type of the discovered Microservice. - * @param qualifiers - * The qualifiers of the discovered Microservice. - * @param annotations - * The annotations of the discovered Microservice. - */ - public MicroserviceMetaData(final String name, final Class type, final Set qualifiers, final Set annotations) { - this.name = name; - this.type = type; - this.qualifiers = qualifiers; - this.annotations = annotations; - this.specVersion = Utils.getClassSpecVersion(type); - this.implVersion = Utils.getClassImplVersion(type); - - if (name == null || type == null) { - throw new IllegalStateException("Name and type fields cannot be null."); - } - } - - /** - * Create a representation of a discovered Microservice. - * - * @param name - * The name of the discovered Microservice. + * The name of the discovered Microservice. * @param type - * The type of the discovered Microservice. + * The type of the discovered Microservice. * @param qualifiers - * The qualifiers of the discovered Microservice. - */ - public MicroserviceMetaData(final String name, final Class type, final Set qualifiers) { - this.name = name; - this.type = type; - this.qualifiers = qualifiers; - this.annotations = new HashSet<>(); - this.specVersion = Utils.getClassSpecVersion(type); - this.implVersion = Utils.getClassImplVersion(type); - - if (name == null || type == null) { - throw new IllegalStateException("Name and type fields cannot be null."); - } - } - - /** - * Create a representation of a discovered Microservice. - * - * @param name - * The name of the discovered Microservice. - * @param type - * The type of the discovered Microservice. - * @param qualifiers - * The qualifiers of the discovered Microservice. + * The qualifiers of the discovered Microservice. * @param annotations - * The annotations of the discovered Microservice. - * @param specVersion - * The specification version we are looking for. + * The annotations of the discovered Microservice. + * @param apiVersion + * The specification version we are looking for. * @param implVersion - * The implementation version we are looking for. + * The implementation version we are looking for. */ - public MicroserviceMetaData(final String name, final Class type, final Set qualifiers, final Set annotations, final String specVersion, final String implVersion) { + public MicroserviceMetaData(final String name, final Class type, final Set qualifiers, final Set annotations, final String apiVersion, final String implVersion) { this.name = name; this.type = type; this.qualifiers = qualifiers; this.annotations = annotations; - this.specVersion = specVersion; + this.apiVersion = apiVersion; this.implVersion = implVersion; if (name == null || type == null) { @@ -189,8 +141,8 @@ public Set getAnnotations() { * * @return The Microservice specification version. */ - public String getSpecVersion() { - return specVersion; + public String getApiVersion() { + return apiVersion; } /** @@ -222,10 +174,7 @@ public boolean equals(Object o) { if (qualifiers != null ? !qualifiers.equals(that.qualifiers) : that.qualifiers != null) { return false; } - if (annotations != null ? !annotations.equals(that.annotations) : that.annotations != null) { - return false; - } - return !(specVersion != null ? !specVersion.equals(that.specVersion) : that.specVersion != null); + return (annotations != null ? !annotations.equals(that.annotations) : that.annotations != null); } @@ -241,16 +190,30 @@ public int hashCode() { @Override public String toString() { return "microservice " + name + " of type " + type.getCanonicalName() + " with qualifiers " + Arrays.toString(qualifiers.toArray()) - + " and with annotations " + Arrays.toString(annotations.toArray()) + " (version: spec. " + specVersion + ", impl. " + implVersion + ")"; + + " and with annotations " + Arrays.toString(annotations.toArray()) + " (version: spec. " + apiVersion + ", impl. " + implVersion + ")"; + } + + /** + * Compares api version from query with a implementation version of a this object resolve whether it satisfies. + * + * @param query + * other metada object which specify verion + * @return boolean representing whether this object satisfies a query + */ + public boolean satisfies(MicroserviceMetaData query) { + return equals(query) && VersionComparator.forVersion(this.implVersion).satisfies(query.apiVersion); } /** * Queries host and retrieves all service handles * - * @param context context of a host - * @param host address of a host + * @param context + * context of a host + * @param host + * address of a host * @return a list of a service handles - * @throws Exception when something went wrong + * @throws Exception + * when something went wrong */ public List query(final Context context, final String host) throws Exception { String urlBase = "http://" + host + "/" + context.getProperties().get(HttpInvokerSilverService.INVOKER_URL) + "/query"; diff --git a/microservices/src/main/java/io/silverware/microservices/silver/cluster/LocalServiceHandle.java b/microservices/src/main/java/io/silverware/microservices/silver/cluster/LocalServiceHandle.java index a95da18..27e039f 100644 --- a/microservices/src/main/java/io/silverware/microservices/silver/cluster/LocalServiceHandle.java +++ b/microservices/src/main/java/io/silverware/microservices/silver/cluster/LocalServiceHandle.java @@ -19,12 +19,13 @@ */ package io.silverware.microservices.silver.cluster; -import com.cedarsoftware.util.io.JsonReader; -import com.cedarsoftware.util.io.JsonWriter; import io.silverware.microservices.Context; import io.silverware.microservices.MicroserviceMetaData; import io.silverware.microservices.silver.HttpInvokerSilverService; +import com.cedarsoftware.util.io.JsonReader; +import com.cedarsoftware.util.io.JsonWriter; + import java.net.HttpURLConnection; import java.net.URL; import java.util.concurrent.atomic.AtomicInteger; @@ -37,7 +38,7 @@ * * @author Martin Večeřa */ -// TODO: 9/8/16 Remove remote proxy and htpp invoker - it should be in separated object +// TODO: 9/8/16 Remove htpp invoker - it should be in separated object public class LocalServiceHandle implements ServiceHandle { private static final transient AtomicInteger handleSource = new AtomicInteger(0); @@ -75,7 +76,7 @@ public String getHost() { return host; } - public MicroserviceMetaData getQuery() { + public MicroserviceMetaData getMetaData() { return query; } diff --git a/microservices/src/main/java/io/silverware/microservices/silver/cluster/RemoteServiceHandlesStore.java b/microservices/src/main/java/io/silverware/microservices/silver/cluster/RemoteServiceHandlesStore.java index 076337d..1e0d046 100644 --- a/microservices/src/main/java/io/silverware/microservices/silver/cluster/RemoteServiceHandlesStore.java +++ b/microservices/src/main/java/io/silverware/microservices/silver/cluster/RemoteServiceHandlesStore.java @@ -70,7 +70,7 @@ public void addHandle(MicroserviceMetaData metaData, ServiceHandle handle) { /** * Removes all handles which are not mentioned in available nodes * - * @param availableNodes adresses of available nodes + * @param availableNodes addresses of available nodes */ public void keepHandlesFor(Set availableNodes) { outboundHandles.forEach((metaData, serviceHandles) -> { diff --git a/microservices/src/main/java/io/silverware/microservices/silver/services/LookupStrategyFactory.java b/microservices/src/main/java/io/silverware/microservices/silver/services/LookupStrategyFactory.java index 6ed8a71..e83a0ad 100644 --- a/microservices/src/main/java/io/silverware/microservices/silver/services/LookupStrategyFactory.java +++ b/microservices/src/main/java/io/silverware/microservices/silver/services/LookupStrategyFactory.java @@ -23,6 +23,7 @@ import io.silverware.microservices.MicroserviceMetaData; import io.silverware.microservices.annotations.InvocationPolicy; import io.silverware.microservices.silver.services.lookup.RandomRobinLookupStrategy; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -38,7 +39,7 @@ public class LookupStrategyFactory { /** * Logger. */ - private static Logger log = LogManager.getLogger(LookupStrategyFactory.class); + private static final Logger log = LogManager.getLogger(LookupStrategyFactory.class); /** * Returns strategy based on given parameters @@ -68,7 +69,6 @@ public static LookupStrategy getStrategy(final Context context, final Microservi } if (strategy == null) { - // TODO: 9/9/16 this should be discussed strategy = new RandomRobinLookupStrategy(); strategy.initialize(context, metaData, options); } diff --git a/microservices/src/main/java/io/silverware/microservices/util/Utils.java b/microservices/src/main/java/io/silverware/microservices/util/Utils.java index e3dd68d..c190b82 100644 --- a/microservices/src/main/java/io/silverware/microservices/util/Utils.java +++ b/microservices/src/main/java/io/silverware/microservices/util/Utils.java @@ -52,7 +52,7 @@ public class Utils { * Logs a shutdown message with the given exception. * * @param log A logger where to log the message to. - * @param ie An exception causing the shutdown. + * @param ie An exception causing the shutdown. */ public static void shutdownLog(final Logger log, final InterruptedException ie) { log.info("Execution interrupted, exiting."); @@ -65,7 +65,7 @@ public static void shutdownLog(final Logger log, final InterruptedException ie) * Waits for the URL to become available. * * @param urlString The URL to check for. - * @param code The expected HTTP response code. + * @param code The expected HTTP response code. * @return Returns true if the URL was available, false otherwise. * @throws Exception When it was not possible to check the URL. */ @@ -109,7 +109,7 @@ public static String readFromUrl(String urlString) throws IOException { /** * Gets the manifest entry for the given class. * - * @param clazz The class I want to obtain entry for. + * @param clazz The class I want to obtain entry for. * @param entryName The name of the entry to obtain. * @return The entry from manifest, null if there is no such entry or the manifest file does not exists. * @throws IOException When it was not possible to get the manifest file. @@ -130,41 +130,6 @@ public static String getManifestEntry(final Class clazz, final String entryName) return null; } - /** - * Gets the class implementation version from manifest. - * - * @param clazz The class I want to obtain version of. - * @return The class specification version from manifest, null if there is no version information present or the manifest file does not exists. - */ - public static String getClassImplVersion(final Class clazz) { - try { - return getManifestEntry(clazz, "Implementation-Version"); - } catch (IOException ioe) { - if (log.isDebugEnabled()) { - log.debug("Cannot obtain version for class {}.", clazz.getName()); - } - } - - return null; - } - - /** - * Gets the class specification version from manifest. - * - * @param clazz The class I want to obtain version of. - * @return The class specification version from manifest, null if there is no version information present or the manifest file does not exists. - */ - public static String getClassSpecVersion(final Class clazz) { - try { - return getManifestEntry(clazz, "Specification-Version"); - } catch (IOException ioe) { - if (log.isDebugEnabled()) { - log.debug("Cannot obtain version for class {}.", clazz.getName()); - } - } - - return null; - } /** * Do the best to sleep for the given time. Ignores {@link InterruptedException}. diff --git a/microservices/src/main/java/io/silverware/microservices/util/VersionComparator.java b/microservices/src/main/java/io/silverware/microservices/util/VersionComparator.java new file mode 100644 index 0000000..7211991 --- /dev/null +++ b/microservices/src/main/java/io/silverware/microservices/util/VersionComparator.java @@ -0,0 +1,109 @@ +/* + * -----------------------------------------------------------------------\ + * SilverWare + * + * Copyright (C) 2010 - 2013 the original author or 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 io.silverware.microservices.util; + +import static com.google.common.base.Strings.isNullOrEmpty; + +import com.vdurmont.semver4j.Semver; +import com.vdurmont.semver4j.SemverException; + +/** + * Adapter for a Java Sem-Ver + * Created because the project is in beta and the api can change. + * This implementation is using NPM versioning rules. + * implemented in library Semantic Versioning home page. + * + * Be aware: + * If a version has a prerelease tag (for example, 1.2.3-alpha.3) then it will only be allowed + * to satisfy comparator sets if at least one comparator with the same [major, minor, patch] tuple also has a prerelease tag. + * + * @author Slavomír Krupa (slavomir.krupa@gmail.com) + */ +public class VersionComparator { + + private final Semver semVersion; + + private VersionComparator(String version) { + try { + + if (isNullOrEmpty(version)) { + this.semVersion = null; + } else { + /* + build version must be appended to x.y.z format number otherwise the comparision wont work. + here we are creating correct string for comparision. + */ + Semver builtVersion = new Semver(version, Semver.SemverType.NPM); + if (builtVersion.getMinor() == null && builtVersion.getPatch() == null) { + int indexOfMinorVersion = ("" + builtVersion.getMajor()).length(); + version = buildVersionWithPatch(version, indexOfMinorVersion, ".0.0"); + } else if (builtVersion.getPatch() == null) { + int indexOfPatchVersion = ("." + builtVersion.getMinor() + builtVersion.getMajor()).length(); + version = buildVersionWithPatch(version, indexOfPatchVersion, ".0"); + } + this.semVersion = new Semver(version, Semver.SemverType.NPM); + } + + } catch (SemverException e) { + throw new IllegalArgumentException(e); + } + } + + /** + * Factory method which creates an instance of this class. + * + * @param version + * semVersion for which object should be created when or empty provided then it won't satisfy any expression + * @return created object + * @throws IllegalArgumentException + * when the format of the semVersion is wrong + */ + public static VersionComparator forVersion(String version) { + return new VersionComparator(version); + } + + /** + * Compare semVersion of a object and the expression. + * + * @param expression + * the expression specifying supported versions + * @return true when expression is null, false when semVersion in object is null and result of a @{@link Semver}.satisfies() otherwise. + * @throws IllegalArgumentException + * when the format of a expression is wrong + */ + public boolean satisfies(String expression) { + if (isNullOrEmpty(expression)) { + return true; + } + if (semVersion == null) { + return false; + } + try { + return semVersion.satisfies(expression); + } catch (SemverException e) { + throw new IllegalArgumentException(e); + } + } + + private static String buildVersionWithPatch(String originalValue, int index, String missingVersions) { + return originalValue.substring(0, index) + missingVersions + originalValue.substring(index, originalValue.length()); + } + +} diff --git a/microservices/src/test/java/io/silverware/microservices/util/VersionComparatorTest.java b/microservices/src/test/java/io/silverware/microservices/util/VersionComparatorTest.java new file mode 100644 index 0000000..8600830 --- /dev/null +++ b/microservices/src/test/java/io/silverware/microservices/util/VersionComparatorTest.java @@ -0,0 +1,65 @@ +package io.silverware.microservices.util; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * This test shall demonstrate functionality of version specifying + * + * @author Slavomír Krupa (slavomir.krupa@gmail.com) + */ +public class VersionComparatorTest { + private static final String VERSION = "1.2.3"; + + private static final String MINOR_VERSION_SNAPSHOT = "1.2-SNAPSHOT"; + private static final String MAJOR_VERSION_SNAPSHOT = "1-SNAPSHOT"; + + public static final String DESCRIPTION = "Version %s should%sbe satisfied by a condition %s."; + public static final String SUCCESS_MAJOR_SNAPSHOT = "successMajorSnapshot"; + public static final String SUCCESS_LESS_DIGITS = "successLessDigits"; + public static final String FAIL = "fail"; + public static final String SUCCESS = "success"; + + @DataProvider(name = SUCCESS) + public static Object[][] successVersions() { + return new Object[][] { { VERSION }, { "1.*" }, { "1.2.x" }, { "1.X" }, { "~1.2" }, { VERSION + "-" + VERSION }, { "^1" }, { "^" + VERSION } }; + } + + @Test(dataProvider = SUCCESS) + public void testSatisfiesConditionSuccess(String condition) throws Exception { + assertThat(VersionComparator.forVersion(VERSION).satisfies(condition)).as(DESCRIPTION, VERSION, " ", condition).isTrue(); + } + + @DataProvider(name = FAIL) + public static Object[][] failVersions() { + return new Object[][] { { "1.2.5" }, { "1.0.*" }, { "1.1.x" }, { "1.3.X" }, { "~1.3" }, { "1.2.4-1.4.0" }, { "^2" }, { "^1.2.4" } }; + } + + @Test(dataProvider = FAIL) + public void testSatisfiesConditionFails(String condition) throws Exception { + assertThat(VersionComparator.forVersion(VERSION).satisfies(condition)).as(DESCRIPTION, VERSION, " not ", condition).isFalse(); + } + + @DataProvider(name = SUCCESS_LESS_DIGITS) + public static Object[][] successVersionsLessDigits() { + return new Object[][] { { MINOR_VERSION_SNAPSHOT }, { "~1.2-SNAPSHOT" }, { "1.2.x-SNAPSHOT" }, { "" } }; + } + + @Test(dataProvider = SUCCESS_LESS_DIGITS) + public void testSatisfiesConditionWithLessDigitsSuccess(String condition) throws Exception { + assertThat(VersionComparator.forVersion(MINOR_VERSION_SNAPSHOT).satisfies(condition)).as(DESCRIPTION, MINOR_VERSION_SNAPSHOT, " ", condition).isTrue(); + } + + @DataProvider(name = SUCCESS_MAJOR_SNAPSHOT) + public static Object[][] successVersionsMajorSnapshot() { + return new Object[][] { { MAJOR_VERSION_SNAPSHOT }, { "~1-SNAPSHOT" }, { "1.x-SNAPSHOT" }, { "" }, { "^1-SNAPSHOT" }, { "1-SNAPSHOT" } }; + } + + @Test(dataProvider = SUCCESS_MAJOR_SNAPSHOT) + public void testSatisfiesConditionMajorSnapshotSuccess(String condition) throws Exception { + assertThat(VersionComparator.forVersion(MAJOR_VERSION_SNAPSHOT).satisfies(condition)).as(DESCRIPTION, MAJOR_VERSION_SNAPSHOT, " ", condition).isTrue(); + } + +} \ No newline at end of file