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 package gov.nist.secauto.oscal.lib.profile.resolver.policy;
28
29 import com.vladsch.flexmark.ast.InlineLinkNode;
30 import com.vladsch.flexmark.util.ast.Node;
31
32 import gov.nist.secauto.metaschema.model.common.datatype.markup.IMarkupString;
33 import gov.nist.secauto.metaschema.model.common.datatype.markup.flexmark.InsertAnchorExtension.InsertAnchorNode;
34 import gov.nist.secauto.metaschema.model.common.metapath.MetapathExpression;
35 import gov.nist.secauto.metaschema.model.common.metapath.format.IPathFormatter;
36 import gov.nist.secauto.metaschema.model.common.metapath.function.library.FnData;
37 import gov.nist.secauto.metaschema.model.common.metapath.item.IDocumentNodeItem;
38 import gov.nist.secauto.metaschema.model.common.metapath.item.IMarkupItem;
39 import gov.nist.secauto.metaschema.model.common.metapath.item.IRequiredValueModelNodeItem;
40 import gov.nist.secauto.metaschema.model.common.util.CollectionUtil;
41 import gov.nist.secauto.metaschema.model.common.util.ObjectUtils;
42 import gov.nist.secauto.oscal.lib.model.CatalogGroup;
43 import gov.nist.secauto.oscal.lib.model.Control;
44 import gov.nist.secauto.oscal.lib.model.ControlPart;
45 import gov.nist.secauto.oscal.lib.model.Link;
46 import gov.nist.secauto.oscal.lib.model.Property;
47 import gov.nist.secauto.oscal.lib.model.metadata.AbstractProperty;
48 import gov.nist.secauto.oscal.lib.model.metadata.IProperty;
49 import gov.nist.secauto.oscal.lib.profile.resolver.support.AbstractCatalogEntityVisitor;
50 import gov.nist.secauto.oscal.lib.profile.resolver.support.IEntityItem;
51 import gov.nist.secauto.oscal.lib.profile.resolver.support.IIndexer;
52
53 import org.apache.logging.log4j.LogManager;
54 import org.apache.logging.log4j.Logger;
55
56 import java.net.URI;
57 import java.util.EnumSet;
58 import java.util.HashMap;
59 import java.util.HashSet;
60 import java.util.Locale;
61 import java.util.Map;
62 import java.util.Set;
63 import java.util.UUID;
64 import java.util.function.BiConsumer;
65
66 import javax.xml.namespace.QName;
67
68 import edu.umd.cs.findbugs.annotations.NonNull;
69 import edu.umd.cs.findbugs.annotations.Nullable;
70 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
71
72 public class ReferenceCountingVisitor
73 extends AbstractCatalogEntityVisitor<ReferenceCountingVisitor.Context, Void>
74 implements IReferenceVisitor<ReferenceCountingVisitor.Context> {
75 private static final Logger LOGGER = LogManager.getLogger(ReferenceCountingVisitor.class);
76
77 private static final ReferenceCountingVisitor SINGLETON = new ReferenceCountingVisitor();
78
79 @NonNull
80 private static final MetapathExpression PARAM_MARKUP_METAPATH
81 = MetapathExpression
82 .compile("label|usage|constraint/(description|tests/remarks)|guideline/prose|select/choice|remarks");
83 @NonNull
84 private static final MetapathExpression ROLE_MARKUP_METAPATH
85 = MetapathExpression.compile("title|description|remarks");
86 @NonNull
87 private static final MetapathExpression LOCATION_MARKUP_METAPATH
88 = MetapathExpression.compile("title|remarks");
89 @NonNull
90 private static final MetapathExpression PARTY_MARKUP_METAPATH
91 = MetapathExpression.compile("title|remarks");
92 @NonNull
93 private static final MetapathExpression RESOURCE_MARKUP_METAPATH
94 = MetapathExpression.compile("title|description|remarks");
95
96 @NonNull
97 private static final IReferencePolicy<Property> PROPERTY_POLICY_IGNORE = IReferencePolicy.ignore();
98 @NonNull
99 private static final IReferencePolicy<Link> LINK_POLICY_IGNORE = IReferencePolicy.ignore();
100
101 @NonNull
102 private static final Map<QName, IReferencePolicy<Property>> PROPERTY_POLICIES;
103 @NonNull
104 private static final Map<String, IReferencePolicy<Link>> LINK_POLICIES;
105 @NonNull
106 private static final InsertReferencePolicy INSERT_POLICY = new InsertReferencePolicy();
107 @NonNull
108 private static final AnchorReferencePolicy ANCHOR_POLICY = new AnchorReferencePolicy();
109
110 static {
111 PROPERTY_POLICIES = new HashMap<>();
112 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.OSCAL_NAMESPACE, "resolution-tool"), PROPERTY_POLICY_IGNORE);
113 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.OSCAL_NAMESPACE, "label"), PROPERTY_POLICY_IGNORE);
114 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.OSCAL_NAMESPACE, "sort-id"), PROPERTY_POLICY_IGNORE);
115 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.OSCAL_NAMESPACE, "alt-label"), PROPERTY_POLICY_IGNORE);
116 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.OSCAL_NAMESPACE, "alt-identifier"), PROPERTY_POLICY_IGNORE);
117 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.OSCAL_NAMESPACE, "method"), PROPERTY_POLICY_IGNORE);
118 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.OSCAL_NAMESPACE, "keep"), PROPERTY_POLICY_IGNORE);
119 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.RMF_NAMESPACE, "method"), PROPERTY_POLICY_IGNORE);
120 PROPERTY_POLICIES.put(AbstractProperty.qname(IProperty.RMF_NAMESPACE, "aggregates"),
121 PropertyReferencePolicy.create(IIdentifierParser.IDENTITY_PARSER, IEntityItem.ItemType.PARAMETER));
122
123 LINK_POLICIES = new HashMap<>();
124 LINK_POLICIES.put("source-profile", LINK_POLICY_IGNORE);
125 LINK_POLICIES.put("citation", LinkReferencePolicy.create(IEntityItem.ItemType.RESOURCE));
126 LINK_POLICIES.put("reference", LinkReferencePolicy.create(IEntityItem.ItemType.RESOURCE));
127 LINK_POLICIES.put("related", LinkReferencePolicy.create(IEntityItem.ItemType.CONTROL));
128 LINK_POLICIES.put("required", LinkReferencePolicy.create(IEntityItem.ItemType.CONTROL));
129 LINK_POLICIES.put("corresp", LinkReferencePolicy.create(IEntityItem.ItemType.PART));
130 }
131
132 public static ReferenceCountingVisitor instance() {
133 return SINGLETON;
134 }
135
136 public ReferenceCountingVisitor() {
137
138
139
140 super(ObjectUtils.notNull(EnumSet.complementOf(
141 EnumSet.of(
142 IEntityItem.ItemType.PART,
143 IEntityItem.ItemType.ROLE,
144 IEntityItem.ItemType.LOCATION,
145 IEntityItem.ItemType.PARTY,
146 IEntityItem.ItemType.PARAMETER,
147 IEntityItem.ItemType.RESOURCE))));
148 }
149
150 @Override
151 protected Void newDefaultResult(Context context) {
152
153 return null;
154 }
155
156 @Override
157 protected Void aggregateResults(Void first, Void second, Context context) {
158
159 return null;
160 }
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179 public void visitCatalog(@NonNull IDocumentNodeItem catalogItem, @NonNull IIndexer indexer, @NonNull URI baseUri) {
180 Context context = new Context(indexer, baseUri);
181 visitCatalog(catalogItem, context);
182
183 IIndexer index = context.getIndexer();
184
185
186 IIndexer.getReferencedEntitiesAsStream(index.getEntitiesByItemType(IEntityItem.ItemType.ROLE))
187 .forEachOrdered(
188 item -> resolveEntity(ObjectUtils.notNull(item), context, ReferenceCountingVisitor::resolveRole));
189 IIndexer.getReferencedEntitiesAsStream(index.getEntitiesByItemType(IEntityItem.ItemType.LOCATION))
190 .forEachOrdered(
191 item -> resolveEntity(ObjectUtils.notNull(item), context,
192 ReferenceCountingVisitor::resolveLocation));
193 IIndexer.getReferencedEntitiesAsStream(index.getEntitiesByItemType(IEntityItem.ItemType.PARTY))
194 .forEachOrdered(
195 item -> resolveEntity(ObjectUtils.notNull(item), context,
196 ReferenceCountingVisitor::resolveParty));
197 IIndexer.getReferencedEntitiesAsStream(index.getEntitiesByItemType(IEntityItem.ItemType.PARAMETER))
198 .forEachOrdered(
199 item -> resolveEntity(ObjectUtils.notNull(item), context,
200 ReferenceCountingVisitor::resolveParameter));
201 IIndexer.getReferencedEntitiesAsStream(index.getEntitiesByItemType(IEntityItem.ItemType.RESOURCE))
202 .forEachOrdered(
203 item -> resolveEntity(ObjectUtils.notNull(item), context,
204 ReferenceCountingVisitor::resolveResource));
205 }
206
207 @Override
208 public Void visitGroup(@NonNull IRequiredValueModelNodeItem item, Void childResult, Context context) {
209 IIndexer index = context.getIndexer();
210
211
212
213 if (IIndexer.SelectionStatus.SELECTED.equals(index.getSelectionStatus(item))) {
214 CatalogGroup group = (CatalogGroup) item.getValue();
215 String id = group.getId();
216
217 boolean resolve;
218 if (id == null) {
219
220 resolve = true;
221 } else {
222 IEntityItem entity = index.getEntity(IEntityItem.ItemType.GROUP, id, false);
223 if (entity != null && !context.isResolved(entity)) {
224
225 context.markResolved(entity);
226 resolve = true;
227 } else {
228 resolve = false;
229 }
230 }
231
232
233 if (resolve) {
234 resolveGroup(item, context);
235 }
236 }
237 return null;
238 }
239
240 @Override
241 public Void visitControl(@NonNull IRequiredValueModelNodeItem item, Void childResult, Context context) {
242 IIndexer index = context.getIndexer();
243
244 if (IIndexer.SelectionStatus.SELECTED.equals(index.getSelectionStatus(item))) {
245 Control control = (Control) item.getValue();
246 IEntityItem entity
247 = context.getIndexer().getEntity(IEntityItem.ItemType.CONTROL, ObjectUtils.notNull(control.getId()), false);
248
249
250 assert entity != null;
251
252 if (!context.isResolved(entity)) {
253 context.markResolved(entity);
254 if (IIndexer.SelectionStatus.SELECTED.equals(context.getIndexer().getSelectionStatus(item))) {
255 resolveControl(item, context);
256 }
257 }
258 }
259 return null;
260 }
261
262 @Override
263 protected void visitParts(@NonNull IRequiredValueModelNodeItem groupOrControlItem, Context context) {
264
265 CHILD_PART_METAPATH.evaluate(groupOrControlItem).asStream()
266 .map(item -> (IRequiredValueModelNodeItem) item)
267 .forEachOrdered(partItem -> {
268 visitPart(ObjectUtils.notNull(partItem), groupOrControlItem, context);
269 });
270 }
271
272 @Override
273 protected void visitPart(IRequiredValueModelNodeItem item, IRequiredValueModelNodeItem groupOrControlItem,
274 Context context) {
275 assert context != null;
276
277 ControlPart part = (ControlPart) item.getValue();
278 String id = part.getId();
279
280 boolean resolve;
281 if (id == null) {
282
283 resolve = true;
284 } else {
285 IEntityItem entity = context.getIndexer().getEntity(IEntityItem.ItemType.PART, id, false);
286 if (entity != null && !context.isResolved(entity)) {
287
288 context.markResolved(entity);
289 resolve = true;
290 } else {
291 resolve = false;
292 }
293 }
294
295 if (resolve) {
296 resolvePart(item, context);
297 }
298 }
299
300 protected void resolveGroup(
301 @NonNull IRequiredValueModelNodeItem item,
302 @NonNull Context context) {
303 if (IIndexer.SelectionStatus.SELECTED.equals(context.getIndexer().getSelectionStatus(item))) {
304
305
306 item.getModelItemsByName("title").forEach(child -> handleMarkup(ObjectUtils.notNull(child), context));
307 item.getModelItemsByName("prop").forEach(child -> handleProperty(ObjectUtils.notNull(child), context));
308 item.getModelItemsByName("link").forEach(child -> handleLink(ObjectUtils.notNull(child), context));
309
310
311 visitParts(item, context);
312
313
314 }
315 }
316
317 protected void resolveControl(
318 @NonNull IRequiredValueModelNodeItem item,
319 @NonNull Context context) {
320
321 item.getModelItemsByName("title").forEach(child -> handleMarkup(ObjectUtils.notNull(child), context));
322 item.getModelItemsByName("prop").forEach(child -> handleProperty(ObjectUtils.notNull(child), context));
323 item.getModelItemsByName("link").forEach(child -> handleLink(ObjectUtils.notNull(child), context));
324
325
326 visitParts(item, context);
327
328
329 }
330
331 private static void resolveRole(@NonNull IEntityItem entity, @NonNull Context context) {
332 IRequiredValueModelNodeItem item = entity.getInstance();
333 item.getModelItemsByName("prop").forEach(child -> handleProperty(ObjectUtils.notNull(child), context));
334 item.getModelItemsByName("link").forEach(child -> handleLink(ObjectUtils.notNull(child), context));
335 ROLE_MARKUP_METAPATH.evaluate(item).asList()
336 .forEach(child -> handleMarkup(ObjectUtils.notNull((IRequiredValueModelNodeItem) child), context));
337 }
338
339 private static void resolveParty(@NonNull IEntityItem entity, @NonNull Context context) {
340 IRequiredValueModelNodeItem item = entity.getInstance();
341 item.getModelItemsByName("prop").forEach(child -> handleProperty(ObjectUtils.notNull(child), context));
342 item.getModelItemsByName("link").forEach(child -> handleLink(ObjectUtils.notNull(child), context));
343 PARTY_MARKUP_METAPATH.evaluate(item).asList()
344 .forEach(child -> handleMarkup(ObjectUtils.notNull((IRequiredValueModelNodeItem) child), context));
345 }
346
347 public static void resolveLocation(@NonNull IEntityItem entity, @NonNull Context context) {
348 IRequiredValueModelNodeItem item = entity.getInstance();
349 item.getModelItemsByName("prop").forEach(child -> handleProperty(ObjectUtils.notNull(child), context));
350 item.getModelItemsByName("link").forEach(child -> handleLink(ObjectUtils.notNull(child), context));
351 LOCATION_MARKUP_METAPATH.evaluate(item).asList()
352 .forEach(child -> handleMarkup(ObjectUtils.notNull((IRequiredValueModelNodeItem) child), context));
353 }
354
355 public static void resolveResource(@NonNull IEntityItem entity, @NonNull Context context) {
356 IRequiredValueModelNodeItem item = entity.getInstance();
357
358 item.getModelItemsByName("prop").forEach(child -> handleProperty(ObjectUtils.notNull(child), context));
359
360 item.getModelItemsByName("citation").forEach(child -> {
361 if (child != null) {
362 child.getModelItemsByName("text")
363 .forEach(citationChild -> handleMarkup(ObjectUtils.notNull(citationChild), context));
364 child.getModelItemsByName("prop")
365 .forEach(citationChild -> handleProperty(ObjectUtils.notNull(citationChild), context));
366 child.getModelItemsByName("link")
367 .forEach(citationChild -> handleLink(ObjectUtils.notNull(citationChild), context));
368 }
369 });
370
371 RESOURCE_MARKUP_METAPATH.evaluate(item).asList()
372 .forEach(child -> handleMarkup(ObjectUtils.notNull((IRequiredValueModelNodeItem) child), context));
373 }
374
375 public static void resolveParameter(@NonNull IEntityItem entity, @NonNull Context context) {
376 IRequiredValueModelNodeItem item = entity.getInstance();
377
378 item.getModelItemsByName("prop").forEach(child -> handleProperty(ObjectUtils.notNull(child), context));
379 item.getModelItemsByName("link").forEach(child -> handleLink(ObjectUtils.notNull(child), context));
380 PARAM_MARKUP_METAPATH.evaluate(item).asList()
381 .forEach(child -> handleMarkup(ObjectUtils.notNull((IRequiredValueModelNodeItem) child), context));
382 }
383
384 private static void resolvePart(
385 @NonNull IRequiredValueModelNodeItem item,
386 @NonNull Context context) {
387 item.getModelItemsByName("title").forEach(child -> handleMarkup(ObjectUtils.notNull(child), context));
388 item.getModelItemsByName("prop").forEach(child -> handleProperty(ObjectUtils.notNull(child), context));
389 item.getModelItemsByName("link").forEach(child -> handleLink(ObjectUtils.notNull(child), context));
390 item.getModelItemsByName("prose").forEach(child -> handleMarkup(ObjectUtils.notNull(child), context));
391
392
393
394 }
395
396 private static void handleMarkup(
397 @NonNull IRequiredValueModelNodeItem item,
398 @NonNull Context context) {
399 IMarkupItem markupItem = (IMarkupItem) FnData.fnDataItem(item);
400 IMarkupString<?> markup = markupItem.getValue();
401 handleMarkup(item, markup, context);
402 }
403
404 private static void handleMarkup(
405 @NonNull IRequiredValueModelNodeItem contextItem,
406 @NonNull IMarkupString<?> text,
407 @NonNull Context context) {
408 for (Node node : CollectionUtil.toIterable(text.getNodesAsStream().iterator())) {
409 if (node instanceof InsertAnchorNode) {
410 handleInsert(contextItem, (InsertAnchorNode) node, context);
411 } else if (node instanceof InlineLinkNode) {
412 handleAnchor(contextItem, (InlineLinkNode) node, context);
413 }
414 }
415 }
416
417 private static void handleInsert(
418 @NonNull IRequiredValueModelNodeItem contextItem,
419 @NonNull InsertAnchorNode node,
420 @NonNull Context context) {
421 boolean retval = INSERT_POLICY.handleReference(contextItem, node, context);
422 if (LOGGER.isWarnEnabled() && !retval) {
423 LOGGER.atWarn().log("Unsupported insert type '{}' at '{}'",
424 node.getType().toString(),
425 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER));
426 }
427 }
428
429 private static void handleAnchor(
430 @NonNull IRequiredValueModelNodeItem contextItem,
431 @NonNull InlineLinkNode node,
432 @NonNull Context context) {
433 boolean result = ANCHOR_POLICY.handleReference(contextItem, node, context);
434 if (LOGGER.isWarnEnabled() && !result) {
435 LOGGER.atWarn().log("Unsupported anchor with href '{}' at '{}'",
436 node.getUrl().toString(),
437 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER));
438 }
439 }
440
441 private static void handleProperty(
442 @NonNull IRequiredValueModelNodeItem item,
443 @NonNull Context context) {
444 Property property = (Property) item.getValue();
445 QName qname = property.getQName();
446
447 IReferencePolicy<Property> policy = PROPERTY_POLICIES.get(qname);
448
449 boolean result = policy != null && policy.handleReference(item, property, context);
450 if (LOGGER.isWarnEnabled() && !result) {
451 LOGGER.atWarn().log("Unsupported property '{}' at '{}'",
452 property.getQName(),
453 item.toPath(IPathFormatter.METAPATH_PATH_FORMATER));
454 }
455 }
456
457 private static void handleLink(
458 @NonNull IRequiredValueModelNodeItem item,
459 @NonNull Context context) {
460 Link link = (Link) item.getValue();
461 IReferencePolicy<Link> policy = null;
462 String rel = link.getRel();
463 if (rel != null) {
464 policy = LINK_POLICIES.get(rel);
465 }
466
467 boolean result = policy != null && policy.handleReference(item, link, context);
468 if (LOGGER.isWarnEnabled() && !result) {
469 LOGGER.atWarn().log("unsupported link rel '{}' at '{}'",
470 link.getRel(),
471 item.toPath(IPathFormatter.METAPATH_PATH_FORMATER));
472 }
473 }
474
475 protected void resolveEntity(
476 @NonNull IEntityItem entity,
477 @NonNull Context context,
478 @NonNull BiConsumer<IEntityItem, Context> handler) {
479
480 if (!context.isResolved(entity)) {
481 context.markResolved(entity);
482
483 if (LOGGER.isDebugEnabled()) {
484 LOGGER.atDebug().log("Resolving {} identified as '{}'",
485 entity.getItemType().name(),
486 entity.getIdentifier());
487 }
488
489 if (!IIndexer.SelectionStatus.UNSELECTED
490 .equals(context.getIndexer().getSelectionStatus(entity.getInstance()))) {
491
492 handler.accept(entity, context);
493 }
494 }
495 }
496
497 public void resolveEntity(
498 @NonNull IEntityItem entity,
499 @NonNull Context context) {
500 resolveEntity(entity, context, (theEntity, theContext) -> entityDispatch(
501 ObjectUtils.notNull(theEntity),
502 ObjectUtils.notNull(theContext)));
503 }
504
505 protected void entityDispatch(@NonNull IEntityItem entity, @NonNull Context context) {
506 IRequiredValueModelNodeItem item = entity.getInstance();
507 switch (entity.getItemType()) {
508 case CONTROL:
509 resolveControl(item, context);
510 break;
511 case GROUP:
512 resolveGroup(item, context);
513 break;
514 case LOCATION:
515 resolveLocation(entity, context);
516 break;
517 case PARAMETER:
518 resolveParameter(entity, context);
519 break;
520 case PART:
521 resolvePart(item, context);
522 break;
523 case PARTY:
524 resolveParty(entity, context);
525 break;
526 case RESOURCE:
527 resolveResource(entity, context);
528 break;
529 case ROLE:
530 resolveRole(entity, context);
531 break;
532 default:
533 throw new UnsupportedOperationException(entity.getItemType().name());
534 }
535 }
536
537
538
539
540
541
542
543
544
545
546
547
548 public static final class Context {
549 @NonNull
550 private final IIndexer indexer;
551 @NonNull
552 private final URI source;
553 @NonNull
554 private final Set<IEntityItem> resolvedEntities = new HashSet<>();
555
556 private Context(@NonNull IIndexer indexer, @NonNull URI source) {
557 this.indexer = indexer;
558 this.source = source;
559 }
560
561 @NonNull
562 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "intending to expose this field")
563 public IIndexer getIndexer() {
564 return indexer;
565 }
566
567 @Nullable
568 public IEntityItem getEntity(@NonNull IEntityItem.ItemType itemType, @NonNull String identifier) {
569 return getIndexer().getEntity(itemType, identifier);
570 }
571
572 @SuppressWarnings("unused")
573 @NonNull
574 private URI getSource() {
575 return source;
576 }
577
578 public void markResolved(@NonNull IEntityItem entity) {
579 resolvedEntities.add(entity);
580 }
581
582 public boolean isResolved(@NonNull IEntityItem entity) {
583 return resolvedEntities.contains(entity);
584 }
585
586 public void incrementReferenceCount(
587 @NonNull IRequiredValueModelNodeItem contextItem,
588 @NonNull IEntityItem.ItemType type,
589 @NonNull UUID identifier) {
590 incrementReferenceCountInternal(
591 contextItem,
592 type,
593 ObjectUtils.notNull(identifier.toString()),
594 false);
595 }
596
597 public void incrementReferenceCount(
598 @NonNull IRequiredValueModelNodeItem contextItem,
599 @NonNull IEntityItem.ItemType type,
600 @NonNull String identifier) {
601 incrementReferenceCountInternal(
602 contextItem,
603 type,
604 identifier,
605 type.isUuid());
606 }
607
608 private void incrementReferenceCountInternal(
609 @NonNull IRequiredValueModelNodeItem contextItem,
610 @NonNull IEntityItem.ItemType type,
611 @NonNull String identifier,
612 boolean normalize) {
613 IEntityItem item = getIndexer().getEntity(type, identifier, normalize);
614 if (item == null) {
615 if (LOGGER.isErrorEnabled()) {
616 LOGGER.atError().log("Unknown reference to {} '{}' at '{}'",
617 type.toString().toLowerCase(Locale.ROOT),
618 identifier,
619 contextItem.toPath(IPathFormatter.METAPATH_PATH_FORMATER));
620 }
621 } else {
622 item.incrementReferenceCount();
623 }
624 }
625 }
626 }