Skip to content

Package: ContextBasedObjectSupplier

ContextBasedObjectSupplier

nameinstructionbranchcomplexitylinemethod
ContextBasedObjectSupplier(Class, Class)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
checkDependencies(Annotation, Class, IEclipseContext)
M: 15 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
get(IObjectDescriptor, IRequestor, boolean, boolean)
M: 14 C: 50
78%
M: 3 C: 5
63%
M: 3 C: 2
40%
M: 4 C: 13
76%
M: 0 C: 1
100%
getContext(IRequestor)
M: 2 C: 16
89%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 1 C: 5
83%
M: 0 C: 1
100%
getRawType(Type)
M: 2 C: 14
88%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 1 C: 4
80%
M: 0 C: 1
100%
lambda$0(Annotation, Class, IEclipseContext, Object[])
M: 14 C: 21
60%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 2 C: 5
71%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2019 Christian W. Damus and others.
3: *
4: * All rights reserved. This program and the accompanying materials
5: * are made available under the terms of the Eclipse Public License 2.0
6: * which accompanies this distribution, and is available at
7: * https://www.eclipse.org/legal/epl-2.0/
8: *
9: * SPDX-License-Identifier: EPL-2.0
10: *
11: * Contributors:
12: * Christian W. Damus - initial API and implementation
13: ******************************************************************************/
14: package org.eclipse.emf.ecp.view.spi.common.di;
15:
16: import java.lang.annotation.Annotation;
17: import java.lang.reflect.ParameterizedType;
18: import java.lang.reflect.Type;
19: import java.util.Optional;
20:
21: import org.eclipse.e4.core.contexts.IEclipseContext;
22: import org.eclipse.e4.core.contexts.RunAndTrack;
23: import org.eclipse.e4.core.di.IInjector;
24: import org.eclipse.e4.core.di.InjectionException;
25: import org.eclipse.e4.core.di.suppliers.ExtendedObjectSupplier;
26: import org.eclipse.e4.core.di.suppliers.IObjectDescriptor;
27: import org.eclipse.e4.core.di.suppliers.IRequestor;
28: import org.eclipse.e4.core.di.suppliers.PrimaryObjectSupplier;
29:
30: /**
31: * A partial implementation of an object supplier that computes its results from
32: * values in the {@linkplain IEclipseContext Eclipse context}.
33: *
34: * @param <A> my qualifier annotation type
35: * @param <T> my value type
36: * @since 1.22
37: */
38: public abstract class ContextBasedObjectSupplier<A extends Annotation, T> extends ExtendedObjectSupplier {
39:
40:         private final Class<A> qualifierType;
41:         private final Class<T> valueType;
42:
43:         /**
44:          * Initializes me with the type of value that I supply and the
45:          * qualifier annotation type that I key on.
46:          *
47:          * @param qualifierType the qualifier annotation type
48:          * @param valueType the value type
49:          */
50:         protected ContextBasedObjectSupplier(Class<A> qualifierType, Class<T> valueType) {
51:                 super();
52:
53:                 this.qualifierType = qualifierType;
54:                 this.valueType = valueType;
55:         }
56:
57:         @Override
58:         public Object get(IObjectDescriptor descriptor, IRequestor requestor, boolean track, boolean group) {
59:                 final Class<?> desiredType = getRawType(descriptor.getDesiredType());
60:                 final A qualifier = descriptor.getQualifier(qualifierType);
61:
62:•                if (!valueType.isAssignableFrom(desiredType)) {
63:                         return IInjector.NOT_A_VALUE;
64:                 }
65:                 final Class<? extends T> requestedType = desiredType.asSubclass(valueType);
66:
67:                 final IEclipseContext ctx = getContext(requestor);
68:•                if (ctx == null) {
69:                         return IInjector.NOT_A_VALUE;
70:                 }
71:
72:•                if (!checkDependencies(qualifier, requestedType, ctx)) {
73:                         return IInjector.NOT_A_VALUE;
74:                 }
75:
76:                 final Object[] result = { null };
77:                 final Runnable compute = () -> {
78:                         final Optional<? extends T> computedResult = compute(qualifier, requestedType, ctx);
79:•                        if (computedResult == null) {
80:                                 throw new InjectionException(String.format(
81:                                         "null computation for @%s injection", qualifierType.getSimpleName())); //$NON-NLS-1$
82:                         }
83:                         result[0] = computedResult.map(Object.class::cast)
84:                                 .orElse(IInjector.NOT_A_VALUE);
85:                 };
86:•                if (track) {
87:                         ctx.runAndTrack(new RunAndTrack() {
88:
89:                                 @Override
90:                                 public boolean changed(IEclipseContext context) {
91:                                         final boolean valid = requestor.isValid();
92:                                         final boolean notify = result[0] != null && requestor.isValid();
93:                                         if (valid) {
94:                                                 compute.run();
95:                                         }
96:                                         if (notify) {
97:                                                 requestor.resolveArguments(false);
98:                                                 requestor.execute();
99:                                         }
100:                                         return valid;
101:                                 }
102:                         });
103:                 } else {
104:                         compute.run();
105:                 }
106:
107:                 return result[0];
108:         }
109:
110:         /**
111:          * Check whether the Eclipse {@code context} has the dependencies required to
112:          * compute my result. The default implementation just attempts to compute
113:          * the result, which is useful for simple cases where the computation is not
114:          * expensive and does not have undesired side-effects if it fails.
115:          *
116:          * @param qualifier the qualifier annotation, which may have attributes required for the computation
117:          * @param requestedType the type requested for injection
118:          * @param context the Eclipse context
119:          * @return {@code true} if I can compute a value from this {@code context};
120:          * {@code false}, otherwise
121:          *
122:          * @see #compute(Annotation, IEclipseContext)
123:          */
124:         protected boolean checkDependencies(A qualifier, Class<? extends T> requestedType, IEclipseContext context) {
125:                 final Optional<? extends T> test = compute(qualifier, requestedType, context);
126:•                return test != null && test.isPresent();
127:         }
128:
129:         /**
130:          * Compute my value from the Eclipse {@code context}. An empty result
131:          * indicates that the value does not exist (the {@link IInjector#NOT_A_VALUE}
132:          * special result for the object-supplier protocol). Injection of {@code null}
133:          * values is not supported.
134:          *
135:          * @param qualifier the qualifier annotation, which may have attributes required for the computation
136:          * @param requestedType the type requested for injection
137:          * @param context the Eclipse context
138:          * @return the result of the computation (possibly empty, but not {@code null})
139:          */
140:         protected abstract Optional<? extends T> compute(A qualifier, Class<? extends T> requestedType,
141:                 IEclipseContext context);
142:
143:         private static Class<?> getRawType(Type type) {
144:•                if (type instanceof Class<?>) {
145:                         return (Class<?>) type;
146:•                } else if (type instanceof ParameterizedType) {
147:                         return getRawType(((ParameterizedType) type).getRawType());
148:                 } else {
149:                         return Object.class;
150:                 }
151:         }
152:
153:         @SuppressWarnings("restriction")
154:         private static IEclipseContext getContext(IRequestor requestor) {
155:                 PrimaryObjectSupplier supplier = null;
156:
157:•                if (requestor instanceof org.eclipse.e4.core.internal.di.Requestor<?>) {
158:                         supplier = ((org.eclipse.e4.core.internal.di.Requestor<?>) requestor).getPrimarySupplier();
159:                 }
160:
161:•                if (supplier instanceof org.eclipse.e4.core.internal.contexts.ContextObjectSupplier) {
162:                         return ((org.eclipse.e4.core.internal.contexts.ContextObjectSupplier) supplier).getContext();
163:                 }
164:
165:                 return null;
166:         }
167:
168: }