1
2
3
4
5
6 package gov.nist.secauto.metaschema.core.metapath.function;
7
8 import gov.nist.secauto.metaschema.core.metapath.StaticMetapathException;
9 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
10
11 import java.util.ServiceLoader;
12 import java.util.ServiceLoader.Provider;
13 import java.util.stream.Stream;
14
15 import javax.xml.namespace.QName;
16
17 import edu.umd.cs.findbugs.annotations.NonNull;
18 import nl.talsmasoftware.lazy4j.Lazy;
19
20 public final class FunctionService {
21 private static final Lazy<FunctionService> INSTANCE = Lazy.lazy(() -> new FunctionService());
22 @NonNull
23 private final ServiceLoader<IFunctionLibrary> loader;
24 @NonNull
25 private final Lazy<IFunctionLibrary> library;
26
27
28
29
30
31
32 public static FunctionService getInstance() {
33 return INSTANCE.get();
34 }
35
36
37
38
39 @SuppressWarnings("null")
40 public FunctionService() {
41 this.loader = ServiceLoader.load(IFunctionLibrary.class);
42 ServiceLoader<IFunctionLibrary> loader = getLoader();
43
44 this.library = Lazy.lazy(() -> {
45 FunctionLibrary functionLibrary = new FunctionLibrary();
46 loader.stream()
47 .map(Provider<IFunctionLibrary>::get)
48 .flatMap(IFunctionLibrary::stream)
49 .forEachOrdered(function -> functionLibrary.registerFunction(ObjectUtils.notNull(function)));
50 return functionLibrary;
51 });
52 }
53
54
55
56
57
58
59 @NonNull
60 private ServiceLoader<IFunctionLibrary> getLoader() {
61 return loader;
62 }
63
64 @NonNull
65 private IFunctionLibrary getLibrary() {
66 return ObjectUtils.notNull(library.get());
67 }
68
69
70
71
72
73
74 public Stream<IFunction> stream() {
75 return getLibrary().stream();
76 }
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public IFunction getFunction(@NonNull String name, int arity) {
92 IFunction retval;
93 synchronized (this) {
94 retval = getLibrary().getFunction(name, arity);
95 }
96
97 if (retval == null) {
98 throw new StaticMetapathException(StaticMetapathException.NO_FUNCTION_MATCH,
99 String.format("unable to find function with name '%s' having arity '%d'", name, arity));
100 }
101 return retval;
102 }
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 public IFunction getFunction(@NonNull QName name, int arity) {
118 IFunction retval;
119 synchronized (this) {
120 retval = getLibrary().getFunction(name, arity);
121 }
122
123 if (retval == null) {
124 throw new StaticMetapathException(StaticMetapathException.NO_FUNCTION_MATCH,
125 String.format("unable to find function with name '%s' having arity '%d'", name, arity));
126 }
127 return retval;
128 }
129
130 }