/*
* 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.model;
import java.io.Serializable;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import org.hawkular.inventory.api.model.ComputeHash.IntermediateHashContext;
import org.hawkular.inventory.api.model.ComputeHash.IntermediateHashResult;
import org.hawkular.inventory.paths.CanonicalPath;
import org.hawkular.inventory.paths.Path;
import org.hawkular.inventory.paths.RelativePath;
/**
* A container for all type of hashes computed on an entity. Depending on what kind of hashes have been computed, some
* properties of this class might be null. The caller is responsible to keep track of what's been computed and hence
* what hashes are held in instances of this class.
*
* @author Lukas Krejci
* @since 0.18.0
*/
public final class Hashes implements Serializable {
private final String identityHash;
private final String contentHash;
private final String syncHash;
public static Hashes of(InventoryStructure<?> root, CanonicalPath rootPath) {
return ComputeHash.of(root, rootPath, true, true, true);
}
public static Tree treeOf(InventoryStructure<?> root, CanonicalPath rootPath) {
Tree.AbstractBuilder<?>[] tbld =
new Tree.AbstractBuilder[1];
Consumer<IntermediateHashContext> startChild = context -> {
if (tbld[0] == null) {
tbld[0] = Tree.builder();
} else {
tbld[0] = tbld[0].startChild();
}
};
BiConsumer<IntermediateHashContext, IntermediateHashResult> endChild = (ctx, result) -> {
if (tbld[0] instanceof Tree.ChildBuilder) {
tbld[0].withHash(new Hashes(result)).withPath(result.path);
@SuppressWarnings("unchecked")
Tree.AbstractBuilder<?> parent =
((Tree.ChildBuilder<?>) tbld[0]).getParent();
parent.addChild(((Tree.ChildBuilder<?>) tbld[0]).build());
tbld[0] = parent;
}
};
IntermediateHashResult res = ComputeHash.treeOf(root, rootPath, true, true, true, startChild, endChild);
tbld[0].withPath(res.path).withHash(new Hashes(res));
return ((Tree.Builder)tbld[0]).build();
}
public Hashes(String identityHash, String contentHash, String syncHash) {
this.identityHash = identityHash;
this.contentHash = contentHash;
this.syncHash = syncHash;
}
Hashes(IntermediateHashResult res) {
this(res.identityHash, res.contentHash, res.syncHash);
}
public String getIdentityHash() {
return identityHash;
}
public String getContentHash() {
return contentHash;
}
public String getSyncHash() {
return syncHash;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Hashes hashes = (Hashes) o;
if (identityHash != null ? !identityHash.equals(hashes.identityHash) : hashes.identityHash != null) {
return false;
} else if (contentHash != null ? !contentHash.equals(hashes.contentHash) : hashes.contentHash != null) {
return false;
} else {
return syncHash != null ? syncHash.equals(hashes.syncHash) : hashes.syncHash == null;
}
}
@Override public int hashCode() {
int result = identityHash != null ? identityHash.hashCode() : 0;
result = 31 * result + (contentHash != null ? contentHash.hashCode() : 0);
result = 31 * result + (syncHash != null ? syncHash.hashCode() : 0);
return result;
}
public static final class Tree extends AbstractHashTree<Tree, Hashes> {
//jackson support
private Tree() {
this(null, null, null);
}
private Tree(RelativePath path, Hashes hash, Map<Path.Segment, Tree> children) {
super(path, hash == null ? new Hashes(null, null, null) : hash, children);
}
public static Builder builder() {
return new Builder();
}
public interface AbstractBuilder<This extends AbstractHashTree.Builder<This, ChildBuilder<This>, Tree, Hashes>
& AbstractBuilder<This>>
extends AbstractHashTree.Builder<This, ChildBuilder<This>, Tree, Hashes> {
}
public static final class Builder
extends AbstractHashTree.AbstractBuilder<Builder, ChildBuilder<Builder>, Tree, Hashes>
implements AbstractBuilder<Builder>, TopBuilder<Builder, ChildBuilder<Builder>, Tree, Hashes> {
private Builder() {
super(Tree::new, ChildBuilder<Builder>::new);
}
@Override
public Tree build() {
return super.build();
}
}
public static final class ChildBuilder<
Parent extends AbstractHashTree.Builder<Parent, ChildBuilder<Parent>, Tree, Hashes>
& AbstractBuilder<Parent>>
extends AbstractChildBuilder<ChildBuilder<Parent>, Parent, ChildBuilder<ChildBuilder<Parent>>,
Tree, Hashes>
implements AbstractBuilder<ChildBuilder<Parent>>,
AbstractHashTree.ChildBuilder<ChildBuilder<Parent>, Parent, ChildBuilder<ChildBuilder<Parent>>, Tree,
Hashes> {
ChildBuilder(TreeConstructor<Tree, Hashes> tctor, Parent p) {
super(tctor, p, ChildBuilder<ChildBuilder<Parent>>::new);
}
}
}
}