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

Quick Search    Search Deep

Source code: com/synaptics/elvis/ElvisMessage.java


1   /*
2    * The contents of this file are subject to the Mozilla Public License Version 
3    * 1.1 (the "License"); you may not use this file except in compliance with the 
4    * License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ 
5    *
6    * Software distributed under the License is distributed on an "AS IS" basis, 
7    * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
8    * the specific language governing rights and limitations under the License.
9    *
10   * The Original Code is com.synaptics.elvis code.
11   *
12   * The Initial Developers of the Original Code are Synaptics, Inc. and Christopher Heiny.
13   * Portions created by Synaptics, Inc. and Christopher Heiny are
14   * Copyright (C) 2002 Synaptics, Inc. and Christopher Heiny. All Rights Reserved.
15   *
16   * Contributor(s):
17   *    Christopher Heiny <cheiny@synaptics.com>
18   */
19  
20  package com.synaptics.elvis;
21  
22  import java.beans.*;
23  
24  /** ElvisMessage is used internally by Elvis to both build and parse the messages
25   * exchanged between the One True Elvis and various impersonators.
26   * <P>
27   * Each message has five fields:
28   * <UL>
29   * <LI>the Elvis identified field.  This field is always the string <CODE>"Elvis"</code>
30   * <LI>the Elvis program name.  This is the program name associated with this application.
31   * We check this to ensure that Elvis impersonators are talking to the One True Elvis they
32   * are expecting to talk to.
33   * <LI>the key.  This is a random integer that helps to uniquely identify a particular instance of
34   * the One True Elvis.  It is used mainly for security purposes - an attacker must not only know the
35   * Elvis program name he wishes to exploit, but he must be able to guess the key the program is currently
36   * using.  While by no means bulletproof, this makes it much harder for an attacker to either submit
37   * fraudulent requests to the One True Elvis, or to spoof responses to the Elvis impersonators.
38   * <LI>the keyword.  This indicates what the message is, and what semantics should be applied to it.
39   * <LI>the data.  This is a string, which may contain status information, or may contain information of
40   * interest to the client.  It may be <CODE>null</code> or empty.
41   * </ol>
42   * For transmission to the One True Elvis, the fields are assembled into a single string, with the fields
43   * delimited by colon (<CODE>':'</code>) characters.  This means it is a bad idea for any of the fields (except
44   * the <CODE>data</code> field) to contain a <CODE>':'</code>.
45   * <P>
46   * Additionally, the transmitted message is read as a single string.  This means that it is a bad idea for
47   * any of the fields to contain an end-of-line sequence of any sort.
48   *
49   * @author  cheiny
50   * @version $Id: ElvisMessage.java,v 1.1 2002/05/09 07:17:17 clheiny Exp $
51   */
52  class ElvisMessage extends Object implements java.io.Serializable {
53  
54      private PropertyChangeSupport propertySupport;
55  
56      /** Holds value of property program. */
57      private String program;
58      
59      /** Holds value of property key. */
60      private String key;
61      
62      /** Holds value of property keyword. */
63      private String keyword;
64      
65      /** Holds value of property data. */
66      private String data;
67      
68      public static final char SEPARATOR = ':';
69      
70      public static final String HEADER = SEPARATOR + "Elvis" + SEPARATOR;
71      
72      /** Creates new ElvisMessage */
73      private ElvisMessage() {
74          propertySupport = new PropertyChangeSupport ( this );
75      }
76      
77      /** Create a new ElvisMessage for the given program, key, keyword and data
78       * @throws IllegalArgumentException if any of the above are null or zero length (except data).
79       */
80      ElvisMessage ( String program, String key, String keyword, String data ) {
81          if ( (program == null) || (program.length() == 0) ) throw new IllegalArgumentException ( "Invalid program provided" );
82          if ( (key == null) || (key.length() == 0) ) throw new IllegalArgumentException ( "Invalid key provided" );
83          if ( (keyword == null) || (keyword.length() == 0) ) throw new IllegalArgumentException ( "Invalid keyword provided" );
84          if ( data == null ) data = "";
85          propertySupport = new PropertyChangeSupport ( this );
86          this.program = program;
87          this.key = key;
88          this.keyword = keyword;
89          this.data = data;
90      }
91  
92  
93      public void addPropertyChangeListener (PropertyChangeListener listener) {
94          propertySupport.addPropertyChangeListener (listener);
95      }
96  
97      public void removePropertyChangeListener (PropertyChangeListener listener) {
98          propertySupport.removePropertyChangeListener (listener);
99      }
100 
101     /** Get the program name associated with this message.
102      * @return A String: the program name.
103      */
104     public String getProgram() {
105         return program;
106     }
107     
108     /** Set the program name.  Not available to anyone else.
109      * @param program New program name.
110      */
111     private void setProgram(String program) {
112         this.program = program;
113     }
114     
115     /** Get the key associated with this message.
116      * @return A String.
117      */
118     public String getKey() {
119         return key;
120     }
121     
122     /** Set the message's key.  Not available to anyone else.
123      * @param key A String, the new key.
124      */
125     private void setKey(String key) {
126         this.key = key;
127     }
128     
129     /** Get the keyword associated with this message.
130      * @return A String - the keyword.
131      */
132     public String getKeyword() {
133         return keyword;
134     }
135     
136     /** Set the message's keyword.  Not available to anyone else.
137      * @param keyword A String - the new keyword.
138      */
139     private void setKeyword(String keyword) {
140         this.keyword = keyword;
141     }
142     
143     /** Get the data field associated with this message.
144      * @return The data field.  May be null or empty.
145      */
146     public String getData() {
147         return data;
148     }
149     
150     /** Set the message's data.  Not available to anyone else.
151      * @param data The new data value.  If <CODE>null</code>, the empty string
152      * will be substituted.
153      */
154     private void setData(String data) {
155         if ( data == null ) data = "";
156         this.data = data;
157     }
158     
159     /** This is a factory method for creating an ElvisMessage from a given
160      * input string (hopefully, one received from an Elvis or an Elvis client.
161      * @throws ElvisException if the message is not parseable.
162      */
163     public static ElvisMessage parse(java.lang.String input) {
164         ElvisMessage msg = new ElvisMessage();
165         String token;
166         int index;
167         int field;
168         
169         if ( input.length() < 10 ) {
170                 // we expect at least 5 fields, each at least one character long
171             throw new ElvisException ( "Message is too short" );
172         }
173         
174             // first char should be delimiter
175         index = input.indexOf ( SEPARATOR );
176         if ( index != 0 ) {
177             throw new ElvisException ( "Malformed message - first character is not '" + SEPARATOR + "'" );
178         }
179         
180             // first token should be Elvis
181         if ( !input.startsWith(HEADER) ) {
182             throw new ElvisException ( "Incorrect header on message" );
183         }
184         
185             // next token is program name
186         int startIndex = HEADER.length();
187         index = input.indexOf ( SEPARATOR, HEADER.length() );
188         if ( index < 0 ) {
189                 // no separator
190             throw new ElvisException ( "Malformed message - no program name" );
191         }
192         token = input.substring( startIndex, index );
193         if ( token.length() == 0 ) {
194                 // empty not allowed
195             throw new ElvisException ( "Malformed message - empty program name" );
196         }
197         msg.setProgram ( token );
198         
199             // next token is key
200         startIndex = index+1;
201         index = input.indexOf ( SEPARATOR, startIndex );
202         if ( index < 0 ) {
203                 // no separator
204             throw new ElvisException ( "Malformed message - no key" );
205         }
206         token = input.substring( startIndex, index );
207         if ( token.length() == 0 ) {
208                 // empty not allowed
209             throw new ElvisException ( "Malformed message - empty key" );
210         }
211         msg.setKey ( token );
212         
213             // next token is keyword
214         startIndex = index+1;
215         index = input.indexOf ( SEPARATOR, startIndex );
216         if ( index < 0 ) {
217                 // no separator
218             throw new ElvisException ( "Malformed message - no keyword" );
219         }
220         token = input.substring( startIndex, index );
221         if ( token.length() == 0 ) {
222                 // empty not allowed
223             throw new ElvisException ( "Malformed message - empty keyword" );
224         }
225         if ( ! (ElvisRequest.valid(token) || ElvisResponse.valid(token)) ) {
226                 // we don't recognize what they're asking us to do
227             throw new ElvisException ( "Invalid keyword " + token );
228         }
229         msg.setKeyword ( token );
230         
231             // remainder of string is data, allowed to be empty
232         if ( index == input.length()-1 ) msg.setData ( "" );
233         else msg.setData ( input.substring (index+1) );
234         
235         return msg;
236     }
237     
238     /** Return the String representation of this message.  This will be suitable for sending
239      * to Elvis, or for an Elvis to return to an ElvisClient.
240      * @returns the string as described
241      */
242     public String toString() {
243         return HEADER + program + SEPARATOR + key + SEPARATOR + keyword + SEPARATOR + data;
244     }
245     
246 }