/*
* 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.defines;
import static org.hawkular.inventory.api.Relationships.WellKnown.incorporates;
import static org.hawkular.inventory.api.filters.With.id;
import org.hawkular.inventory.api.EntityAlreadyExistsException;
import org.hawkular.inventory.api.EntityNotFoundException;
import org.hawkular.inventory.api.MetricTypes;
import org.hawkular.inventory.api.Metrics;
import org.hawkular.inventory.api.Query;
import org.hawkular.inventory.api.filters.Filter;
import org.hawkular.inventory.api.filters.Related;
import org.hawkular.inventory.api.filters.With;
import org.hawkular.inventory.api.model.MetadataPack;
import org.hawkular.inventory.api.model.Metric;
import org.hawkular.inventory.api.model.MetricType;
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 BaseMetricTypes {
private BaseMetricTypes() {
}
public static class ReadWrite<BE>
extends Mutator<BE, MetricType, MetricType.Blueprint, MetricType.Update, String>
implements MetricTypes.ReadWrite {
public ReadWrite(TraversalContext<BE, MetricType> context) {
super(context);
}
@Override
protected String getProposedId(Transaction<BE> tx, MetricType.Blueprint blueprint) {
return blueprint.getId();
}
@Override
protected EntityAndPendingNotifications<BE, MetricType>
wireUpNewEntity(Discriminator discriminator, BE entity, MetricType.Blueprint blueprint,
CanonicalPath parentPath, BE parent,
Transaction<BE> tx) {
MetricType metricType = new MetricType(blueprint.getName(),
parentPath.extend(MetricType.SEGMENT_TYPE, tx.extractId(entity)).get(), null, null, null,
blueprint.getUnit(), blueprint.getMetricDataType(), blueprint.getProperties(),
blueprint.getCollectionInterval());
return new EntityAndPendingNotifications<>(entity, metricType, emptyList());
}
@Override
public MetricTypes.Multiple getAll(Filter[][] filters) {
return new BaseMetricTypes.Multiple<>(context.proceed().whereAll(filters).get());
}
@Override
public MetricTypes.Single get(String id) throws EntityNotFoundException {
return new BaseMetricTypes.Single<>(context.proceed().where(id(id)).get());
}
@Override
public MetricTypes.Single create(MetricType.Blueprint blueprint, boolean cache)
throws EntityAlreadyExistsException {
if (blueprint.getMetricDataType() == null ||
blueprint.getUnit() == null ||
blueprint.getCollectionInterval() == null) {
String msg = getErrorMessage(blueprint);
throw new IllegalArgumentException(msg);
}
return new BaseMetricTypes.Single<>(context.toCreatedEntity(doCreate(blueprint), cache));
}
@Override
protected void preDelete(String s, BE entityRepresentation, Transaction<BE> transaction) {
preDelete(entityRepresentation, context.discriminator(), transaction);
}
@Override
protected void preUpdate(String s, BE entityRepresentation, MetricType.Update update,
Transaction<BE> transaction) {
preUpdate(context, entityRepresentation, update, transaction);
}
@Override protected void postUpdate(BE entityRepresentation, Transaction<BE> transaction) {
postUpdate(context, entityRepresentation, transaction);
}
private static <BE> void preDelete(BE deletedEntity, Discriminator discriminator, Transaction<BE> tx) {
if (isInMetadataPack(deletedEntity, discriminator, tx)) {
throw new IllegalArgumentException("Cannot delete a metric type that is a part of metadata pack.");
}
}
private static <BE> void preUpdate(TraversalContext<BE, ?> context, BE entity, MetricType.Update update,
Transaction<BE> tx) {
MetricType mt = tx.convert(context.discriminator(), entity, MetricType.class);
if (mt.getUnit() == update.getUnit()) {
//k, this is the only updatable thing that influences metadata packs, so if it is equal, we're ok.
return;
}
if (isInMetadataPack(entity, context.discriminator(), tx)) {
throw new IllegalArgumentException("Cannot update a metric type that is a part of metadata pack.");
}
}
private static <BE> void postUpdate(TraversalContext<BE, ?> context, BE entity,
Transaction<BE> tx) {
}
private static <BE> boolean isInMetadataPack(BE metricType, Discriminator discriminator, Transaction<BE> tx) {
return tx.traverseToSingle(discriminator, metricType, Query.path().with(Related.asTargetBy(incorporates),
With.type(MetadataPack.class)).get()) != null;
}
private String getErrorMessage(MetricType.Blueprint blueprint) {
String msg;
if (blueprint.getCollectionInterval() == null) {
msg = "Interval (\"collectionInterval\" in JSON)";
} else if (blueprint.getMetricDataType() == null) {
msg = "Data type (\"type\" in JSON)";
} else {
msg = "Metric unit (\"unit\" in JSON)";
}
return msg + " is null";
}
}
public static class ReadContained<BE> extends Fetcher<BE, MetricType, MetricType.Update>
implements MetricTypes.ReadContained {
public ReadContained(TraversalContext<BE, MetricType> context) {
super(context);
}
@Override
public MetricTypes.Multiple getAll(Filter[][] filters) {
return new BaseMetricTypes.Multiple<>(context.proceed().whereAll(filters).get());
}
@Override
public MetricTypes.Single get(String id) throws EntityNotFoundException {
return new BaseMetricTypes.Single<>(context.proceed().where(id(id)).get());
}
}
public static class Read<BE> extends Fetcher<BE, MetricType, MetricType.Update> implements MetricTypes.Read {
public Read(TraversalContext<BE, MetricType> context) {
super(context);
}
@Override
public MetricTypes.Multiple getAll(Filter[][] filters) {
return new BaseMetricTypes.Multiple<>(context.proceed().whereAll(filters).get());
}
@Override
public MetricTypes.Single get(Path id) throws EntityNotFoundException {
return new BaseMetricTypes.Single<>(context.proceedTo(id));
}
}
public static class ReadAssociate<BE> extends Associator<BE, MetricType>
implements MetricTypes.ReadAssociate {
public ReadAssociate(TraversalContext<BE, MetricType> context) {
super(context, incorporates, SegmentType.rt);
}
@Override
public MetricTypes.Multiple getAll(Filter[][] filters) {
return new BaseMetricTypes.Multiple<>(context.proceed().whereAll(filters).get());
}
@Override
public MetricTypes.Single get(Path id) throws EntityNotFoundException {
return new BaseMetricTypes.Single<>(context.proceedTo(id));
}
}
public static class Single<BE> extends SingleSyncedFetcher<BE, MetricType, MetricType.Blueprint,
MetricType.Update> implements MetricTypes.Single {
public Single(TraversalContext<BE, MetricType> context) {
super(context);
}
@Override
public Metrics.Read metrics() {
return new BaseMetrics.Read<>(context.proceedTo(defines, Metric.class).get());
}
@Override
public MetricTypes.Read identical() {
return new Read<>(context.proceed().hop(With.sameIdentityHash()).get());
}
@Override
protected void preDelete(BE deletedEntity, Transaction<BE> transaction) {
ReadWrite.preDelete(deletedEntity, context.discriminator(), transaction);
}
@Override
protected void preUpdate(BE updatedEntity, MetricType.Update update, Transaction<BE> transaction) {
ReadWrite.preUpdate(context, updatedEntity, update, transaction);
}
@Override protected void postUpdate(BE updatedEntity, Transaction<BE> transaction) {
ReadWrite.postUpdate(context, updatedEntity, transaction);
}
}
public static class Multiple<BE> extends MultipleEntityFetcher<BE, MetricType, MetricType.Update>
implements MetricTypes.Multiple {
public Multiple(TraversalContext<BE, MetricType> context) {
super(context);
}
@Override
public Metrics.Read metrics() {
return new BaseMetrics.Read<>(context.proceedTo(defines, Metric.class).get());
}
@Override public MetricTypes.Read identical() {
return new Read<>(context.proceed().hop(With.sameIdentityHash()).get());
}
}
}