/** * Returns all direct children of the specified parent. * * <b>WARNING</b>: the returned stream MUST BE closed after processing. * * @param parent the parent of which to return the children * @return the stream of all children of the parent */ @SuppressWarnings({"unchecked", "rawtypes"}) default Stream<FullNode> getAllChildNodes(RelativePath parent) { Stream<FullNode> ret = Stream.empty(); RelativePath.Extender check = RelativePath.empty() .extend(Blueprint.getSegmentTypeOf(getRoot()),getRoot().getId()) .extend(parent.getPath()); for (EntityType et : EntityType.values()) { SegmentType st = et.segmentType; if (check.canExtendTo(st)) { List<FullNode> res; Class entityType = Entity.entityTypeFromSegmentType(st); try (Stream<FullNode> next = (Stream<FullNode>) getChildNodes(parent, entityType)) { res = next.collect(Collectors.toList()); } ret = Stream.concat(ret, res.stream()); } } return ret; }
RelativePath.empty().get()));
syncTrees(tx, rootPath, RelativePath.empty().get(), root, newTree, newStructure, currentStructure); DBG.debugf("Done syncing the merged tree and the database state of root %s", rootPath);
/** * Returns all direct children of the specified parent. * * <b>WARNING</b>: the returned stream MUST BE closed after processing. * * @param parent the parent of which to return the children * @return the stream of all children of the parent */ @SuppressWarnings({"unchecked", "rawtypes"}) default Stream<FullNode> getAllChildNodes(RelativePath parent) { Stream<FullNode> ret = Stream.empty(); RelativePath.Extender check = RelativePath.empty() .extend(Blueprint.getSegmentTypeOf(getRoot()),getRoot().getId()) .extend(parent.getPath()); for (EntityType et : EntityType.values()) { SegmentType st = et.segmentType; if (check.canExtendTo(st)) { List<FullNode> res; Class entityType = Entity.entityTypeFromSegmentType(st); try (Stream<FullNode> next = (Stream<FullNode>) getChildNodes(parent, entityType)) { res = next.collect(Collectors.toList()); } ret = Stream.concat(ret, res.stream()); } } return ret; }
@SuppressWarnings("unchecked") private InventoryStructure.Builder<B> mergeDeepTree(InventoryStructure<?> currentTree, RelativePath treePath, InventoryStructure.AbstractBuilder<?> newTree, Set<SegmentType> mergedTypes) { DBG.debugf("Starting to merge shallow tree. Loading children under [%s]", treePath); try (Stream<InventoryStructure.FullNode> currentChildren = currentTree.getAllChildNodes(treePath)) { DBG.debugf("Done loading the children under [%s]", treePath); Set<Path.Segment> newChildPaths = newTree.getChildrenPaths(); currentChildren.forEach(currentChild -> { SegmentType childType = Inventory.types().byBlueprint(currentChild.getEntity().getClass()).getSegmentType(); Path.Segment childPathSegment = new Path.Segment(childType, currentChild.getEntity().getId()); if (newChildPaths.contains(childPathSegment)) { mergeDeepTree(currentTree, treePath.modified().extend(childPathSegment).get(), newTree.getChild(childPathSegment), mergedTypes); } else if (!mergedTypes.contains(childType)) { newTree.addChild(currentChild.getEntity(), currentChild.getAttachment()); mergeDeepTree(currentTree, treePath.modified().extend(childPathSegment).get(), newTree.getChild(childPathSegment), mergedTypes); } }); DBG.debugf("Done merging shallow tree of [%s]", treePath); if (newTree instanceof InventoryStructure.Builder) { return (InventoryStructure.Builder<B>) newTree; } else { return null; } } }
private void deserializeChildren(JsonParser p, AbstractHashTree.Builder<?, ?, T, H> bld, RelativePath.Extender parentPath, DeserializationContext ctx) throws IOException { //make a copy so that we don't modify the parent RelativePath.Extender origParentPath = parentPath; parentPath = origParentPath.get().modified(); RelativePath childPath = null; while (p.nextToken() != null) { switch (p.getCurrentToken()) { case FIELD_NAME: childPath = parentPath.extend(Path.Segment.from(p.getCurrentName())).get(); break; case START_OBJECT: AbstractHashTree.ChildBuilder<?, ?, ?, T, H> childBld = bld.startChild(); deserializeChild(p, childBld, childPath.modified(), ctx); childBld.endChild(); parentPath = origParentPath.get().modified(); break; case END_OBJECT: return; } } }
private void serializeLevel(InventoryStructure<?> structure, RelativePath.Extender root, JsonGenerator gen) throws IOException { RelativePath rootPath = root.get(); for (InventoryStructure.EntityType entityType : InventoryStructure.EntityType.values()) { @SuppressWarnings("unchecked") List<? extends Entity.Blueprint> children = getChildren(structure, rootPath, (Class) entityType.elementType); if (!children.isEmpty()) { gen.writeFieldName(entityType.name()); gen.writeStartArray(); for (Entity.Blueprint bl : children) { gen.writeStartObject(); gen.writeObjectField("data", bl); gen.writeFieldName("children"); gen.writeStartObject(); serializeLevel(structure, rootPath.modified().extend(entityType.segmentType, bl.getId()), gen); gen.writeEndObject(); gen.writeEndObject(); } gen.writeEndArray(); } } }
private void deserializeChild(JsonParser p, AbstractHashTree.Builder<?, ?, T, H> bld, RelativePath.Extender childPath, DeserializationContext ctx) throws IOException { bld.withPath(childPath.get()); String currentField = null; while (p.nextToken() != null) { switch (p.getCurrentToken()) { case END_OBJECT: return; case FIELD_NAME: currentField = p.getCurrentName(); break; default: switch (currentField) { case "hash": H hash = ctx.readValue(p, hashType); bld.withHash(hash); break; case "children": deserializeChildren(p, bld, childPath, ctx); break; } } } } }
/** * Starts building a new child of the currently built entity. * * @param child the child entity blueprint * @param childAttachment the attachment to store along with the child * @return a new child builder * @throws IllegalArgumentException if the provided child cannot be contained in the currently built entity * (i.e. a resource type cannot be contained in a resource for example). */ public ChildBuilder<This> startChild(Entity.Blueprint child, Object childAttachment) { RelativePath.Extender extender = myPath.modified(); Class<? extends AbstractElement<?, ?>> childType = Blueprint.getEntityTypeOf(child); SegmentType childSeg = Blueprint.getSegmentTypeOf(child); if (!extender.canExtendTo(childSeg)) { throw new IllegalArgumentException("Cannot extend path " + myPath + " with child of type " + childType); } RelativePath childPath = extender.extend(childSeg, child.getId()).get(); Set<FullNode> bls = getChildrenOfType(EntityType.of(childType)); FullNode node = new FullNode(child, childAttachment); bls.add(node); blueprints.put(childPath, node); return new ChildBuilder<>(castThis(), childPath, blueprints, children); }
@SuppressWarnings("unchecked") private InventoryStructure.Builder<B> mergeShallowTree(InventoryStructure<?> currentTree, RelativePath treePath, InventoryStructure.AbstractBuilder<?> newTree, Set<SegmentType> mergedTypes) { DBG.debugf("Starting to merge shallow tree. Loading children under [%s]", treePath); try (Stream<InventoryStructure.FullNode> currentChildren = currentTree.getAllChildNodes(treePath)) { DBG.debugf("Done loading the children under [%s]", treePath); Set<Path.Segment> newChildPaths = newTree.getChildrenPaths(); currentChildren.forEach(currentChild -> { SegmentType childType = Inventory.types().byBlueprint(currentChild.getEntity().getClass()).getSegmentType(); Path.Segment childPathSegment = new Path.Segment(childType, currentChild.getEntity().getId()); if (newChildPaths.contains(childPathSegment)) { mergeShallowTree(currentTree, treePath.modified().extend(childPathSegment).get(), newTree.getChild(childPathSegment), mergedTypes); } else if (!mergedTypes.contains(childType)) { newTree.addChild(currentChild.getEntity(), currentChild.getAttachment()); } }); DBG.debugf("Done merging shallow tree of [%s]", treePath); if (newTree instanceof InventoryStructure.Builder) { return (InventoryStructure.Builder<B>) newTree; } else { return null; } } }
private Map.Entry<InventoryStructure<B>, SyncHash.Tree> treeHashAndStructure(Transaction<BE> tx) { BE root = tx.querySingle(context.select().get()); E entity = tx.convert(root, context.entityClass); SyncHash.Tree.Builder bld = SyncHash.Tree.builder(); InventoryStructure.Builder<B> structBld = InventoryStructure.of(Inventory.asBlueprint(entity)); bld.withPath(RelativePath.empty().get()).withHash(entity.getSyncHash()); //the closure is returned in a breadth-first manner Iterator<BE> closure = tx.getTransitiveClosureOver(root, outgoing, contains.name()); if (closure.hasNext()) { Function<BE, Entity<? extends Entity.Blueprint, ?>> convert = e -> (Entity<Entity.Blueprint, ?>) tx.convert(e, tx.extractType(e)); Stream<BE> st = StreamSupport.stream(Spliterators.spliteratorUnknownSize(closure, 0), false); Iterator<Entity<? extends Entity.Blueprint, ?>> entities = st.map(convert).iterator(); buildChildTree(tx, entity.getPath(), singletonList(bld), singletonList(structBld), new ArrayList<>(), new ArrayList<>(), entities.next(), entities); } return new SimpleImmutableEntry<>(structBld.build(), bld.build()); }
/** * Returns a child builder of a pre-existing child. * @param childPath the path to the child * @return the child builder or null */ public ChildBuilder<This> getChild(Path.Segment childPath) { Map<EntityType, Set<FullNode>> myChildren = children.get(myPath); if (myChildren == null) { return null; } EntityType childType = EntityType.of(childPath.getElementType()); Set<FullNode> childrenOfType = myChildren.get(childType); return childrenOfType.stream().filter(child -> child.getEntity().getId().equals(childPath.getElementId())) .findAny().map(child -> { RelativePath rp = myPath.modified().extend(childPath).get(); return new ChildBuilder<>(castThis(), rp, blueprints, children); }).orElse(null); }
/** * Starts building a new child of the currently built entity. * * @param child the child entity blueprint * @param childAttachment the attachment to store along with the child * @return a new child builder * @throws IllegalArgumentException if the provided child cannot be contained in the currently built entity * (i.e. a resource type cannot be contained in a resource for example). */ public ChildBuilder<This> startChild(Entity.Blueprint child, Object childAttachment) { RelativePath.Extender extender = myPath.modified(); Class<? extends AbstractElement> childType = Blueprint.getEntityTypeOf(child); SegmentType childSeg = Blueprint.getSegmentTypeOf(child); if (!extender.canExtendTo(childSeg)) { throw new IllegalArgumentException("Cannot extend path " + myPath + " with child of type " + childType); } RelativePath childPath = extender.extend(childSeg, child.getId()).get(); Set<FullNode> bls = getChildrenOfType(EntityType.of(childType)); FullNode node = new FullNode(child, childAttachment); bls.add(node); blueprints.put(childPath, node); return new ChildBuilder<>(castThis(), childPath, blueprints, children); }
/** * Returns a child builder of a pre-existing child. * @param childPath the path to the child * @return the child builder or null */ public ChildBuilder<This> getChild(Path.Segment childPath) { Map<EntityType, Set<FullNode>> myChildren = children.get(myPath); if (myChildren == null) { return null; } EntityType childType = EntityType.of(childPath.getElementType()); Set<FullNode> childrenOfType = myChildren.get(childType); return childrenOfType.stream().filter(child -> child.getEntity().getId().equals(childPath.getElementId())) .findAny().map(child -> { RelativePath rp = myPath.modified().extend(childPath).get(); return new ChildBuilder<>(castThis(), rp, blueprints, children); }).orElse(null); }
@Override public Path deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException { String val = jp.getValueAsString(); if (val.isEmpty()) { return RelativePath.empty().get(); } return Path.fromString(jp.getValueAsString()); } }
private InventoryStructure<B> mergeTree(InventoryStructure<B> currentTree, InventoryStructure<B> newTree, SyncConfiguration configuration) { if (configuration.isDeepSearch()) { return mergeDeepTree(currentTree, RelativePath.empty().get(), InventoryStructure.Offline.copy(newTree).asBuilder(), configuration.getSyncedTypes()).build(); } else { return mergeShallowTree(currentTree, RelativePath.empty().get(), InventoryStructure.Offline.copy(newTree).asBuilder(), configuration.getSyncedTypes()).build(); } }
@Override default boolean exists() { try { flatData(RelativePath.empty().get()); return true; } catch (EntityNotFoundException | RelationNotFoundException ignored) { return false; } }
@Override public List<Metric.Blueprint> getResourceMetrics(RelativePath rootPath, Resource.Blueprint parentResource) { RelativePath p = rootPath.modified().extend(SegmentType.r, parentResource.getId()).get() .slide(1, 0); try (Stream<Metric.Blueprint> s = structure.getChildren(p, Metric.class)) { return s.collect(toList()); } }