1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.component.chain;
import com.yahoo.component.AbstractComponent;
import com.yahoo.component.ComponentId;
import com.yahoo.component.chain.dependencies.After;
import com.yahoo.component.chain.dependencies.Before;
import com.yahoo.component.chain.dependencies.Dependencies;
import com.yahoo.component.chain.dependencies.Provides;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* Component with dependencies.
*
* @author Tony Vaagenes
*/
public abstract class ChainedComponent extends AbstractComponent {
/** The immutable set of dependencies of this. NOTE: the default is only for unit testing. */
private Dependencies dependencies = getDefaultAnnotatedDependencies();
public ChainedComponent(ComponentId id) {
super(id);
}
protected ChainedComponent() {}
/**
* Called by the container to assign the full set of dependencies to this class (configured and declared).
* This is called once before this is started.
* @param dependencies The configured dependencies, that this method will merge with annotated dependencies.
*/
public void initDependencies(Dependencies dependencies) {
this.dependencies = dependencies.union(getDefaultAnnotatedDependencies());
}
/** Returns the configured and declared dependencies of this chainedcomponent */
public Dependencies getDependencies() { return dependencies; }
/** This method is here only for legacy reasons, do not override. */
protected Dependencies getDefaultAnnotatedDependencies() {
Dependencies dependencies = getAnnotatedDependencies(com.yahoo.yolean.chain.Provides.class, com.yahoo.yolean.chain.Before.class, com.yahoo.yolean.chain.After.class);
Dependencies legacyDependencies = getAnnotatedDependencies(Provides.class, Before.class, After.class);
return dependencies.union(legacyDependencies);
}
/**
* @param providesClass The annotation class representing 'provides'.
* @param beforeClass The annotation class representing 'before'.
* @param afterClass The annotation class representing 'after'.
* @return a new {@link Dependencies} created from the annotations given in this component's class.
*/
protected Dependencies getAnnotatedDependencies(Class<? extends Annotation> providesClass,
Class<? extends Annotation> beforeClass,
Class<? extends Annotation> afterClass) {
return new Dependencies(
allOf(getSymbols(this, providesClass), this.getClass().getSimpleName(), this.getClass().getName()),
getSymbols(this, beforeClass),
getSymbols(this, afterClass));
}
// TODO: move to vespajlib.
private static List<String> allOf(List<String> symbols, String... otherSymbols) {
List<String> result = new ArrayList<>(symbols);
result.addAll(Arrays.asList(otherSymbols));
return result;
}
private static List<String> getSymbols(ChainedComponent component, Class<? extends Annotation> annotationClass) {
List<String> result = new ArrayList<>();
result.addAll(annotationSymbols(component, annotationClass));
return result;
}
private static Collection<String> annotationSymbols(ChainedComponent component, Class<? extends Annotation> annotationClass) {
try {
Annotation annotation = component.getClass().getAnnotation(annotationClass);
if (annotation != null) {
Object values = annotationClass.getMethod("value").invoke(annotation);
return Arrays.asList((String[])values);
}
return List.of();
} catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
|