Skip to contentMethod: getAttribute(String)
1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: * <p>
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: * <p>
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.model.metamodel;
16:
17: import cz.cvut.kbss.jopa.model.lifecycle.LifecycleEvent;
18:
19: import java.lang.reflect.Method;
20: import java.lang.reflect.Modifier;
21: import java.util.*;
22: import java.util.stream.Collectors;
23:
24: public abstract class AbstractIdentifiableType<X> implements IdentifiableType<X> {
25:
26: private final Class<X> javaType;
27:
28: private Identifier identifier;
29:
30: private AbstractIdentifiableType<? super X> supertype;
31:
32: private final Set<AbstractIdentifiableType<? extends X>> subtypes = new HashSet<>(2);
33:
34: private TypesSpecification<X, ?> directTypes;
35:
36: private PropertiesSpecification<X, ?, ?, ?> properties;
37:
38: private final Map<String, Attribute<X, ?>> declaredAttributes = new HashMap<>();
39:
40: // Lifecycle hooks declared on this type
41: private final Map<LifecycleEvent, Method> lifecycleHooks = new EnumMap<>(LifecycleEvent.class);
42:
43: AbstractIdentifiableType(Class<X> javaType) {
44: this.javaType = javaType;
45: }
46:
47: void addDeclaredAttribute(final String name, final Attribute<X, ?> a) {
48: declaredAttributes.put(name, a);
49: }
50:
51: void setSupertype(AbstractIdentifiableType<? super X> supertype) {
52: assert supertype != null;
53: this.supertype = supertype;
54: supertype.addSubtype(this);
55: }
56:
57: private void addSubtype(AbstractIdentifiableType<? extends X> subtype) {
58: subtypes.add(subtype);
59: }
60:
61: void addDirectTypes(TypesSpecification<X, ?> a) {
62: this.directTypes = a;
63: }
64:
65: void addOtherProperties(PropertiesSpecification<X, ?, ?, ?> a) {
66: this.properties = a;
67: }
68:
69: void addLifecycleListener(LifecycleEvent event, Method listener) {
70: lifecycleHooks.put(event, listener);
71: }
72:
73: public void setIdentifier(final Identifier identifier) {
74: this.identifier = identifier;
75: }
76:
77: @Override
78: public boolean hasSingleIdAttribute() {
79: return true; // We do not support id classes
80: }
81:
82: @Override
83: public <Y> SingularAttribute<X, Y> getDeclaredVersion(Class<Y> type) {
84: // TODO
85: throw new UnsupportedOperationException();
86: }
87:
88: @Override
89: public IdentifiableType<? super X> getSupertype() {
90: return supertype;
91: }
92:
93: /**
94: * Whether this managed type has any managed subtypes (entities or mapped superclasses).
95: *
96: * @return {@code true} when managed subtypes exist, {@code false} otherwise
97: */
98: public boolean hasSubtypes() {
99: return !subtypes.isEmpty();
100: }
101:
102: /**
103: * Whether the Java type represented by this type is an abstract class.
104: *
105: * @return {@code true} if the represented Java type is abstract, {@code false} otherwise
106: */
107: public boolean isAbstract() {
108: return Modifier.isAbstract(javaType.getModifiers());
109: }
110:
111: public Set<AbstractIdentifiableType<? extends X>> getSubtypes() {
112: return Collections.unmodifiableSet(subtypes);
113: }
114:
115: @Override
116: public <Y> SingularAttribute<? super X, Y> getVersion(Class<Y> type) {
117: // TODO
118: throw new UnsupportedOperationException();
119: }
120:
121: @Override
122: public boolean hasVersionAttribute() {
123: return false;
124: }
125:
126: @Override
127: public Set<Attribute<? super X, ?>> getAttributes() {
128: final Set<Attribute<? super X, ?>> attributes = new HashSet<>(declaredAttributes.values());
129: if (supertype != null) {
130: attributes.addAll(supertype.getAttributes());
131: }
132: return attributes;
133: }
134:
135: @Override
136: public Attribute<? super X, ?> getAttribute(String name) {
137: Objects.requireNonNull(name);
138:• if (declaredAttributes.containsKey(name)) {
139: return declaredAttributes.get(name);
140: }
141:• if (supertype != null) {
142: return supertype.getAttribute(name);
143: }
144: throw new IllegalArgumentException("Attribute " + name + " is not present in type " + this.toString());
145: }
146:
147: @Override
148: public CollectionAttribute<? super X, ?> getCollection(String name) {
149: return getCollection(name, Object.class);
150: }
151:
152: @Override
153: public <E> CollectionAttribute<? super X, E> getCollection(String name, Class<E> elementType) {
154: return getPluralAttribute("Collection", name, elementType, CollectionAttribute.class);
155: }
156:
157: private <E, R extends PluralAttribute<? super X, ?, E>> R getPluralAttribute(String type, String name,
158: Class<E> elementType,
159: Class<R> attType) {
160: final Attribute<? super X, ?> a = getAttribute(name);
161:
162: checkPluralAttribute(a, type, name, elementType, attType, false);
163: return attType.cast(a);
164: }
165:
166: private <E, R extends PluralAttribute<? super X, ?, E>> void checkPluralAttribute(Attribute<? super X, ?> att,
167: String type, String name,
168: Class<E> elementType,
169: Class<R> attType,
170: boolean declared) {
171: if (!attType.isAssignableFrom(att.getClass())) {
172: throw pluralAttNotFound(type, name, elementType, declared);
173: }
174:
175: final PluralAttribute<? super X, ?, E> colAtt = (PluralAttribute<? super X, ?, E>) att;
176: if (!elementType.isAssignableFrom(colAtt.getBindableJavaType())) {
177: throw pluralAttNotFound(type, name, elementType, declared);
178: }
179: }
180:
181: private IllegalArgumentException pluralAttNotFound(String type, String name, Class<?> elementType,
182: boolean declared) {
183: return new IllegalArgumentException(type + " attribute " + name + " with element type " + elementType +
184: " is not " + (declared ? "declared" : "present") + " in type " + this);
185: }
186:
187: @Override
188: public <E> ListAttribute<? super X, E> getList(String name, Class<E> elementType) {
189: return getPluralAttribute("List", name, elementType, ListAttribute.class);
190: }
191:
192: @Override
193: public ListAttribute<? super X, ?> getList(String name) {
194: return getList(name, Object.class);
195: }
196:
197: @Override
198: public <K, V> MapAttribute<? super X, K, V> getMap(String name, Class<K> keyType, Class<V> valueType) {
199: throw new UnsupportedOperationException();
200: }
201:
202: @Override
203: public MapAttribute<? super X, ?, ?> getMap(String name) {
204: return getMap(name, Object.class, Object.class);
205: }
206:
207: @Override
208: public <E> SetAttribute<? super X, E> getSet(String name, Class<E> elementType) {
209: return getPluralAttribute("Set", name, elementType, SetAttribute.class);
210: }
211:
212: @Override
213: public SetAttribute<? super X, ?> getSet(String name) {
214: return getSet(name, Object.class);
215: }
216:
217: @Override
218: public Set<PluralAttribute<? super X, ?, ?>> getPluralAttributes() {
219: final Set<PluralAttribute<? super X, ?, ?>> plurals = new HashSet<>();
220: plurals.addAll(getDeclaredPluralAttributes());
221: if (supertype != null) {
222: plurals.addAll(supertype.getPluralAttributes());
223: }
224: return plurals;
225: }
226:
227: @Override
228: public Set<SingularAttribute<? super X, ?>> getSingularAttributes() {
229: final Set<SingularAttribute<? super X, ?>> singulars = new HashSet<>();
230: singulars.addAll(getDeclaredSingularAttributes());
231: if (supertype != null) {
232: singulars.addAll(supertype.getSingularAttributes());
233: }
234: return singulars;
235: }
236:
237: @Override
238: public <Y> SingularAttribute<? super X, Y> getSingularAttribute(String name, Class<Y> type) {
239: final Attribute<? super X, ?> a = getAttribute(name);
240:
241: if (a.isCollection()) {
242: throw singularAttNotFound(name, type, false);
243: }
244: assert a instanceof SingularAttribute;
245: if (!type.isAssignableFrom(a.getJavaType())) {
246: throw singularAttNotFound(name, type, false);
247: }
248:
249: return (SingularAttribute<? super X, Y>) a;
250: }
251:
252: private IllegalArgumentException singularAttNotFound(String name, Class<?> type, boolean declared) {
253: return new IllegalArgumentException(
254: "Singular attribute " + name + " of type " + type + " is not " + (declared ? "declared" : "present") +
255: " in type " + this);
256: }
257:
258: @Override
259: public SingularAttribute<? super X, ?> getSingularAttribute(String name) {
260: return getSingularAttribute(name, Object.class);
261: }
262:
263: @Override
264: public Set<Attribute<X, ?>> getDeclaredAttributes() {
265: return new HashSet<>(declaredAttributes.values());
266: }
267:
268: @Override
269: public Set<PluralAttribute<X, ?, ?>> getDeclaredPluralAttributes() {
270: return declaredAttributes.values().stream().filter(Attribute::isCollection)
271: .map(a -> (PluralAttribute<X, ?, ?>) a).collect(Collectors.toSet());
272: }
273:
274: @Override
275: public Set<SingularAttribute<X, ?>> getDeclaredSingularAttributes() {
276: return declaredAttributes.values().stream().filter(att -> !att.isCollection()).map(
277: a -> (SingularAttribute<X, ?>) a).collect(Collectors.toSet());
278: }
279:
280: @Override
281: public Attribute<X, ?> getDeclaredAttribute(String name) {
282: if (declaredAttributes.containsKey(name)) {
283: return declaredAttributes.get(name);
284: }
285: throw new IllegalArgumentException("Attribute " + name + " is not declared in type " + name);
286: }
287:
288: @Override
289: public <E> CollectionAttribute<X, E> getDeclaredCollection(String name, Class<E> elementType) {
290: return getDeclaredPluralAttribute("Collection", name, elementType, CollectionAttribute.class);
291: }
292:
293: private <E, R extends PluralAttribute<? super X, ?, E>> R getDeclaredPluralAttribute(String type, String name,
294: Class<E> elementType,
295: Class<R> attType) {
296: final Attribute<? super X, ?> a = getDeclaredAttribute(name);
297:
298: checkPluralAttribute(a, type, name, elementType, attType, true);
299: return attType.cast(a);
300: }
301:
302: @Override
303: public CollectionAttribute<X, ?> getDeclaredCollection(String name) {
304: return getDeclaredCollection(name, Object.class);
305: }
306:
307: @Override
308: public <E> ListAttribute<X, E> getDeclaredList(String name, Class<E> elementType) {
309: return getDeclaredPluralAttribute("List", name, elementType, ListAttribute.class);
310: }
311:
312: @Override
313: public ListAttribute<X, ?> getDeclaredList(String name) {
314: return getDeclaredList(name, Object.class);
315: }
316:
317: @Override
318: public <K, V> MapAttribute<X, K, V> getDeclaredMap(String name, Class<K> keyType, Class<V> valueType) {
319: throw new UnsupportedOperationException();
320: }
321:
322: @Override
323: public MapAttribute<X, ?, ?> getDeclaredMap(String name) {
324: return getDeclaredMap(name, Object.class, Object.class);
325: }
326:
327: @Override
328: public <E> SetAttribute<X, E> getDeclaredSet(String name, Class<E> elementType) {
329: return getDeclaredPluralAttribute("Set", name, elementType, SetAttribute.class);
330: }
331:
332: @Override
333: public SetAttribute<X, ?> getDeclaredSet(String name) {
334: return getDeclaredSet(name, Object.class);
335: }
336:
337: @Override
338: public <Y> SingularAttribute<X, Y> getDeclaredSingularAttribute(String name, Class<Y> type) {
339: final Attribute<X, ?> a = getDeclaredAttribute(name);
340:
341: if (a.isCollection()) {
342: throw singularAttNotFound(name, type, true);
343: }
344: if (!type.isAssignableFrom(a.getJavaType())) {
345: throw singularAttNotFound(name, type, true);
346: }
347:
348: return (SingularAttribute<X, Y>) a;
349: }
350:
351: @Override
352: public SingularAttribute<X, ?> getDeclaredSingularAttribute(String name) {
353: return getDeclaredSingularAttribute(name, Object.class);
354: }
355:
356: @Override
357: public TypesSpecification<? super X, ?> getTypes() {
358: if (directTypes != null) {
359: return directTypes;
360: }
361: return supertype != null ? supertype.getTypes() : null;
362: }
363:
364: @Override
365: public PropertiesSpecification<? super X, ?, ?, ?> getProperties() {
366: if (properties != null) {
367: return properties;
368: }
369: return supertype != null ? supertype.getProperties() : null;
370: }
371:
372: @Override
373: public Set<FieldSpecification<? super X, ?>> getFieldSpecifications() {
374: final Set<FieldSpecification<? super X, ?>> specs = new HashSet<>(getAttributes());
375: final TypesSpecification<? super X, ?> types = getTypes();
376: if (types != null) {
377: specs.add(types);
378: }
379: final PropertiesSpecification<? super X, ?, ?, ?> props = getProperties();
380: if (props != null) {
381: specs.add(props);
382: }
383: return specs;
384: }
385:
386: @Override
387: public FieldSpecification<? super X, ?> getFieldSpecification(String fieldName) {
388: if (declaredAttributes.containsKey(fieldName)) {
389: return declaredAttributes.get(fieldName);
390: }
391: if (directTypes != null && directTypes.getName().equals(fieldName)) {
392: return directTypes;
393: } else if (properties != null && properties.getName().equals(fieldName)) {
394: return properties;
395: }
396: if (supertype != null) {
397: return supertype.getFieldSpecification(fieldName);
398: }
399: throw new IllegalArgumentException("Field " + fieldName + " is not present in type " + this);
400: }
401:
402: @Override
403: public Identifier getIdentifier() {
404: if (identifier != null) {
405: return identifier;
406: }
407: if (supertype != null) {
408: return supertype.getIdentifier();
409: }
410: // This shouldn't happen, because every entity has to contain an identifier, otherwise metamodel building fails
411: throw new IllegalArgumentException("Identifier attribute is not present in type " + this);
412: }
413:
414: @Override
415: public Class<X> getJavaType() {
416: return javaType;
417: }
418:
419: public List<Method> getLifecycleListeners(LifecycleEvent event) {
420: final List<Method> hooks = supertype != null ? supertype.getLifecycleListeners(event) : new ArrayList<>();
421: if (lifecycleHooks.containsKey(event)) {
422: hooks.add(lifecycleHooks.get(event));
423: }
424: return hooks;
425: }
426:
427: public boolean hasLifecycleListeners(LifecycleEvent event) {
428: return hasDeclaredLifecycleListener(event) || (supertype != null && supertype.hasLifecycleListeners(event));
429: }
430:
431: public boolean hasDeclaredLifecycleListener(LifecycleEvent event) {
432: return lifecycleHooks.containsKey(event);
433: }
434: }