-
Notifications
You must be signed in to change notification settings - Fork 14
/
Descriptor.java
230 lines (201 loc) · 7.78 KB
/
Descriptor.java
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
/**
* Copyright (C) 2019 Czech Technical University in Prague
* <p>
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
* version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details. You should have received a copy of the GNU General Public License along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
package cz.cvut.kbss.jopa.model.descriptors;
import cz.cvut.kbss.jopa.model.metamodel.FieldSpecification;
import java.lang.reflect.Field;
import java.net.URI;
import java.util.*;
/**
* Defines base descriptor, which is used to specify context information for entities and their fields.
* <p>
* The descriptor hierarchy is a classical <b>Composite</b> pattern.
*/
public abstract class Descriptor {
protected final URI context;
protected final boolean assertionsInSubjectContext;
private String language;
private boolean hasLanguage;
protected Descriptor() {
this(null);
}
protected Descriptor(boolean assertionsInSubjectContext) {
this(null, assertionsInSubjectContext);
}
protected Descriptor(URI context) {
this.context = context;
this.assertionsInSubjectContext = true;
}
protected Descriptor(URI context, boolean assertionsInSubjectContext) {
this.context = context;
this.assertionsInSubjectContext = assertionsInSubjectContext;
}
/**
* Gets context for this descriptor.
* <p>
* Note that the context URI may be {@code null}, meaning that the default context is referenced
*
* @return Context URI
*/
public URI getContext() {
return context;
}
/**
* Gets the language set for this descriptor.
*
* @return Language tag (e.g. en, cs), can be {@code null}, meaning any language is supported or the language tag
* has not been set (see {@link #hasLanguage()})
*/
public String getLanguage() {
return language;
}
/**
* Gets information about whether language tag has been set on this descriptor.
* <p>
* The language tag can be explicitly set to {@code null}, meaning any language is supported. This can be used to
* override PU-level language setting.
*
* @return {@code true} if a language tag has been set on this descriptor, {@code false} otherwise
*/
public boolean hasLanguage() {
return hasLanguage;
}
/**
* Sets language tag of this descriptor.
* <p>
* Applies to any possible sub-descriptors as well.
*
* @param languageTag The language tag to use, possibly {@code null}, meaning no language preference should be used
* @see #anyLanguage()
*/
public Descriptor setLanguage(String languageTag) {
this.language = languageTag;
this.hasLanguage = true;
return this;
}
/**
* Configures this descriptor to support any language tag (including no language tags).
* <p>
* This is useful for overriding previously set language tag expectations (either on PU level or parent descriptor
* level).
* <p>
* This does the same as calling {@link #setLanguage(String)} with {@code null} argument, but is more explicit.
*/
public Descriptor anyLanguage() {
return setLanguage(null);
}
/**
* Gets attribute descriptors specified in this descriptor.
*
* @return Unmodifiable view of attribute descriptors
*/
public abstract Collection<Descriptor> getAttributeDescriptors();
/**
* Gets descriptor for the specified attribute.
*
* @param attribute Entity attribute, as specified by the application metamodel
* @return Descriptor
* @throws IllegalArgumentException If the descriptor is not available
*/
public abstract Descriptor getAttributeDescriptor(FieldSpecification<?, ?> attribute);
/**
* Gets context in which the property assertion(s) of the specified attribute should be stored.
*
* @param attribute Entity attribute, as specified by the application model
* @return Context identifier
*/
public abstract URI getAttributeContext(FieldSpecification<?, ?> attribute);
/**
* Adds descriptor for the specified attribute.
*
* @param attribute The attribute to set descriptor for
* @param descriptor The descriptor to use
*/
public abstract Descriptor addAttributeDescriptor(Field attribute, Descriptor descriptor);
/**
* Adds repository context for the specified attribute.
* <p>
* This in effect means creating a descriptor for the specified field with the specified context.
*
* @param attribute The attribute to set context for
* @param context The context to set
* @see #addAttributeDescriptor(Field, Descriptor)
*/
public abstract Descriptor addAttributeContext(Field attribute, URI context);
/**
* Sets language to be used when working (retrieving, persisting) with values of the specified attribute.
* <p>
* Note that setting language in this manner will not have any effect on descriptors of the specified attribute
* previously retrieved from this descriptor.
*
* @param attribute The attribute concerned
* @param languageTag Language tag to use, possibly {@code null}
*/
public abstract Descriptor setAttributeLanguage(Field attribute, String languageTag);
/**
* Gets all contexts present in this descriptor.
* <p>
* If any of the descriptors specifies the default context, an empty set is returned.
* <p>
* In case of entity descriptor this means recursively asking all of its attributes for their context.
*
* @return Set of context URIs or an empty set, if the default one should be used
*/
public Set<URI> getAllContexts() {
Set<URI> contexts = new HashSet<>();
contexts = getContextsInternal(contexts, new HashSet<>());
return contexts != null ? contexts : Collections.emptySet();
}
/**
* Gets the contexts, discarding any already visited descriptors.
*
* @param contexts Contexts collected so far
* @param visited Visited descriptors
* @return Already visited contexts + those found in this descriptor
*/
protected abstract Set<URI> getContextsInternal(Set<URI> contexts, Set<Descriptor> visited);
/**
* Whether this descriptor can override parent descriptor's assertionsInSubjectContext setting.
*/
protected boolean overridesAssertionsInSubjectContext() {
return false;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Descriptor)) {
return false;
}
Descriptor that = (Descriptor) o;
if (hasLanguage != that.hasLanguage) {
return false;
}
if (assertionsInSubjectContext != that.assertionsInSubjectContext) {
return false;
}
return Objects.equals(context, that.context) && Objects.equals(language, that.language);
}
@Override
public int hashCode() {
int result = context != null ? context.hashCode() : 0;
result = 31 * result + (language != null ? language.hashCode() : 0);
result = 31 * result + (hasLanguage ? 1 : 0);
result = 31 * result + (assertionsInSubjectContext ? 1 : 0);
return result;
}
@Override
public String toString() {
return context != null ? context.toString() : "default_context";
}
}