Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: Freenet/RawMessage.java


1   /*
2    *$Id: RawMessage.java,v 1.19 2000/04/07 20:34:09 hobbex Exp $
3   
4     This code is part of the Java Adaptive Network Client by Ian Clarke. 
5     It is distributed under the GNU General Public Licence (GPL) 
6     version 2.  See http://www.gnu.org/ for further details of the GPL.
7    */
8   
9   /**
10   * This class represents a raw message in the general format
11   * expected by Freenet.  It can be created either from
12   * an InputStream or manually created from scratch.  It can
13   * then by piped out to an OutputStream.  Methods are provided
14   * for manipulation of normal fields, however the type of the
15   * message and the trailing field should be set by direct
16   * manipulation of fields.
17   *
18   * @author <A HREF="mailto:I.Clarke@strs.co.uk">Ian Clarke</A>
19   * @author <A HREF="mailto:blanu@uts.cc.utexas.edu">Brandon Wiley</A>
20   **/
21  package Freenet;
22  
23  import Freenet.support.*;
24  import java.io.*;
25  import java.io.EOFException;
26  import java.util.*;
27  
28  public class RawMessage
29  {
30    public static final boolean debug = true;
31  
32    /**
33     * Test method
34     **/
35    public static void main(String[] args)
36      throws Exception
37      {
38        RawMessage r = new RawMessage(System.in);
39        InputStream i = r.toInputStream();
40        int t=0;
41        while (t != -1)
42    {
43      t = i.read();
44      System.out.write(t);
45    }
46      }
47  
48    // Public Fields
49    /** The type of the message **/
50    public String messageType = null;
51    public Long trailingFieldLength;
52      public long trailingFieldLength() {return trailingFieldLength == null ? 0 :trailingFieldLength.longValue();}
53    public String trailingFieldName = null;
54    public InputStream trailingFieldStream = null;
55    
56    // Protected/Private Fields
57    protected Hashtable fields = new Hashtable();
58    protected static final char[] crlf = {'\n', '\r'};
59    protected static final char[] endfn = {'=', '\n', '\r'};
60  
61    // Constructors
62      public RawMessage(InputStream i) throws InvalidMessageException, EOFException
63      {
64        try
65    {
66        Logger.log("RawMessage.java","Reading message",Logger.DEBUGGING);
67      PushbackInputStream in = new PushbackInputStream(i);
68  
69      // Read message type
70      messageType = readTo(in, crlf);
71  
72      // Now read field/data pairs
73      while(true)
74        {
75          String name, data;
76          long length=0;
77          char r;
78  
79          // Read field name
80          remCRLF(in);
81          if (testEOF(in))
82        break;
83          name = readTo(in, endfn);
84  
85          if (testEOF(in))
86        break;
87          // If the next value is a CR then this is a
88          // trailing field
89          if (testEOF(in))
90        break;
91  
92          if ((r = (char)in.read()) == '\n' || r == '\r')
93        {
94            if(name.equals("EndMessage")) {
95          break;
96            } 
97            // Removing LF after CR
98            r = (char) in.read();
99            if (r != '\n')
100         in.unread ((int)r);
101 
102           Logger.log("RawMessage.java","Found trailing field",Logger.MINOR);
103           trailingFieldName = name;
104           String dl=readField("DataLength");
105                       if(dl!=null) {
106         trailingFieldLength = new Long(dl);
107         deleteField("DataLength");
108           }
109                       trailingFieldStream=in;
110           break;
111       }
112         else
113       { // This is not a trailing field
114                   data = readTo(in, crlf);
115       }
116         setField(name, data);
117       }
118 
119   }
120       catch (EOFException e)
121   {
122       if (messageType != null) {
123     // messages must end with "EndMessage"
124     Logger.log("RawMessage.java", "Stream died while reading message of type: " + messageType, Logger.ERROR);
125       }
126       else {
127     // stream closed without getting a new message
128     Logger.log("RawMessage.java", "Stream closed", Logger.DEBUGGING);
129       }
130       throw e;
131   }
132       catch (IOException e)
133   {
134     throw new InvalidMessageException("Could not parse message from stream.");
135   }
136       catch(Exception e)
137         {
138           Logger.log("RawMessage.java", "Exception in RawMessage()", Logger.ERROR);
139           e.printStackTrace();
140         }
141     }
142 
143   public RawMessage(String name)
144     {
145       messageType = name;
146     }
147 
148   // Public Methods
149 
150     public boolean isKeepAlive() {
151   return !(readField("KeepAlive") != null && readField("KeepAlive").equalsIgnoreCase("false"));
152     }
153 
154   public void deleteField(String name)
155     {
156       fields.remove(name);
157     }
158 
159   public String readField(String name)
160     {
161       return (String) fields.get(name);
162     }
163 
164   public void setField(String name, String value)
165     {
166       fields.put(name, value);
167     }
168 
169     public Enumeration fieldNames() {
170   return fields.keys();
171     }
172 
173 
174     /**
175      * @depreaciated This method could lock on large messages. Use
176      * writeMessage instead.
177      **/
178     public InputStream toInputStream() throws IOException
179     {
180   PipedOutputStream po=new PipedOutputStream();
181   BufferedInputStream pi=new BufferedInputStream(new PipedInputStream(po));
182   writeMessage(po);
183   po.flush();
184   po.close();
185 
186   return (trailingFieldStream != null) ? (InputStream)(new SequenceInputStream(pi, trailingFieldStream)) : (InputStream)pi;
187     }
188 
189     public InputStream getTrailing() {
190   return trailingFieldName != null ? trailingFieldStream : null;
191     }
192 
193 
194     public void writeMessage(OutputStream out) throws IOException
195     {
196   String key, value;
197 
198   PrintWriter writer=new PrintWriter(out);
199       
200   // Output message type
201   writer.println(messageType);
202 
203   // Output non-trailing fields
204   Enumeration iterator=fields.keys();
205   while(iterator.hasMoreElements()) {
206       key=(String)iterator.nextElement();
207       value=(String)fields.get(key);
208       writer.print(key+"="+value+"\n");
209   }
210 
211   // Output trailing field
212 
213   if (trailingFieldLength!=null)
214       writer.print("DataLength="+trailingFieldLength+"\n");
215         writer.print(trailingFieldName+"\n");
216 
217   writer.flush();
218     }
219 
220     public void writeTrailing(OutputStream out) 
221     {
222   if (trailingFieldStream!=null && out!=null) {
223       Conduit c = new Conduit(trailingFieldStream,out);
224       c.syncFeed();
225   }
226     }
227 
228   public String toString()
229     {
230       return messageType + "\n" + fields.toString();
231     }
232 
233   // Protected/Private Methods
234 
235   /**
236    * Removes any CRLFs from the part of the stream to be
237    * read next
238    **/
239   protected void remCRLF(PushbackInputStream i)
240     throws IOException
241     {
242       char r;
243       do
244   {
245     r = (char) i.read();
246   } while ((r == '\n') || (r == '\r'));
247       i.unread((int) r);
248     }
249 
250     /** Checks non-destructively whether we have received an EOF **/
251     protected boolean testEOF(PushbackInputStream i)
252   throws IOException
253     {
254   int c;
255   c = i.read();
256   if (c==-1)
257       return true;
258   else
259       {
260     i.unread(c);
261     return false;
262       }
263     }
264   
265   /**
266    * Will return String from InputStream until one of
267    * the characters in tms is about to be read.
268    **/
269   protected String readTo(PushbackInputStream i, char[] tms)
270     throws IOException, EOFException
271     {
272       StringBuffer tmp = new StringBuffer();
273       char r=' ';
274       int ir;
275       while (true)
276   {
277       ir = i.read();
278       if (ir == -1)
279     throw new EOFException();
280       r = (char) ir;
281       if (r == -1)
282     throw new EOFException();
283       boolean b = false;
284       for (int x=0; x<tms.length; x++)
285     {
286         if (tms[x] == r)
287       {
288           b=true;
289           break;
290       }
291     }
292       if (b)
293     break;
294       tmp.append(r);
295   }
296       if (ir != -1)
297     i.unread((int) r);
298       return tmp.toString();
299     }
300     
301 }
302 
303 /*
304  *$Log: RawMessage.java,v $
305  *Revision 1.19  2000/04/07 20:34:09  hobbex
306  *Fixed building and running with Kaffe (scripts/kbuild.sh). Added canceling of timer callback and sending of requestfailed on loosing MessageMemory (not too well tested). And fixed a bug in the datastore + some exception catching in requestfailed.
307  *
308  *Revision 1.18  2000/04/05 22:14:08  hobbex
309  *Unknown message fields are passed, and source is now optional for clients
310  *
311  *Revision 1.17  2000/03/31 14:36:13  hobbex
312  *Abstracted returning a message, and made replies set KeepAlive=false if the original message did
313  *
314  *Revision 1.16  2000/03/31 12:51:38  thong
315  *Make "stream died" error more intelligible
316  *
317  *Revision 1.15  2000/03/30 11:32:27  hobbex
318  *Close connections after sending KeepAlive=false message
319  *
320  *Revision 1.14  2000/03/29 00:30:45  hal
321  *Check for CR at end of EndMessage line.
322  *
323  *Revision 1.13  2000/03/27 21:02:32  hobbex
324  *Sustained streams
325  *
326  *Revision 1.12  2000/02/29 06:46:56  blanu
327  *Stray debugging println removed.
328  *
329  *Revision 1.11  2000/02/29 06:35:36  blanu
330  *Handshaking is now in a message-like format. It actually uses RawMessage to construct the handshake.
331  *RawMessage now supports the EndMessage field to end a message instead of EOF.
332  *This is useful for handshaking and also for future Keepalive connections.
333  *
334  *Revision 1.10  2000/02/17 14:12:54  hobbex
335  *catch unknown message types
336  *
337  *Revision 1.9  2000/02/17 12:52:23  hobbex
338  *removed runtime exception on bad connection (annoying)
339  *
340  *Revision 1.8  2000/02/12 13:59:57  hobbex
341  *fixed tunneling on inserts for large files. Britney never sounded so good!
342  *
343  *Revision 1.7  2000/02/11 20:12:01  hobbex
344  *Fixed tunneling to use only one thread. Changed Rawmessage to write to output streams rather than return inputstreams. Fixed releasing of DataStream when a message is dropped.
345  *
346  *Revision 1.6  2000/02/09 23:56:39  hobbex
347  *Preliminary tunneling of DataReplies and DataInserts (for now)
348  *
349  *Revision 1.5  2000/01/27 15:45:39  sanity
350  *Some bug fixes, added localAddress field to Node.java which is used by
351  *DataRequest and DataReply messages to set dataSource field.  Also removed
352  *untidy debugging stuff from RawMessage.
353  *
354  *Revision 1.4  2000/01/11 06:32:05  blanu
355  *fixed problem with hex uniqueid and name=value field format
356  *
357  *Revision 1.3  2000/01/11 02:02:51  blanu
358  *changed from -: to = field format
359  *
360  *Revision 1.2  2000/01/03 16:32:07  hobbex
361  *Changed various println to Logger - think I got them all
362  *
363  *Revision 1.1.1.1  1999/12/31 11:53:02  sanity
364  *Initial import from OpenProjects
365  *
366  *Revision 1.4  1999/12/29 07:14:06  michael
367  *Additional LF after CR of trailing field - bug fixed
368  *
369  *
370  */