-
Notifications
You must be signed in to change notification settings - Fork 28
/
CodeSystemUtils.java
388 lines (305 loc) · 14.6 KB
/
CodeSystemUtils.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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
/*
* Copyright 2011-2015 B2i Healthcare Pte Ltd, http:https://b2i.sg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.b2international.snowowl.datastore;
import static com.b2international.snowowl.core.ApplicationContext.getServiceForClass;
import static com.b2international.snowowl.datastore.BranchPathUtils.isMain;
import static com.google.common.base.Strings.nullToEmpty;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.b2international.snowowl.core.ApplicationContext;
import com.b2international.snowowl.core.CoreTerminologyBroker;
import com.b2international.snowowl.core.api.IBranchPath;
import com.b2international.snowowl.core.api.NullBranchPath;
import com.b2international.snowowl.core.api.SnowowlRuntimeException;
import com.b2international.snowowl.core.date.Dates;
import com.b2international.snowowl.datastore.cdo.ICDOConnection;
import com.b2international.snowowl.datastore.cdo.ICDOConnectionManager;
import com.b2international.snowowl.datastore.cdo.ICDOManagedItem;
import com.b2international.snowowl.datastore.tasks.TaskManager;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
/**
* Contains various continent methods for {@link ICodeSystem} and {@link ICodeSystemVersion}.
*
*/
public class CodeSystemUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(CodeSystemUtils.class);
/**
* Predicate for selecting those {@link ICodeSystem}s:
* <li/> that are residing in the repository denoted by the given repositoryUuid
* <li/> whose branch path matches the active branch's path.
*
* Note: if the active branch is a task branch, this predicate will ignore the last segment (task id part) of the active branch path.
*/
private static final class ActiveCodeSystemPredicate implements Predicate<ICodeSystem> {
private final IBranchPathMap branchPathMap;
private final String repositoryUuid;
private ActiveCodeSystemPredicate(IBranchPathMap branchPathMap, String repositoryUuid) {
this.branchPathMap = branchPathMap;
this.repositoryUuid = repositoryUuid;
}
@Override
public boolean apply(ICodeSystem input) {
IBranchPath activeBranchPath = branchPathMap.getBranchPath(repositoryUuid);
//ignore last segment if we are on a task branch
if (getServiceForClass(TaskManager.class).hasActiveTask())
return activeBranchPath.getParentPath().equals(input.getBranchPath());
return activeBranchPath.getPath().equals(input.getBranchPath());
}
}
private static final class SameRepositoryCodeSystemPredicate implements Predicate<ICodeSystem> {
private final String repositoryUUID;
private SameRepositoryCodeSystemPredicate(String repositoryUUID) {
this.repositoryUUID = Preconditions.checkNotNull(repositoryUUID, "repository UUID cannot be null");
}
@Override
public boolean apply(ICodeSystem input) {
return input.getRepositoryUuid().equals(repositoryUUID);
}
}
/**
* Predicate, which selects code systems, that represent the MAIN for its terminology.
* In other words: Predicate, which doesn't let extension code systems through.
*/
private static final class MainCodeSystemPredicate implements Predicate<ICodeSystem> {
@Override
public boolean apply(ICodeSystem input) {
return BranchPathUtils.isMain(input.getBranchPath());
}
}
/**
* Function to turn {@link ICodeSystem} into it's short name.
*/
public static final class CodeSystemToShortNameFunction implements Function<ICodeSystem, String> {
@Override
public String apply(ICodeSystem input) {
return input.getShortName();
}
}
/**
* Function to turn {@link ICodeSystem} into it's repository Uuid.
*/
public static final class CodeSystemToRepositoryUuidFunction implements Function<ICodeSystem, String> {
@Override
public String apply(ICodeSystem input) {
return input.getRepositoryUuid();
}
}
/**
* Function to turn {@link ICodeSystem} into it's branch path string.
*/
public static final class CodeSystemToBranchPathFunction implements Function<ICodeSystem, String> {
@Override
public String apply(ICodeSystem input) {
return input.getBranchPath();
}
}
private static final LoadingCache<String, ICDOManagedItem<?>> TOOLING_ID_MANAGED_ITEM_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<String, ICDOManagedItem<?>>() {
@Override public ICDOManagedItem<?> load(final String toolingId) throws Exception {
Preconditions.checkNotNull(toolingId, "Snow Owl terminology ID argument cannot be null.");
final String terminologyId = CoreTerminologyBroker.getInstance().getAllRegisteredTerminologies().contains(toolingId)
? toolingId
: CoreTerminologyBroker.getInstance().getTerminologyIdForTerminologyComponentId(toolingId);
for (final ICDOManagedItem<?> item : getServiceForClass(ICDOConnectionManager.class)) {
if (terminologyId.equals(item.getSnowOwlTerminologyComponentId())) {
return item;
}
}
throw new NullPointerException("Cannot find managed item for: '" + toolingId + "'.");
}
});
/**
* Comparator for sorting repository UUIDs in an alphabetic order based on the corresponding tooling feature name.
*/
public static final Comparator<String> TOOLING_FEATURE_NAME_COMPARATOR = new Comparator<String>() {
public int compare(final String leftUuid, final String rightUuid) {
final String leftName = nullToEmpty(CodeSystemUtils.getSnowOwlToolingName(leftUuid));
final String rightName = nullToEmpty(CodeSystemUtils.getSnowOwlToolingName(rightUuid));
return leftName.compareToIgnoreCase(rightName);
}
};
/**
* Returns with the {@link ICodeSystemVersion version} matching with the branch path argument from the given iterable of code system versions
* @param branchPath the branch path.
* @param versions an iterable of code system version.
* @return the matching code system version, or {@code null} if not found.
*/
@Nullable public static ICodeSystemVersion findMatchingVersion(IBranchPath branchPath, final Iterable<? extends ICodeSystemVersion> versions) {
Preconditions.checkNotNull(branchPath, "Branch path argument cannot be null.");
Preconditions.checkNotNull(versions, "Versions argument cannot be null.");
while (NullBranchPath.INSTANCE != branchPath) {
final String versionIdForRepository = branchPath.lastSegment();
for (final ICodeSystemVersion candidate : versions) {
if (candidate.getVersionId().equals(versionIdForRepository)) {
return candidate;
}
}
branchPath = branchPath.getParent();
}
return null;
}
/**
* Checks if the branchPath passed-in, corresponds to a version's branch path. If so, it returns the argument wrapped in an {@link Optional}.
* If not, it iterates upward on the branch's parentage, checking if parent's path is a version's branchPath.
* If none of the branchPaths in the parentage correspond to a version branchPath, it returns {@link Optional#absent()}.
* @param activeBranchPath
* @return
*/
public static Optional<IBranchPath> tryFindVersionBranchPath(final IBranchPath branchPath) {
if (BranchPathUtils.isMain(branchPath))
return Optional.absent();
if(isParsableDate(branchPath.lastSegment())) {
return Optional.of(branchPath);
}
return tryFindVersionBranchPath(branchPath.getParent());
}
private static boolean isParsableDate(String dateString) {
try {
Dates.parse(dateString);
return true;
} catch (SnowowlRuntimeException | NullPointerException e) {
return false;
}
}
public static ICodeSystem findMatchingCodeSystem(String branchPath, String repositoryUuid) {
return findMatchingCodeSystem(BranchPathUtils.createPath(branchPath), repositoryUuid);
}
public static ICodeSystem findMatchingCodeSystem(IBranchPath branchPath, String repositoryUuid) {
// branchPath can be: main, task branch, version/tag branch Path, extension branchPath
Iterable<ICodeSystem> codeSystemsInRepositoryUuid = Iterables.filter(getTerminologyRegistryService().getCodeSystems(new UserBranchPathMap()), sameRepositoryCodeSystemPredicate(repositoryUuid));
Map<String, ICodeSystem> branchPathToCodeSystemMap = Maps.uniqueIndex(codeSystemsInRepositoryUuid, new CodeSystemToBranchPathFunction());
// if (branchPathToCodeSystemMap.containsKey(branchPath.getPath()))
// return branchPathToCodeSystemMap.get(branchPath.getPath());
for (IBranchPath path = branchPath; !isMain(path); path = path.getParent()) {
if (branchPathToCodeSystemMap.containsKey(path.getPath())) {
return branchPathToCodeSystemMap.get(path.getPath());
}
}
// falling back to the repositoryUUID's main code system.
return Iterables.find(codeSystemsInRepositoryUuid, new MainCodeSystemPredicate());
}
/**
* Returns with the UUID of the repository associated with the given
* application specific tooling ID.
* @param snowOwlToolingId the application specific tooling ID. Could be both terminology and terminology component IDs.
* @return the UUID of the repository which is associated with a Snow Owl specific tooling feature.
*/
@Nullable public static String getRepositoryUuid(final String snowOwlToolingId) {
Preconditions.checkNotNull(snowOwlToolingId, "Snow Owl tooling ID argument cannot be null.");
return getAttribute(snowOwlToolingId, new Function<ICDOManagedItem<?>, String>() {
@Override public String apply(final ICDOManagedItem<?> item) {
return item.getUuid();
}
});
}
/**
* Returns with the human readable name of the repository associated with the given
* application specific tooling ID.
* @param snowOwlToolingId the application specific tooling ID. Could be both terminology and terminology component IDs.
* @return the human readable name of the repository which is associated with a Snow Owl specific tooling feature.
*/
@Nullable public static String getRepositoryName(final String snowOwlToolingId) {
Preconditions.checkNotNull(snowOwlToolingId, "Snow Owl tooling ID argument cannot be null.");
return getAttribute(snowOwlToolingId, new Function<ICDOManagedItem<?>, String>() {
@Override public String apply(final ICDOManagedItem<?> item) {
return item.getRepositoryName();
}
});
}
/**Sugar for {@link #getRepositoryUuid(String)}.<br>Returns with the repository UUID for the application specific
*component identifier.*/
@Nullable public static String getRepositoryUuid(final short terminologyComponentId) {
if (CoreTerminologyBroker.UNSPECIFIED_NUMBER_SHORT == terminologyComponentId) {
return null;
}
final String terminologyComponentIdAsString = CoreTerminologyBroker.getInstance().getTerminologyComponentId(terminologyComponentId);
return CodeSystemUtils.getRepositoryUuid(terminologyComponentIdAsString);
}
/**
* Returns with the application specific human readable tooling name associated with a repository given by its unique UUID.
* @param repositoryUuid the unique UUID of a repository.
* @return the application specific tooling name.
*/
public static String getSnowOwlToolingName(final String repositoryUuid) {
Preconditions.checkNotNull(repositoryUuid, "Repository UUID argument cannot be null.");
return getConnection(repositoryUuid).getSnowOwlTerminologyComponentName();
}
/**
* Returns with the application specific tooling ID associated with a repository given by its unique UUID.
* @param repositoryUuid the unique UUID of a repository.
* @return the application specific tooling ID.
*/
public static String getSnowOwlToolingId(final String repositoryUuid) {
Preconditions.checkNotNull(repositoryUuid, "Repository UUID argument cannot be null.");
return getConnection(repositoryUuid).getSnowOwlTerminologyComponentId();
}
public static Predicate<ICodeSystem> sameRepositoryCodeSystemPredicate(final String repositoryUUID) {
return new SameRepositoryCodeSystemPredicate(repositoryUUID);
}
public static Predicate<ICodeSystem> activeCodeSystemPredicate(final IBranchPathMap branchPathMap, final String repositoryUuid) {
return new ActiveCodeSystemPredicate(branchPathMap, repositoryUuid);
}
public static Predicate<ICodeSystem> mainCodeSystemPredicate() {
return new MainCodeSystemPredicate();
}
public static Function<ICodeSystem, String> toShortNameFunction() {
return new CodeSystemToShortNameFunction();
}
public static Function<ICodeSystem, String> toRepositoryUuidFunction() {
return new CodeSystemToRepositoryUuidFunction();
}
public static Function<ICodeSystem, String> toBranchPathFunction() {
return new CodeSystemToBranchPathFunction();
}
/*returns with the connection for the given repository UUID*/
private static ICDOConnection getConnection(final String repositoryUuid) {
return getConnectionManager().getByUuid(repositoryUuid);
}
/*returns with the connection manager service*/
private static ICDOConnectionManager getConnectionManager() {
return ApplicationContext.getInstance().getService(ICDOConnectionManager.class);
}
/*returns with the task manager service*/
private static TaskManager getTaskManager() {
return ApplicationContext.getInstance().getService(TaskManager.class);
}
/*returns with the terminology registry service*/
private static TerminologyRegistryService getTerminologyRegistryService() {
return ApplicationContext.getInstance().getService(TerminologyRegistryService.class);
}
/*applies the given function on a CDO manager item which application specific tooling ID equals with the argument.
*both terminology and terminology component IDs are allowed as Snow Owl tooling ID.*/
private static <T> T getAttribute(final String toolingId, final Function<ICDOManagedItem<?>, T> f) {
try {
Preconditions.checkNotNull(toolingId, "Snow Owl terminology ID argument cannot be null.");
return f.apply(TOOLING_ID_MANAGED_ITEM_CACHE.get(toolingId));
} catch (final ExecutionException e) {
LOGGER.error("Cannot get property on managed item for ID: " + toolingId, e);
return null;
}
}
}