/* * #! * Ontopia Engine * #- * Copyright (C) 2001 - 2013 The Ontopia Project * #- * 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 net.ontopia.persistence.proxy; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Arrays; import net.ontopia.utils.OntopiaRuntimeException; /** * INTERNAL: Class used for representing data store object identities * with more than a single key. See {@link IdentityIF}. */ public final class Identity implements IdentityIF, Externalizable { static final long serialVersionUID = 5662829503505256457L; private Class<?> type; private Object[] keys; private int hashcode; /** * INTERNAL: Constructor that is used for externalization purposes * only. */ public Identity() { } /** * INTERNAL: Creates an identity instance of the given type with the * given keys. */ public Identity(Class<?> type, Object[] keys) { this.type = type; this.keys = keys; this.hashcode = computeHashCode(); } public Class<?> getType() { return type; } public int getWidth() { return keys.length; } public Object getKey(int index) { return keys[index]; } public Object createInstance() throws Exception { return ((Class)type).newInstance(); } public int hashCode() { return hashcode; } public int computeHashCode() { // Note: This is the same implementation as in java.util.List int hashcode = 1 + type.hashCode(); for (int i=0; i < keys.length; i++) { hashcode = 31*hashcode + keys[i].hashCode(); } return hashcode; } public boolean equals(Object object) { if (object instanceof IdentityIF) { // Compare types IdentityIF other = (IdentityIF)object; // FIXME: Use Arrays.compare(Object[], Object[]) instead. // Compare array length int width = keys.length; if (width != other.getWidth()) return false; // Compare array elements for (int i=0; i < width; i++) { Object okey = other.getKey(i); if (!keys[i].equals(okey)) return false; } // Compare type return type.equals(other.getType()); } else { return false; } } public String toString() { return "<Identity " + Arrays.asList(keys) + " " + type + ">"; } // ----------------------------------------------------------------------------- // Externalization // ----------------------------------------------------------------------------- public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(type); out.writeObject(keys); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { type = (Class<?>)in.readObject(); keys = (Object[])in.readObject(); this.hashcode = computeHashCode(); } public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { // Ignore throw new OntopiaRuntimeException(e); } } }