Skip to content

Commit

Permalink
[SilverThings#47] [SilverThings#34] Implement version lookup and fix …
Browse files Browse the repository at this point in the history
…cluster lookup

  - Versioning uses semver4j from https://github.com/vdurmont/semver4j
    in npm mode. It allows wider range of queries to be executed and
    rules for the version format is not so strict.
    i.e - major and patch versions are not required.
    see -  https://github.com/npm/node-semver for more information.
    Process of resolving versions is described in VersionResolver.
  - Fix for cluster when main node of the cluster fails.
  - Cluster lookup now provides more clear information
    about a result of a lookup.
  • Loading branch information
SlavoKrupa authored and RadekKoubsky committed Nov 12, 2016
1 parent 0e45b04 commit dd637a4
Show file tree
Hide file tree
Showing 43 changed files with 1,015 additions and 334 deletions.
Original file line number Diff line number Diff line change
@@ -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:
* <ul>
* <li><strong>Microservice:</strong> can specify version of Microservice Implementation and API. </li>
* <li><strong>Injection point:</strong> can specify supported version of a Microservice API. </li>
* </ul>
* 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 ([email protected])
*/
@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 "";
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -58,6 +59,8 @@

/**
* @author <a href="mailto:[email protected]">Martin Večeřa</a>
* Changes in version resolution in lookupMicroservice
* @author Slavomir Krupa ([email protected])
*/
public class CdiMicroserviceProvider implements MicroserviceProvider, CdiSilverService {

Expand Down Expand Up @@ -134,15 +137,18 @@ public void run() {
@Override
@SuppressWarnings("checkstyle:JavadocMethod")
public Set<Object> lookupMicroservice(final MicroserviceMetaData microserviceMetaData) {
// name can not be null - contract of MicroserviceMetaData
final String name = microserviceMetaData.getName();
final Class<?> type = microserviceMetaData.getType();
final Set<Annotation> qualifiers = microserviceMetaData.getQualifiers();
final String apiVersion = microserviceMetaData.getApiVersion();
final Set<Object> matchingBeansByName = new HashSet<>();
final Set<Object> 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
Expand All @@ -157,33 +163,39 @@ public Set<Object> 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<Annotation> 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<Annotation> 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
}
}
}
Expand Down Expand Up @@ -223,7 +235,7 @@ public <T> T lookupBean(final Class<T> type) {
@Override
public <T> T findByType(final Class<T> type) {
final BeanManager beanManager = (BeanManager) this.context.getProperties().get(BEAN_MANAGER);
final Set<T> beans = new HashSet<T>();
final Set<T> beans = new HashSet<>();
final Set<Bean<?>> definitions = beanManager.getBeans(type);
final Bean<?> bean = beanManager.resolve(definitions);
final CreationalContext<?> creationalContext = beanManager.createCreationalContext(bean);
Expand Down Expand Up @@ -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 {

Expand All @@ -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 {

Expand Down Expand Up @@ -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 {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
*/
Expand All @@ -49,7 +50,7 @@ protected DefaultMethodHandler(final MicroserviceProxyBean proxyBean) throws Exc
this.proxyBean = proxyBean;

final Set<Annotation> 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());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()) {
Expand All @@ -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();
Expand Down Expand Up @@ -156,8 +153,7 @@ private Set<Annotation> preProcessQualifiers(final Set<Annotation> 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());
Expand Down Expand Up @@ -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() {
Expand All @@ -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())));
}

/**
Expand Down
Loading

0 comments on commit dd637a4

Please sign in to comment.