Package com.sun.messaging.jmq.io

Source Code of com.sun.messaging.jmq.io.SysMessageID

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2000-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* @(#)SysMessageID.java  1.21 06/27/07
*/

package com.sun.messaging.jmq.io;

import java.io.*;
import com.sun.messaging.jmq.net.IPAddress;
import com.sun.messaging.jmq.util.Bits;

/**
* This class encapsulates a system message id. This message id uniquely
* identifies a message in the JMQ system. It consists of four values:
* the message sequence number, source IP address, source port and timestamp.
* Note that this is not the JMS MessageID that can be set by the client.
* <P>
* The Swift packet format specifies that the IP address be in IPv6 (128 bit)
* format, so we canonicalize all addresses to IPv6. Initially we will only
* be dealing with IPv4 addresses since that is all the JDK supports -- those
* get translated into an "IPv4-mapped IPv6" address.
*
*/
public class SysMessageID implements Cloneable {

    /**
     * Size of a SysMessageID when externalized.
     */
    public static final int ID_SIZE = 4 + 4 + 8 + IPAddress.IPV6_SIZE;

    private static String ID_PREFIX             = "ID:";

    protected int  sequence;
    protected int  port;
    protected long timestamp;
    protected IPAddress ip;

    private String msgID = null;
    private boolean dirty = true;
   
    transient protected int hashcodeVal = 0;

    /**
     * Construct an unititialized system message ID. It is assumed
     * the caller will set the fields either explicitly or via
     * readID()
     */
    public SysMessageID() {
  ip = new IPAddress();
  clear();
    }

    public static void main(String args[]) {
        SysMessageID trystr = new SysMessageID();

        System.out.println("With MAC Address");
        System.out.println("------------------------");
        // get IPAddress
        java.net.InetAddress inet = null;
        try {
            inet = java.net.InetAddress.getLocalHost();
        } catch (Exception e) {
        }
        // set initial sequence, etc
        trystr.setIPAddress(inet.getAddress(), IPAddress.getRandomMac());
        trystr.setPort(123);
        trystr.setTimestamp(123456);
        trystr.setSequence(5);
        System.out.println("\tOriginal: " + trystr);
        SysMessageID newid = get(trystr.toString());
        System.out.println("\tDecoded: " + newid);
        System.out.println("\tHash[o,n]=[" + trystr.hashCode()
                 + "," + newid.hashCode()+"]");
        System.out.println("\tEquals: " +(trystr.equals(newid)) +
                  " , " + (newid.equals(trystr)));
        // set initial sequence, etc
        System.out.println("\n\nWithout MAC Address");
        System.out.println("------------------------");
        trystr = new SysMessageID();
        trystr.setIPAddress(inet.getAddress());
        trystr.setPort(664);
        trystr.setTimestamp(789012);
        trystr.setSequence(2);
        System.out.println("\tOriginal: " + trystr);
        newid = get(trystr.toString());
        System.out.println("\tHash[o,n]=[" + trystr.hashCode()
                 + "," + newid.hashCode()+"]");
        System.out.println("\tEquals: "+ (trystr.equals(newid)) +
                  " , " + (newid.equals(trystr)));
        System.out.println("\tDecoded: " + get(trystr.toString()));
        System.out.println("\n\nIPV6");
        System.out.println("------------------------");
        System.out.println("Testing IPV6 requires changes to OS");
/*
        trystr = new SysMessageID();
        trystr.setIPAddress(inet.getAddress());
        trystr.setPort(772);
        trystr.setTimestamp(948345);
        trystr.setSequence(22);
        System.out.println("\tOriginal: " + trystr);
        newid = get(trystr.toString());
        System.out.println("\tDecoded: " + newid);
        System.out.println("\tHash[o,n]=[" + trystr.hashCode()
                 + "," + newid.hashCode()+"]");
        System.out.println("\tEquals: "+ (trystr.equals(newid)) +
                  " , " + (newid.equals(trystr)));
        System.out.println("\tDecoded: " + get(trystr.toString()));
*/
    }

    public static SysMessageID get(String sid)
    {
        SysMessageID id = new SysMessageID();

  /*
   * Strip out "ID:" if present
   */
        if (sid.startsWith(ID_PREFIX))  {
            sid = sid.substring(ID_PREFIX.length());
        }

        // parse string
        String[] ss = sid.split("-");

        if (ss.length != 4) { // something went wrong
            // this is specific case of negative port number (bug 6831547)
            // if the port is negative then ss[2] is empty and the length
            // of ss array is 5 instead of 4
            if (ss.length == 5 && ss[2].length() == 0){
                ss[2] = "-" + ss[3];
                ss[3] = ss[4];
             } else {
                throw new RuntimeException("Bad Sysmessage ID");
            }
        }
       
        int sequence = Integer.parseInt(ss[0]);
        int port = Integer.parseInt(ss[2]);
        long ts = Long.parseLong(ss[3]);

        IPAddress ip = IPAddress.readFromString(ss[1]);

        id.setPort(port);
        id.setSequence(sequence);
        id.setTimestamp(ts);
        id.ip = ip;
        return id;
    }


    /**
     * Clears the message id
     */
    public void clear() {
  sequence = port = 0;
  timestamp = 0;
  ip.clear();
        dirty = true;
    }

    /**
     * Check if the passed SysMessageID equals this one
     *
     * @param    o    the object to compare
     *
     * @return   true if the objects are equivalent, else false
     */
    public boolean equals(Object o) {

        if (this == o) return true;

        if (!(o instanceof SysMessageID)) {
            return false;
        }

        SysMessageID id = (SysMessageID)o;

  /*
   * We try to optimize the comparison so if it fails it fails
   * quickly. Most message id comparisions will be done when
   * the router handles acknowledgements from a client. In that
   * case the sequence number is the most likely to determine
   * uniqueness
   */
  return (
       this.sequence == id.sequence &&
      this.timestamp == id.timestamp &&
           this.port == id.port &&
           ip.equals(id.ip)
            );
    }

    public int hashCode() {
  // This should generate enough uniqueness without messing with
  // the IP address.
      if(hashcodeVal==0){ 
        int p = (port == 0 ? 1 : port);
        hashcodeVal = (int)timestamp * p * sequence;
      }
        return hashcodeVal;
    }


    /**
     * Return a string description. The string will be of the format:
     *
     *    nnn-nnn.nnn.nnn.nnn-nnnn-nnnnnnnnnnnn
     *    ^   ^               ^    ^
     *    seq IP              port timestamp
     *
     * @return    String description of message id
     *
     */
    public String toString() {

        if (msgID == null || dirty) {
            msgID = new StringBuffer(128)
                .append(sequence).append("-")
                .append(ip.toString()).append("-")
                .append(port).append("-")
                .append(timestamp)
                .toString();

            dirty = false;
        }

        return msgID;
    }

    /**
     * Generates a unique string that is suitable for use as a key.
     */
    public String getUniqueName() {
        return toString();
    }

    /**
     * Returns the unique string of msg ID prior to MQ 4.1.
     *
     * Note: should only be used for store migration
     */
    public String getUniqueNameOldFormat() {

        String uniqueName = String.valueOf(sequence) +
                            String.valueOf(timestamp) +
                            String.valueOf(port) +
                            IPAddress.rawIPToString(ip.getAddress(), false);

        return uniqueName;
    }

    public int getSequence() {
  return sequence;
    }

    public int getPort() {
  return port;
    }

    public long getTimestamp() {
  return timestamp;
    }

    /**
     * Get the IP address.
     *
     * @return   The raw IP address. This will always be an IPv6 (128 bit)
     *           address. It will contain an embedded Mac address if one
     *           was provided to setIPAddress().
     */
    public byte[] getIPAddress() {
  return ip.getAddress();
    }

    public void setSequence(int n) {
        dirty = true;
  sequence = n;
    }

    public void setPort(int n) {
        dirty = true;
  port = n;
    }

    public void setTimestamp(long n) {
        dirty = true;
  timestamp = n;
    }

    /**
     * Set the IP address.
     *
     * @param    newip    IP address in network byte order. This can be the
     *                    buffer returned by InetAddress.getAddress().
     *                    A null value results in the IP address being cleared.
     *
     */
    public void setIPAddress(byte[] newip)
  throws IllegalArgumentException {

  ip.setAddress(newip);
        dirty = true;
    }

    /**
     * Set the IP address and a 48 bit mac addres.
     *
     * @param    newip    IP address in network byte order. This can be the
     *                    buffer returned by InetAddress.getAddress().
     *                    A null value results in the IP address being cleared.
     *
     * @param   mac       6 byte MAC address (or random psuedo address. You
     *                    can get it from IPAddress.getRandomMac())
     *
     */
    public void setIPAddress(byte[] newip, byte[] mac)
  throws IllegalArgumentException {

  ip.setAddress(newip);

        if (mac != null && ip.getType() != IPAddress.IPV6) {
            // Only set mac if we are not IPV6
      ip.setMac(mac);
        }
        dirty = true;
    }

    /**
     * Write the ID to the specified DataOutput.
     * The format of the written data will be:
     *
     *   <PRE>
     *    0                   1                   2                   3
     *   |0 1 2 3 4 5 6 7|8 9 0 1 2 3 4 5|6 7 8 9 0 1 2 3|4 5 6 7 8 9 0 1|
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   |                                                               |
     *   +                        timestamp                              +
     *   |                                                               |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   |                                                               |
     *   +                                                               +
     *   |                     source IP                                 |
     *   +                                                               +
     *   |                                                               |
     *   +                                                               +
     *   |                                                               |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   |                      source port                              |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   |                     sequence number                           |
     *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     *   </PRE>
     *
     * This format matches the format specified in the ACKNOWLEDGE message
     * of the JMQ protocol spec.
     *
     * We don't use ObjectSerialization to do this because we don't want
     * the class version cruft that would be prefixed to the data.
     *
     * @param    out    DataOutput to write ID to
     */
    public void writeID(DataOutput out)
  throws IOException {

  out.writeLong(timestamp);
  ip.writeAddress(out);
  out.writeInt(port);
  out.writeInt(sequence);

        if (out instanceof DataOutputStream) {
            ((DataOutputStream)out).flush();
        }
    }

    /**
     * Returns the ID in a raw format. The format will be as described
     * in writeID, and the size of the byte[] will be ID_SIZE
     */
    public byte[] getRawID() {
        byte[] buf = new byte[ID_SIZE];

        int i = 0;
        i = Bits.put(buf, i, timestamp);
        i = Bits.put(buf, i, ip.getAddressUnsafe());
        i = Bits.put(buf, i, port);
            Bits.put(buf, i, sequence);

        return buf;
    }

    /**
     * Read the ID from the specified DataInput. The format of
     * the data is assumed to match that generated by writeID.
     *
     * @param    in    DataInput to write ID to
     *
     */
    public void readID(DataInput in)
  throws IOException {

  timestamp = in.readLong();
              ip.readAddress(in);
  port      = in.readInt();
  sequence  = in.readInt();
    }

    /**
     * Make a deep copy of this object
     */
    public Object clone() {
  try {
      SysMessageID newID = (SysMessageID)super.clone();
      newID.ip           = (IPAddress)this.ip.clone();
      return newID;
  } catch (CloneNotSupportedException e) {
      // Should never get this, but don't fail silently
      System.out.println("SysMessageID: Could not clone: " + e);
      return null;
  }
    }
}
TOP

Related Classes of com.sun.messaging.jmq.io.SysMessageID

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.