/* * 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.base; import static java.util.Collections.emptyList; import static org.hawkular.inventory.api.Relationships.WellKnown.contains; import static org.hawkular.inventory.api.Relationships.WellKnown.incorporates; import static org.hawkular.inventory.api.filters.Related.by; import static org.hawkular.inventory.api.filters.With.id; import static org.hawkular.inventory.api.filters.With.type; import org.hawkular.inventory.api.EntityNotFoundException; import org.hawkular.inventory.api.Feeds; import org.hawkular.inventory.api.MetricTypes; import org.hawkular.inventory.api.Metrics; import org.hawkular.inventory.api.Query; import org.hawkular.inventory.api.ResourceTypes; import org.hawkular.inventory.api.Resources; import org.hawkular.inventory.api.filters.Filter; import org.hawkular.inventory.api.filters.RecurseFilter; import org.hawkular.inventory.api.model.Feed; import org.hawkular.inventory.api.model.Metric; import org.hawkular.inventory.api.model.MetricType; import org.hawkular.inventory.api.model.Resource; import org.hawkular.inventory.api.model.ResourceType; import org.hawkular.inventory.api.model.Tenant; import org.hawkular.inventory.base.spi.Discriminator; import org.hawkular.inventory.paths.CanonicalPath; import org.hawkular.inventory.paths.Path; import org.hawkular.inventory.paths.SegmentType; /** * @author Lukas Krejci * @since 0.1.0 */ public final class BaseFeeds { private BaseFeeds() { } public static class ReadWrite<BE> extends Mutator<BE, Feed, Feed.Blueprint, Feed.Update, String> implements Feeds.ReadWrite { public ReadWrite(TraversalContext<BE, Feed> context) { super(context); } @Override protected String getProposedId(Transaction<BE> tx, Feed.Blueprint blueprint) { BE tenant = tx.querySingle(context.discriminator(), context.sourcePath.extend().filter() .with(type(Tenant.class)).get()); if (tenant == null) { throw new EntityNotFoundException(Tenant.class, Query.filters(context.sourcePath)); } CanonicalPath feedPath = tx.extractCanonicalPath(tenant) .extend(Feed.SEGMENT_TYPE, blueprint.getId()).get(); return context.configuration.getFeedIdStrategy().generate(context.inventory.keepTransaction(tx), new Feed(feedPath, null, null, null)); } @Override protected EntityAndPendingNotifications<BE, Feed> wireUpNewEntity(Discriminator discriminator, BE entity, Feed.Blueprint blueprint, CanonicalPath parentPath, BE parent, Transaction<BE> transaction) { return new EntityAndPendingNotifications<>(entity, new Feed(blueprint.getName(), parentPath.extend(Feed.SEGMENT_TYPE, transaction.extractId(entity)).get(), null, null, null, blueprint.getProperties()), emptyList()); } @Override public Feeds.Single create(Feed.Blueprint blueprint, boolean cache) { return new Single<>(context.toCreatedEntity(doCreate(blueprint), cache)); } @Override public Feeds.Multiple getAll(Filter[][] filters) { return new Multiple<>(context.proceed().whereAll(filters).get()); } @Override public Feeds.Single get(String id) throws EntityNotFoundException { return new Single<>(context.proceed().where(id(id)).get()); } } public static class ReadContained<BE> extends Fetcher<BE, Feed, Feed.Update> implements Feeds.ReadContained { public ReadContained(TraversalContext<BE, Feed> context) { super(context); } @Override public Feeds.Multiple getAll(Filter[][] filters) { return new Multiple<>(context.proceed().whereAll(filters).get()); } @Override public Feeds.Single get(String id) throws EntityNotFoundException { return new Single<>(context.proceed().where(id(id)).get()); } } public static class Read<BE> extends Fetcher<BE, Feed, Feed.Update> implements Feeds.Read { public Read(TraversalContext<BE, Feed> context) { super(context); } @Override public Feeds.Multiple getAll(Filter[][] filters) { return new Multiple<>(context.proceed().whereAll(filters).get()); } @Override public Feeds.Single get(Path id) throws EntityNotFoundException { return new Single<>(context.proceedTo(id)); } } public static class ReadAssociate<BE> extends Associator<BE, Feed> implements Feeds.ReadAssociate { public ReadAssociate(TraversalContext<BE, Feed> context) { super(context, incorporates, SegmentType.e); } @Override public Feeds.Multiple getAll(Filter[][] filters) { return new BaseFeeds.Multiple<>(context.proceed().whereAll(filters).get()); } @Override public Feeds.Single get(Path path) throws EntityNotFoundException { return new BaseFeeds.Single<>(context.proceedTo(path)); } } public static class Single<BE> extends SingleSyncedFetcher<BE, Feed, Feed.Blueprint, Feed.Update> implements Feeds.Single { public Single(TraversalContext<BE, Feed> context) { super(context); } @Override public Resources.ReadWrite resources() { return new BaseResources.ReadWrite<>(context.proceedTo(contains, Resource.class).get()); } @Override public Resources.Read resourcesUnder(Feeds.ResourceParents... parents) { return proceedToResources(context, parents); } @Override public Metrics.ReadWrite metrics() { return new BaseMetrics.ReadWrite<>(context.proceedTo(contains, Metric.class).get()); } @Override public Metrics.Read metricsUnder(Feeds.MetricParents... parents) { return proceedToMetrics(context, parents); } @Override public MetricTypes.ReadWrite metricTypes() { return new BaseMetricTypes.ReadWrite<>(context.proceedTo(contains, MetricType.class).get()); } @Override public ResourceTypes.ReadWrite resourceTypes() { return new BaseResourceTypes.ReadWrite<>(context.proceedTo(contains, ResourceType.class).get()); } } public static class Multiple<BE> extends MultipleEntityFetcher<BE, Feed, Feed.Update> implements Feeds.Multiple { public Multiple(TraversalContext<BE, Feed> context) { super(context); } @Override public Resources.ReadContained resources() { return new BaseResources.ReadContained<>(context.proceedTo(contains, Resource.class).get()); } @Override public Resources.Read resourcesUnder(Feeds.ResourceParents... parents) { return proceedToResources(context, parents); } @Override public Metrics.ReadContained metrics() { return new BaseMetrics.ReadContained<>(context.proceedTo(contains, Metric.class).get()); } @Override public Metrics.Read metricsUnder(Feeds.MetricParents... parents) { return proceedToMetrics(context, parents); } @Override public MetricTypes.ReadContained metricTypes() { return new BaseMetricTypes.ReadContained<>(context.proceedTo(contains, MetricType.class).get()); } @Override public ResourceTypes.ReadContained resourceTypes() { return new BaseResourceTypes.ReadContained<>(context.proceedTo(contains, ResourceType.class).get()); } } private static <BE> BaseResources.Read<BE> proceedToResources(TraversalContext<BE, Feed> context, Feeds.ResourceParents... parents) { return new BaseResources.Read<>(context.proceedWithParents(Resource.class, Feeds.ResourceParents.class, Feeds.ResourceParents.FEED, parents, (p, extender) -> { switch (p) { case FEED: extender.path().with(by(contains), type(Resource.class)); break; case RESOURCE: extender.path().with(by(contains), type(Resource.class), RecurseFilter.builder() .addChain(by(contains), type(Resource.class)).build()); break; default: throw new AssertionError("Unhandled type of resource parent under feed."); } })); } private static <BE> BaseMetrics.Read<BE> proceedToMetrics(TraversalContext<BE, Feed> context, Feeds.MetricParents... parents) { return new BaseMetrics.Read<>(context.proceedWithParents(Metric.class, Feeds.MetricParents.class, Feeds.MetricParents.FEED, parents, (p, extender) -> { switch (p) { case FEED: extender.path().with(by(contains), type(Metric.class)); break; case RESOURCE: //go to the root resources and their children extender.path().with(new Filter[][]{ {by(contains), type(Resource.class)}, {by(contains), type(Resource.class), RecurseFilter.builder().addChain( by(contains), type(Resource.class)).build()}}); //and from the resources, go to the metrics extender.path().with(by(contains), type(Metric.class)); break; default: throw new AssertionError("Unhandled type of resource parent under feed."); } })); } }