/*
* 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 org.hawkular.inventory.api.Relationships.Direction.outgoing;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import org.hawkular.inventory.api.Action;
import org.hawkular.inventory.api.EntityNotFoundException;
import org.hawkular.inventory.api.Query;
import org.hawkular.inventory.api.Relationships;
import org.hawkular.inventory.api.model.Change;
import org.hawkular.inventory.api.model.Entity;
import org.hawkular.inventory.base.spi.EntityHistory;
import org.hawkular.inventory.base.spi.EntityStateChange;
/**
* Base for {@code *Single} implementations on entities.
*
* @author Lukas Krejci
* @since 0.1.0
*/
class SingleEntityFetcher<BE, E extends Entity<?, U>, U extends Entity.Update>
extends Fetcher<BE, E, U> {
public SingleEntityFetcher(TraversalContext<BE, E> context) {
super(context);
}
public List<Change<E>> history(Instant from, Instant to) {
EntityHistory<E> history = inTx(tx -> {
//the null discriminator is here intentionally - we need to find the entity whenever it existed in time..
BE myEntity = tx.querySingle(null, context.select().get());
if (myEntity == null) {
throw new EntityNotFoundException(Query.filters(context.select().get()));
}
Instant f = from == null ? Instant.ofEpochMilli(0) : from;
Instant t = to == null ? Instant.ofEpochMilli(Long.MAX_VALUE) : to;
return tx.getHistory(myEntity, context.entityClass, f, t);
});
List<Change<E>> ret = new ArrayList<>(history.getChanges().size());
int processed = 0;
Action.Enumerated created = Action.Enumerated.CREATED;
Action.Enumerated updated = Action.Enumerated.UPDATED;
for (EntityStateChange<E> ch : history.getChanges()) {
Action.Enumerated chAction = ch.getAction().asEnum();
if (chAction == updated) {
E previous;
//we need to compute the update object from the previous and current state
if (processed == 0) {
previous = history.getInitialState();
} else {
previous = history.getChanges().get(processed - 1).getEntity();
}
E current = ch.getEntity();
//casting fun to overcome the imperfect typing of the update() method
@SuppressWarnings({"unchecked", "rawtypes"})
U update = (U) ((Entity.Updater) previous.update()).to(current);
ret.add(new Change<E>(ch.getOccurrenceTime(), Action.updated(),
new Action.Update<>(previous, update)));
} else if (chAction == created) {
ret.add(new Change<>(ch.getOccurrenceTime(), Action.created(), ch.getEntity()));
} else {
ret.add(new Change<>(ch.getOccurrenceTime(), Action.deleted(), ch.getEntity()));
}
processed++;
}
return ret;
}
public Relationships.ReadWrite relationships() {
return relationships(outgoing);
}
public Relationships.ReadWrite relationships(Relationships.Direction direction) {
return new BaseRelationships.ReadWrite<>(context.proceedToRelationships(direction).get(), context.entityClass);
}
}