/* $Id$ */ package ibis.ipl.impl.multi; import ibis.ipl.IbisIdentifier; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataOutput; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.UnsupportedEncodingException; import java.util.HashMap; /** * This implementation of the {@link ibis.ipl.IbisIdentifier} interface * identifies an Ibis instance on the network. */ public final class MultiIbisIdentifier implements IbisIdentifier { /** * Generated */ private static final long serialVersionUID = 5259510418367257559L; /** * The location for this Ibis instance. */ public final Location location; /** The name of the pool to which this Ibis instance belongs. */ public final String pool; /** Extra data for registry. */ private byte[] registryData; /** Identification of Ibis instances, provided by the registry. */ private final String id; /** An Ibis identifier coded as a byte array. Computed once. */ private transient byte[] codedForm; private final HashMap<String, IbisIdentifier>idMap; /** The application tag for this multi ibis instance */ private byte[] tag; /** * Constructs an <code>IbisIdentifier</code> with the specified parameters. * @param id join id, allocated by the registry. * @param idMap implementation-dependent data. * @param registryData registry-dependent data. * @param location location of this Ibis instance. * @param pool identifies the run with the registry. */ public MultiIbisIdentifier(String id, HashMap<String, ibis.ipl.IbisIdentifier> idMap, byte[] registryData, Location location, String pool, byte[] applicationTag) { this.id = id; this.idMap = idMap; this.registryData = registryData; this.location = location; this.pool = pool; this.tag = applicationTag; this.codedForm = computeCodedForm(); } /** * Constructs an <code>IbisIdentifier</code> from the specified coded form. * @param codedForm the coded form. * @exception IOException is thrown in case of trouble. */ public MultiIbisIdentifier(byte[] codedForm) throws IOException { this(codedForm, 0, codedForm.length); } /** * Constructs an <code>IbisIdentifier</code> from the specified coded form, * at a particular offset and size. * @param codedForm the coded form. * @param offset offset in the coded form. * @param size size of the coded form. * @exception IOException is thrown in case of trouble. */ public MultiIbisIdentifier(byte[] codedForm, int offset, int size) throws IOException { this(new ObjectInputStream( new ByteArrayInputStream(codedForm, offset, size))); } /** * Reads an <code>IbisIdentifier</code> from the specified input stream. * @param dis the input stream. * @exception IOException is thrown in case of trouble. */ public MultiIbisIdentifier(ObjectInputStream dis) throws IOException { location = new Location(dis); pool = dis.readUTF(); idMap = new HashMap<String, ibis.ipl.IbisIdentifier>(); int subCount = dis.readInt(); for (int i = 0; i < subCount; i++) { try { String impl = dis.readUTF(); ibis.ipl.IbisIdentifier ibisId = (ibis.ipl.IbisIdentifier)dis.readObject(); idMap.put(impl, ibisId); } catch (ClassNotFoundException e) { // TODO should we be ignoring this? // It means we won't be able to connect on this Ibis but we lack // it anyway so I am not sure it matters. } } int registrySize = dis.readInt(); if (registrySize < 0) { registryData = null; } else { registryData = new byte[registrySize]; dis.readFully(registryData); } int tagSize = dis.readInt(); if (tagSize < 0) { tag = null; } else { tag = new byte[tagSize]; dis.readFully(tag); } id = dis.readUTF(); codedForm = computeCodedForm(); } /** * Returns the coded form of this <code>IbisIdentifier</code>. * @return the coded form. */ public byte[] toBytes() { if (codedForm == null) { codedForm = computeCodedForm(); } return codedForm.clone(); } private synchronized byte[] computeCodedForm() { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream dos = new ObjectOutputStream(bos); location.writeTo(dos); dos.writeUTF(pool); dos.write(idMap.size()); for (String impl:idMap.keySet()) { dos.writeUTF(impl); dos.writeObject(idMap.get(impl)); } if (registryData == null) { dos.writeInt(-1); } else { dos.writeInt(registryData.length); dos.write(registryData); } if (tag == null) { dos.writeInt(-1); } else { dos.writeInt(tag.length); dos.write(tag); } dos.writeUTF(id); dos.close(); return bos.toByteArray(); } catch(Exception e) { // Should not happen. return null; } } /** * Adds coded form of this <code>IbisIdentifier</code> to the specified * output stream. * @param dos the output stream. * @exception IOException is thrown in case of trouble. */ public void writeTo(DataOutput dos) throws IOException { if (codedForm == null) { codedForm = computeCodedForm(); } dos.write(codedForm); } public boolean equals(Object o) { if (o == this) { return true; } if (o == null) { return false; } if (! o.getClass().equals(getClass())) { return false; } MultiIbisIdentifier other = (MultiIbisIdentifier) o; return other.id.equals(id) && other.pool.equals(pool); } public int hashCode() { return id.hashCode(); } public String toString() { return "(Ibis " + id + ", location " + location + ")"; } public String name() { return "(Ibis " + id + ")"; } public ibis.ipl.Location location() { return location; } public String poolName() { return pool; } /** * Obtains the registry dependent data. * @return the data. */ public synchronized byte[] getRegistryData() { return registryData; } /** * Compare to the specified Ibis identifier. * @param c the Ibis identifier to compare to. */ public int compareTo(ibis.ipl.IbisIdentifier c) { if (c instanceof MultiIbisIdentifier) { // If not, the specified Ibis identifier is from a completely // different implementation. MultiIbisIdentifier other = (MultiIbisIdentifier) c; // First compare pools. int cmp = pool.compareTo(other.pool); if (cmp == 0) { cmp = location.compareTo(other.location); if (cmp == 0) { // Finally compare id. return id.compareTo(other.id); } } return cmp; } return this.getClass().getName().compareTo(c.getClass().getName()); } public String getID() { return id; } public String tagAsString() { if (tag == null) { return null; } try { return new String(tag, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException("could not convert tag to string", e); } } public byte[] tag() { return tag; } public IbisIdentifier subIdForIbis(String ibisName) { return idMap.get(ibisName); } }