mev-4.0.01/source/org/tigr/microarray/mev/r/Rtalk.java

Code
Comments
Other
Rev Date Author Line
2 26 Feb 07 jari 1 package org.tigr.microarray.mev.r;
2 26 Feb 07 jari 2
2 26 Feb 07 jari 3 import java.io.InputStream;
2 26 Feb 07 jari 4 import java.io.OutputStream;
2 26 Feb 07 jari 5
2 26 Feb 07 jari 6 /** This class encapsulates the QAP1 protocol used by Rserv.
2 26 Feb 07 jari 7     it is independent of the underying protocol(s), therefore Rtalk
2 26 Feb 07 jari 8     can be used over any transport layer
2 26 Feb 07 jari 9     <p>
2 26 Feb 07 jari 10     The current implementation supports long (0.3+/0102) data format only
2 26 Feb 07 jari 11     up to 32-bit and only for incoming packets.
2 26 Feb 07 jari 12     <p>
2 26 Feb 07 jari 13     @version $Id$
2 26 Feb 07 jari 14 */
2 26 Feb 07 jari 15 public class Rtalk {
2 26 Feb 07 jari 16     public static final int DT_INT=1;
2 26 Feb 07 jari 17     public static final int DT_CHAR=2;
2 26 Feb 07 jari 18     public static final int DT_DOUBLE=3;
2 26 Feb 07 jari 19     public static final int DT_STRING=4;
2 26 Feb 07 jari 20     public static final int DT_BYTESTREAM=5;
2 26 Feb 07 jari 21     public static final int DT_SEXP=10;
2 26 Feb 07 jari 22     public static final int DT_ARRAY=11;
2 26 Feb 07 jari 23
2 26 Feb 07 jari 24     /** this is a flag saying that the contents is large (>0xfffff0) and hence uses 56-bit length field */
2 26 Feb 07 jari 25     public static final int DT_LARGE=64;
2 26 Feb 07 jari 26
2 26 Feb 07 jari 27     public static final int CMD_login=0x001;
2 26 Feb 07 jari 28     public static final int CMD_voidEval=0x002;
2 26 Feb 07 jari 29     public static final int CMD_eval=0x003;
2 26 Feb 07 jari 30     public static final int CMD_shutdown=0x004;
2 26 Feb 07 jari 31     public static final int CMD_openFile=0x010;
2 26 Feb 07 jari 32     public static final int CMD_createFile=0x011;
2 26 Feb 07 jari 33     public static final int CMD_closeFile=0x012;
2 26 Feb 07 jari 34     public static final int CMD_readFile=0x013;
2 26 Feb 07 jari 35     public static final int CMD_writeFile=0x014;
2 26 Feb 07 jari 36     public static final int CMD_removeFile=0x015;
2 26 Feb 07 jari 37     public static final int CMD_setSEXP=0x020;
2 26 Feb 07 jari 38     public static final int CMD_assignSEXP=0x021;
2 26 Feb 07 jari 39     
2 26 Feb 07 jari 40     public static final int CMD_setBufferSize=0x081;
2 26 Feb 07 jari 41
2 26 Feb 07 jari 42     // errors as returned by Rserve
2 26 Feb 07 jari 43     public static final int ERR_auth_failed=0x41;
2 26 Feb 07 jari 44     public static final int ERR_conn_broken=0x42;
2 26 Feb 07 jari 45     public static final int ERR_inv_cmd=0x43;
2 26 Feb 07 jari 46     public static final int ERR_inv_par=0x44;
2 26 Feb 07 jari 47     public static final int ERR_Rerror=0x45;
2 26 Feb 07 jari 48     public static final int ERR_IOerror=0x46;
2 26 Feb 07 jari 49     public static final int ERR_not_open=0x47;
2 26 Feb 07 jari 50     public static final int ERR_access_denied=0x48;
2 26 Feb 07 jari 51     public static final int ERR_unsupported_cmd=0x49;
2 26 Feb 07 jari 52     public static final int ERR_unknown_cmd=0x4a;
2 26 Feb 07 jari 53     public static final int ERR_data_overflow=0x4b;
2 26 Feb 07 jari 54     public static final int ERR_object_too_big=0x4c;
2 26 Feb 07 jari 55     public static final int ERR_out_of_mem=0x4d;
2 26 Feb 07 jari 56    
2 26 Feb 07 jari 57     InputStream is;
2 26 Feb 07 jari 58     OutputStream os;
2 26 Feb 07 jari 59     
2 26 Feb 07 jari 60     /** constructor; parameters specify the streams
2 26 Feb 07 jari 61   @param sis socket input stream
2 26 Feb 07 jari 62   @param sos socket output stream */
2 26 Feb 07 jari 63
2 26 Feb 07 jari 64     public Rtalk(InputStream sis, OutputStream sos) {
2 26 Feb 07 jari 65   is=sis; os=sos;
2 26 Feb 07 jari 66     }
2 26 Feb 07 jari 67
2 26 Feb 07 jari 68     /** writes bit-wise int to a byte buffer at specified position in Intel-endian form
2 26 Feb 07 jari 69   @param v value to be written
2 26 Feb 07 jari 70   @param buf buffer
2 26 Feb 07 jari 71   @param o offset in the buffer to start at. An int takes always 4 bytes */
2 26 Feb 07 jari 72     public static void setInt(int v, byte[] buf, int o) {
2 26 Feb 07 jari 73   buf[o]=(byte)(v&255); o++;
2 26 Feb 07 jari 74   buf[o]=(byte)((v&0xff00)>>8); o++;
2 26 Feb 07 jari 75   buf[o]=(byte)((v&0xff0000)>>16); o++;
2 26 Feb 07 jari 76   buf[o]=(byte)((v&0xff000000)>>24);
2 26 Feb 07 jari 77     }
2 26 Feb 07 jari 78
2 26 Feb 07 jari 79     /** writes cmd/resp/type byte + 3/7 bytes len into a byte buffer at specified offset.
2 26 Feb 07 jari 80   @param ty type/cmd/resp byte
2 26 Feb 07 jari 81   @param len length
2 26 Feb 07 jari 82   @param buf buffer
2 26 Feb 07 jari 83   @param o offset
2 26 Feb 07 jari 84         @return offset in buf just after the header. Please note that since Rserve 0.3 the header can be either 4 or 8 bytes long, depending on the len parameter.
2 26 Feb 07 jari 85         */
2 26 Feb 07 jari 86     public static int setHdr(int ty, int len, byte[] buf, int o) {
2 26 Feb 07 jari 87         buf[o]=(byte)((ty&255)|((len>0xfffff0)?DT_LARGE:0)); o++;
2 26 Feb 07 jari 88   buf[o]=(byte)(len&255); o++;
2 26 Feb 07 jari 89   buf[o]=(byte)((len&0xff00)>>8); o++;
2 26 Feb 07 jari 90   buf[o]=(byte)((len&0xff0000)>>16); o++;
2 26 Feb 07 jari 91         if (len>0xfffff0) { // for large data we need to set the next 4 bytes as well
2 26 Feb 07 jari 92             buf[o]=(byte)((len&0xff000000)>>24); o++;
2 26 Feb 07 jari 93             buf[o]=0; o++; // since len is int, we get 32-bits only
2 26 Feb 07 jari 94             buf[o]=0; o++;
2 26 Feb 07 jari 95             buf[o]=0; o++;
2 26 Feb 07 jari 96         }
2 26 Feb 07 jari 97         return o;
2 26 Feb 07 jari 98     }
2 26 Feb 07 jari 99
2 26 Feb 07 jari 100     /** creates a new header according to the type and length of the parameter
2 26 Feb 07 jari 101         @param ty type/cmd/resp byte
2 26 Feb 07 jari 102         @param len length */        
2 26 Feb 07 jari 103     public static byte[] newHdr(int ty, int len) {
2 26 Feb 07 jari 104         byte[] hdr=new byte[(len>0xfffff0)?8:4];
2 26 Feb 07 jari 105         setHdr(ty,len,hdr,0);
2 26 Feb 07 jari 106         return hdr;
2 26 Feb 07 jari 107     }
2 26 Feb 07 jari 108     
2 26 Feb 07 jari 109     /** converts bit-wise stored int in Intel-endian form into Java int
2 26 Feb 07 jari 110   @param buf buffer containg the representation
2 26 Feb 07 jari 111   @param o offset where to start (4 bytes will be used)
2 26 Feb 07 jari 112   @return the int value. no bounds checking is done so you need to
2 26 Feb 07 jari 113           make sure that the buffer is big enough */
2 26 Feb 07 jari 114     public static int getInt(byte[] buf, int o) {
2 26 Feb 07 jari 115   return ((buf[o]&255)|((buf[o+1]&255)<<8)|((buf[o+2]&255)<<16)|((buf[o+3]&255)<<24));
2 26 Feb 07 jari 116     }
2 26 Feb 07 jari 117
2 26 Feb 07 jari 118     /** converts bit-wise stored length from a header. "long" format is supported up to 32-bit
2 26 Feb 07 jari 119   @param buf buffer
2 26 Feb 07 jari 120   @param o offset of the header (length is at o+1)
2 26 Feb 07 jari 121   @return length */
2 26 Feb 07 jari 122     public static int getLen(byte[] buf, int o) {
2 26 Feb 07 jari 123
2 26 Feb 07 jari 124         return
2 26 Feb 07 jari 125         ((buf[o]&64)>0)? // "long" format; still - we support 32-bit only
2 26 Feb 07 jari 126         ((buf[o+1]&255)|((buf[o+2]&255)<<8)|((buf[o+3]&255)<<16)|((buf[o+4]&255)<<24))
2 26 Feb 07 jari 127         :
2 26 Feb 07 jari 128         ((buf[o+1]&255)|((buf[o+2]&255)<<8)|((buf[o+3]&255)<<16));
2 26 Feb 07 jari 129     }
2 26 Feb 07 jari 130
2 26 Feb 07 jari 131     /** converts bit-wise Intel-endian format into long
2 26 Feb 07 jari 132   @param buf buffer
2 26 Feb 07 jari 133   @param o offset (8 bytes will be used)
2 26 Feb 07 jari 134   @return long value */
2 26 Feb 07 jari 135     public static long getLong(byte[] buf, int o) {
2 26 Feb 07 jari 136   long low=((long)getInt(buf,o))&0xffffffffL;
2 26 Feb 07 jari 137   long hi=((long)getInt(buf,o+4))&0xffffffffL;
2 26 Feb 07 jari 138   hi<<=32; hi|=low;
2 26 Feb 07 jari 139   return hi;
2 26 Feb 07 jari 140     }
2 26 Feb 07 jari 141
2 26 Feb 07 jari 142     public static void setLong(long l, byte[] buf, int o) {
2 26 Feb 07 jari 143   setInt((int)(l&0xffffffffL),buf,o);
2 26 Feb 07 jari 144   setInt((int)(l>>32),buf,o+4);
2 26 Feb 07 jari 145     }
2 26 Feb 07 jari 146
2 26 Feb 07 jari 147     /** sends a request with no attached parameters
2 26 Feb 07 jari 148   @param cmd command
2 26 Feb 07 jari 149   @return returned packet or <code>null</code> if something went wrong */
2 26 Feb 07 jari 150     public Rpacket request(int cmd) {
2 26 Feb 07 jari 151         byte[] d = new byte[0];
2 26 Feb 07 jari 152         return request(cmd,d);
2 26 Feb 07 jari 153     }
2 26 Feb 07 jari 154
2 26 Feb 07 jari 155     /** sends a request with attached parameters
2 26 Feb 07 jari 156         @param cmd command
2 26 Feb 07 jari 157         @param cont contents - parameters
2 26 Feb 07 jari 158         @return returned packet or <code>null</code> if something went wrong */
2 26 Feb 07 jari 159     public Rpacket request(int cmd, byte[] cont) {
2 26 Feb 07 jari 160         return request(cmd,null,cont,0,(cont==null)?0:cont.length);
2 26 Feb 07 jari 161     }
2 26 Feb 07 jari 162
2 26 Feb 07 jari 163     /** sends a request with attached prefix and  parameters. Both prefix and cont can be <code>null</code>. Effectively <code>request(a,b,null)</code> and <code>request(a,null,b)</code> are equivalent.
2 26 Feb 07 jari 164   @param cmd command
2 26 Feb 07 jari 165         @param prefix - this content is sent *before* cont. It is provided to save memory copy operations where a small header precedes a large data chunk (usually prefix conatins the parameter header and cont contains the actual data).
2 26 Feb 07 jari 166         @param cont contents
2 26 Feb 07 jari 167         @param offset offset in cont where to start sending (if <0 then 0 is assumed, if >cont.length then no cont is sent)
2 26 Feb 07 jari 168         @param len number of bytes in cont to send (it is clipped to the length of cont if necessary)
2 26 Feb 07 jari 169   @return returned packet or <code>null</code> if something went wrong */
2 26 Feb 07 jari 170     public Rpacket request(int cmd, byte[] prefix, byte[] cont, int offset, int len) {
2 26 Feb 07 jari 171         if (cont!=null) {
2 26 Feb 07 jari 172             if (offset>=cont.length) { cont=null; len=0; }
2 26 Feb 07 jari 173             else if (len>cont.length-offset) len=cont.length-offset;
2 26 Feb 07 jari 174         }
2 26 Feb 07 jari 175         if (offset<0) offset=0;
2 26 Feb 07 jari 176         if (len<0) len=0;
2 26 Feb 07 jari 177         int contlen=(cont==null)?0:len;
2 26 Feb 07 jari 178         if (prefix!=null && prefix.length>0) contlen+=prefix.length;
2 26 Feb 07 jari 179   byte[] hdr=new byte[16];
2 26 Feb 07 jari 180   setInt(cmd,hdr,0);
2 26 Feb 07 jari 181   setInt(contlen,hdr,4);
2 26 Feb 07 jari 182   for(int i=8;i<16;i++) hdr[i]=0;
2 26 Feb 07 jari 183   try {
2 26 Feb 07 jari 184       os.write(hdr);
2 26 Feb 07 jari 185             if (prefix!=null && prefix.length>0)
2 26 Feb 07 jari 186                 os.write(prefix);
2 26 Feb 07 jari 187       if (cont!=null && cont.length>0)
2 26 Feb 07 jari 188     os.write(cont,offset,len);
2 26 Feb 07 jari 189
2 26 Feb 07 jari 190       byte[] ih=new byte[16];
2 26 Feb 07 jari 191       if (is.read(ih)!=16)
2 26 Feb 07 jari 192     return null;
2 26 Feb 07 jari 193       int rep=getInt(ih,0);
2 26 Feb 07 jari 194       int rl =getInt(ih,4);
2 26 Feb 07 jari 195       if (rl>0) {
2 26 Feb 07 jari 196     byte[] ct=new byte[rl];
2 26 Feb 07 jari 197                 int n=0;
2 26 Feb 07 jari 198                 while (n<rl) {
2 26 Feb 07 jari 199                     int rd=is.read(ct,n,rl-n);
2 26 Feb 07 jari 200                     n+=rd;
2 26 Feb 07 jari 201                 }
2 26 Feb 07 jari 202     return new Rpacket(rep,ct);
2 26 Feb 07 jari 203       }
2 26 Feb 07 jari 204       return new Rpacket(rep,null);
2 26 Feb 07 jari 205   } catch(Exception e) {
2 26 Feb 07 jari 206       return null;
2 26 Feb 07 jari 207   }
2 26 Feb 07 jari 208     }
2 26 Feb 07 jari 209
2 26 Feb 07 jari 210     /** sends a request with one string parameter attached
2 26 Feb 07 jari 211   @param cmd command
2 26 Feb 07 jari 212   @param par parameter - length and DT_STRING will be prepended
2 26 Feb 07 jari 213   @return returned packet or <code>null</code> if something went wrong */
2 26 Feb 07 jari 214     public Rpacket request(int cmd, String par) {
2 26 Feb 07 jari 215   try {
2 26 Feb 07 jari 216             byte[] b=par.getBytes(Rconnection.transferCharset);
2 26 Feb 07 jari 217             int sl=par.length()+1;
2 26 Feb 07 jari 218             if ((sl&3)>0) sl=(sl&0xfffffc)+4; // make sure the length is divisible by 4
2 26 Feb 07 jari 219       byte[] rq=new byte[sl+5];
2 26 Feb 07 jari 220             int i;
2 26 Feb 07 jari 221       for(i=0;i<b.length;i++)
2 26 Feb 07 jari 222                 rq[i+4]=b[i];
2 26 Feb 07 jari 223             while (i<sl) { // pad with 0
2 26 Feb 07 jari 224                 rq[i+4]=0; i++;
2 26 Feb 07 jari 225             };
2 26 Feb 07 jari 226       setHdr(DT_STRING,sl,rq,0);
2 26 Feb 07 jari 227       return request(cmd,rq);
2 26 Feb 07 jari 228   } catch (Exception e) {
2 26 Feb 07 jari 229   };
2 26 Feb 07 jari 230   return null;
2 26 Feb 07 jari 231     }
2 26 Feb 07 jari 232
2 26 Feb 07 jari 233     /** sends a request with one string parameter attached
2 26 Feb 07 jari 234         @param cmd command
2 26 Feb 07 jari 235         @param par parameter of the type DT_INT
2 26 Feb 07 jari 236         @return returned packet or <code>null</code> if something went wrong */
2 26 Feb 07 jari 237     public Rpacket request(int cmd, int par) {
2 26 Feb 07 jari 238   try {
2 26 Feb 07 jari 239       byte[] rq=new byte[8];
2 26 Feb 07 jari 240       setInt(par,rq,4);
2 26 Feb 07 jari 241       setHdr(DT_INT,4,rq,0);
2 26 Feb 07 jari 242       return request(cmd,rq);
2 26 Feb 07 jari 243   } catch (Exception e) {
2 26 Feb 07 jari 244   };
2 26 Feb 07 jari 245   return null;
2 26 Feb 07 jari 246     }
2 26 Feb 07 jari 247 }