All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.reprezen.genflow.api.normal.openapi.ContentLocalizer Maven / Gradle / Ivy

package com.reprezen.genflow.api.normal.openapi;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Map;
import java.util.Optional;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.Maps;

/**
 * Manages model objects that registered as local objects in the final
 * constructed model spec.
 * 

* Localization comprises two distinct treatments: *

    *
  • Registration: Makes a copy of the JSON tree corresponding to an object, * and creates a name for that object in the final tree. If the object's name in * its defining spec is not yet used for another object, that name will be used. * Otherwise it will be the basis for a disambiguated name.
  • *
  • Retaining: Marks a registered object as required in the final constructed * model spec. Only retained objects will be emitted in that spec. Depending on * a normalizer option, all top-level objects may be retained. If not, they and * all objects originating in component specs are retained only if they are the * target of a reference that is localized.
  • *
* Note that paths are always inlined and retained. This logically follows from * the following observations: *
    *
  • A path reference MUST be an external reference (since a local path * reference would necessarily refer to the value of a member of the containing * spec's "paths" object, which would make that path already a path in the * containing spec).
  • *
  • Every property in the top-level spec's "paths" object defines a path in * the top-level spec. If the definition uses a path reference, that reference * must be inlined in order to fulfill this requirement in the constructed * single-file spec.
  • *
* These observations are unique to paths, and do not apply to the other types * of named model objects, since the property values in the corresponding model * sections are not allowed to be references (though they may contained embedded * references). */ public class ContentLocalizer { private final Integer modelVersion; private final Map localContentItems = Maps.newLinkedHashMap(); private final Map itemsByLocalName = Maps.newHashMap(); private Deque retainedObjectQueue = new ArrayDeque(); private int nextPositionValue = 0; public ContentLocalizer(Integer modelVersion) { this.modelVersion = modelVersion; } /** * Register the given object tree under the given reference, and select a name * for a local copy of that object if it ends up in the constructed spec. */ public LocalContent register(Reference ref, JsonNode node) { if (!localContentItems.containsKey(ref)) { register(new LocalContent(ref, node)); } return localContentItems.get(ref); } private void register(LocalContent localContent) { localContentItems.put(localContent.getRef(), localContent); } /** * Get a reference to the local copy of the referenced object in the constructed * spec. *

* Obtaining a localized reference has the side-effect of retaining the object * in the constructed spec. */ public Reference getLocalizedRef(Reference ref) { LocalContent localContent = localContentItems.get(ref); if (localContent != null) { localContent.retain(); return new Reference(localContent.getLocalizedRefString(), modelVersion); } else { return ref.getBadRef(); } } public JsonNode getLocalizedRefNode(Reference ref) { return getLocalizedRef(ref).getRefNode(); } /** * Obtain the localized object by its local section and object names */ public LocalContent getLocalContent(String sectionName, String objectName) { return itemsByLocalName.get(sectionName + ":" + objectName); } public Iterable getLocalContentItems() { return localContentItems.values(); } /** * Pop the next object off the retained object queue */ public Optional getAndRemoveRetainedModelObject() { return retainedObjectQueue.isEmpty() ? Optional.empty() : Optional.of(retainedObjectQueue.remove()); } public class LocalContent { private final Reference ref; private final JsonNode content; private final String name; private boolean isRetained = false; private int position; public LocalContent(Reference ref, JsonNode node) { this.ref = ref; this.content = node; this.name = chooseLocalName(); this.position = ContentLocalizer.this.nextPositionValue++; } public Reference getRef() { return ref; } public JsonNode getContent() { return content; } public String getName() { return name; } public String getLocalizedRefString() { return "#" + getSectionPath() + "/" + name; } public String getSectionPath() { return ref.getSectionPath(); } public ObjectType getSectionType() { return ref.getSection(); } public int getPosition() { return position; } public void retain() { if (!isRetained) { retainedObjectQueue.addLast(this); } isRetained = true; } public boolean isRetained() { return isRetained; } private String chooseLocalName() { String name = ref.getObjectName(); if (name == null) { name = "_ANON"; } String key = getSectionPath() + ":" + name; if (!itemsByLocalName.containsKey(key)) { itemsByLocalName.put(key, this); return name; } for (int i = 1;; i++) { String disambiguatedKey = key + "_" + i; if (!itemsByLocalName.containsKey(disambiguatedKey)) { itemsByLocalName.put(disambiguatedKey, this); return name + "_" + i; } } } @Override public String toString() { return String.format("LocalContent[%s]\n", getLocalizedRefString()); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy