/*
* Copyright 2015-2016 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* 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://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 org.hawkular.inventory.api;
import org.hawkular.inventory.api.model.Relationship;
import org.hawkular.inventory.api.model.Resource;
import org.hawkular.inventory.paths.DataRole;
import org.hawkular.inventory.paths.Path;
import org.hawkular.inventory.paths.RelativePath;
import org.hawkular.inventory.paths.SegmentType;
/**
* This is a wrapper class to hold various interfaces defining available functionality on resources.
*
* @author Lukas Krejci
* @since 1.0
*/
public final class Resources {
private Resources() {
}
public enum ResourceParents implements Parents {
CONTAINING_RESOURCE, PARENT_RESOURCE
}
public enum MetricParents implements Parents {
CONTAINING_RESOURCE, INCORPORATING_RESOURCE
}
private interface BrowserBase<ContainedMetrics, AllMetrics, DataAccess, ContainedAccess, AllAccess>
extends Metrics.Container<ContainedMetrics>, Data.Container<DataAccess>,
Resources.Container<ContainedAccess> {
ContainedMetrics metrics();
/**
* @return access to metrics incorporated by the resource(s)
*/
AllMetrics allMetrics();
/**
* @return access to children that are existentially bound to this/these resource(s)
*/
ContainedAccess resources();
/**
* Access to all children.
* <p>
* Note that children that are existentially bound to this resource (i.e. in addition to
* {@link org.hawkular.inventory.api.Relationships.WellKnown#isParentOf} there also exists the
* {@link org.hawkular.inventory.api.Relationships.WellKnown#contains} relationship) cannot be disassociated
* using this interface.
*
* @return access to all children of this/these resource(s) (superset of {@link #resources()}, also
* includes the resources bound merely by
* {@link org.hawkular.inventory.api.Relationships.WellKnown#isParentOf}).
*/
AllAccess allResources();
Read recursiveResources();
/**
* @return the parent resource(s) of the current resource(s)
*/
Read parents();
/**
* @return data associated with the resource. See {@link org.hawkular.inventory.paths.DataRole} for
* possible kinds of data associated with a resource.
*/
DataAccess data();
}
/**
* An interface implemented by Single/Multiple interfaces of entities that can contain resources.
* @param <Access> the type of access to resources
*/
public interface Container<Access> {
Access resources();
}
/**
* Interface for accessing a single resource in a writable manner.
*/
public interface Single
extends Synced.SingleEntity<Resource, Resource.Blueprint, Resource.Update>,
BrowserBase<Metrics.ReadWrite, Metrics.ReadAssociate, Data.ReadWrite<DataRole.Resource>, ReadWrite,
ReadAssociate> {
/**
* @return access to the parent resource (if any) that contains the resource on the current position in the
* path traversal. This resource will not exist for top-level resources living directly under an environment or
* feed.
*/
Single parent();
}
/**
* Interface for traversing over a set of resources.
* <p>
* <p>Note that traversing over a set of entities enables only read-only access. If you need to use any of the
* modification methods, you first need to resolve the traversal to a single entity (using the
* {@link ReadInterface#get(Object)} method).
*/
public interface Multiple
extends ResolvableToManyWithRelationships<Resource>, BrowserBase<Metrics.Read, Metrics.Read,
Data.Read<DataRole.Resource>, ReadContained, Read> {
}
public interface ReadBase<Address> extends ReadInterface<Single, Multiple, Address> {
/**
* A shortcut for {@code get(firstChild).allChildren().get(furtherChildren[0]).allChildren()
* .get(furtherChildren[1])...}.
* <p>
* <p>Each of the paths in further children is either a canonical path or a relative path that is relative
* to the preceding child.
* <p>
* <p>Remember that relative paths are resolved using the
* <b>{@link org.hawkular.inventory.api.Relationships.WellKnown#contains}</b> relationship while descend follows
* the {@link org.hawkular.inventory.api.Relationships.WellKnown#isParentOf} relationships.
*
* @param firstChild the id of the first contained child
* @param furtherChildren the list of paths to the grand children and on
* @return access to last child mentioned
*/
default Single descend(Address firstChild, Path... furtherChildren) {
if (firstChild == null) {
throw new IllegalArgumentException("no first child");
}
Single access = get(firstChild);
Read last = access.allResources();
for (Path p : furtherChildren) {
if (!SegmentType.r.equals(p.getSegment().getElementType())) {
throw new IllegalArgumentException("Descend can only traverse child resources.");
}
access = last.get(p);
last = access.allResources();
}
return access;
}
}
/**
* Provides read-only access to resources following the containment chain.
*/
public interface ReadContained extends ReadBase<String> {
default Single descendContained(RelativePath resourcePath) {
ReadContained parent = this;
Single access = null;
for(Path.Segment s : resourcePath.getPath()) {
access = parent.get(s.getElementId());
parent = access.resources();
}
if (access == null) {
throw new IllegalArgumentException("Empty resource path");
}
return access;
}
}
/**
* Provides read-only access to resources from positions that follow associations without the possibility to
* introduce ambiguity when addressing using a relative path.
*/
public interface Read extends ReadBase<Path> {
}
/**
* Provides read-write access to resources.
*/
public interface ReadWrite
extends ReadWriteInterface<Resource.Update, Resource.Blueprint, Single, Multiple, String>,
ReadContained {
}
/**
* This interface enables the creation of "alternative" tree hierarchies of resources using the
* {@link org.hawkular.inventory.api.Relationships.WellKnown#isParentOf} relationship. Resources can be contained
* within each other, which causes such child resources to be deleted along with their parent resources (such
* resources also implicitly have the {@code isParentOf} relationship between each other). If there is only the
* {@code isParentOf} relationship between the two resources they form a tree structure but deleting the parent
* does not affect the child - the link between them just disappears.
*/
public interface ReadAssociate extends Read, AssociationInterface {
/**
* Removes the {@link org.hawkular.inventory.api.Relationships.WellKnown#isParentOf} relationship between the
* two resources.
*
* @param id the id of the entity to remove from the relation with the current entity.
* @return the relationship that was deleted as a result of the disassociation
* @throws EntityNotFoundException if a resource with given id doesn't exist
* @throws IllegalArgumentException if the resource with the supplied path is existentially bound to its parent
* resource
*/
@Override Relationship disassociate(Path id) throws EntityNotFoundException, IllegalArgumentException;
}
}