/* * Copyright 2008-2009 LinkedIn, Inc * * 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.sdnplatform.sync; import java.io.Serializable; import java.util.Arrays; import java.util.Comparator; import org.sdnplatform.sync.IVersion.Occurred; import org.sdnplatform.sync.internal.version.VectorClock; import com.google.common.base.Objects; /** * A wrapper for an object that adds a Version. * * */ public class Versioned<T> implements Serializable { private static final long serialVersionUID = 1; private volatile VectorClock version; private volatile T value; public Versioned(T object) { this(object, new VectorClock()); } public Versioned(T object, IVersion version) { this.version = version == null ? new VectorClock() : (VectorClock) version; this.value = object; } public IVersion getVersion() { return version; } public void increment(int nodeId, long time) { this.version = version.incremented(nodeId, time); } public T getValue() { return value; } public void setValue(T object) { this.value = object; } /** * Determines if two objects are equal as determined by * {@link Object#equals(Object)}, or "deeply equal" if both are arrays. * <p> * If both objects are null, true is returned; if both objects are array, * the corresponding {@link Arrays#deepEquals(Object[], Object[])}, or * {@link Arrays#equals(int[], int[])} or the like are called to determine * equality. * <p> * Note that this method does not "deeply" compare the fields of the * objects. */ private static boolean deepEquals(Object o1, Object o2) { if(o1 == o2) { return true; } if(o1 == null || o2 == null) { return false; } Class<?> type1 = o1.getClass(); Class<?> type2 = o2.getClass(); if(!(type1.isArray() && type2.isArray())) { return o1.equals(o2); } if(o1 instanceof Object[] && o2 instanceof Object[]) { return Arrays.deepEquals((Object[]) o1, (Object[]) o2); } if(type1 != type2) { return false; } if(o1 instanceof boolean[]) { return Arrays.equals((boolean[]) o1, (boolean[]) o2); } if(o1 instanceof char[]) { return Arrays.equals((char[]) o1, (char[]) o2); } if(o1 instanceof byte[]) { return Arrays.equals((byte[]) o1, (byte[]) o2); } if(o1 instanceof short[]) { return Arrays.equals((short[]) o1, (short[]) o2); } if(o1 instanceof int[]) { return Arrays.equals((int[]) o1, (int[]) o2); } if(o1 instanceof long[]) { return Arrays.equals((long[]) o1, (long[]) o2); } if(o1 instanceof float[]) { return Arrays.equals((float[]) o1, (float[]) o2); } if(o1 instanceof double[]) { return Arrays.equals((double[]) o1, (double[]) o2); } throw new AssertionError(); } @Override public boolean equals(Object o) { if(o == this) return true; else if(!(o instanceof Versioned<?>)) return false; Versioned<?> versioned = (Versioned<?>) o; return Objects.equal(getVersion(), versioned.getVersion()) && deepEquals(getValue(), versioned.getValue()); } @Override public int hashCode() { int v = 31 + version.hashCode(); if(value != null) { v += 31 * value.hashCode(); } return v; } @Override public String toString() { return "[" + value + ", " + version + "]"; } /** * Create a clone of this Versioned object such that the object pointed to * is the same, but the VectorClock and Versioned wrapper is a shallow copy. */ public Versioned<T> cloneVersioned() { return new Versioned<T>(this.getValue(), this.version.clone()); } public static <S> Versioned<S> value(S s) { return new Versioned<S>(s, new VectorClock()); } public static <S> Versioned<S> value(S s, IVersion v) { return new Versioned<S>(s, v); } public static <S> Versioned<S> emptyVersioned() { return new Versioned<S>(null, new VectorClock(0)); } public static final class HappenedBeforeComparator<S> implements Comparator<Versioned<S>> { public int compare(Versioned<S> v1, Versioned<S> v2) { Occurred occurred = v1.getVersion().compare(v2.getVersion()); if(occurred == Occurred.BEFORE) return -1; else if(occurred == Occurred.AFTER) return 1; else return 0; } } }