1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package uk.ac.rdg.resc.jstyx;
30
31 import java.io.UnsupportedEncodingException;
32 import java.io.IOException;
33
34 import java.nio.charset.Charset;
35
36 import java.text.SimpleDateFormat;
37 import java.text.ParseException;
38
39 import java.util.Date;
40 import java.util.TimeZone;
41
42 import org.apache.mina.common.ByteBuffer;
43
44 /***
45 * Set of constants and useful static methods for the Styx protocol
46 * @author Jon Blower
47 * $Revision: 604 $
48 * $Date: 2006-03-21 14:58:42 +0000 (Tue, 21 Mar 2006) $
49 * $Log$
50 * Revision 1.12 2006/03/21 14:58:40 jonblower
51 * Implemented clear-text password-based authentication and did some simple tests
52 *
53 * Revision 1.11 2006/01/04 16:45:29 jonblower
54 * Implemented automatic termination of SGS instances using Quartz scheduler
55 *
56 * Revision 1.10 2006/01/04 11:24:56 jonblower
57 * Implemented time directory in the SGS instance namespace
58 *
59 * Revision 1.8 2005/03/18 13:55:55 jonblower
60 * Improved freeing of ByteBuffers, and bug fixes
61 *
62 * Revision 1.7 2005/03/16 22:16:41 jonblower
63 * Added Styx Grid Service classes to core module
64 *
65 * Revision 1.6 2005/03/16 17:55:46 jonblower
66 * Replaced use of java.nio.ByteBuffer with MINA's ByteBuffer to minimise copying of buffers
67 *
68 * Revision 1.5 2005/03/15 15:52:17 jonblower
69 * Added constant for maximum allowable message size
70 *
71 * Revision 1.4 2005/03/11 13:58:24 jonblower
72 * Merged MINA-Test_20059309 into main line of development
73 *
74 * Revision 1.3.2.1 2005/03/10 20:54:55 jonblower
75 * Removed references to Netty
76 *
77 * Revision 1.3 2005/03/09 16:59:51 jonblower
78 * Added HEADER_LENGTH
79 *
80 * Revision 1.2 2005/02/24 07:39:39 jonblower
81 * Added getDataSummary()
82 *
83 * Revision 1.1.1.1 2005/02/16 18:58:16 jonblower
84 * Initial import
85 *
86 */
87 public class StyxUtils
88 {
89 /***
90 * The header length of a StyxMessage
91 */
92 public static final int HEADER_LENGTH = 7;
93
94 /***
95 * The maximum length of a single Styx message. This is actually an
96 * arbitrary figure; there is no reason why messages can't be larger than this
97 */
98 public static final int MAX_MESSAGE_SIZE = 65536;
99
100
101 public static final int MAXUBYTE = 0xff;
102 public static final int MAXUSHORT = 0xffff;
103 public static final long MAXUINT = 0xffffffffL;
104 public static final long MAXULONG = -1;
105
106 public static final int NOTAG = MAXUSHORT;
107 public static final long NOFID = MAXUINT;
108
109 public static final int MAXPATHELEMENTS = 16;
110
111
112
113 public static final int OREAD = 0;
114 public static final int OWRITE = 1;
115 public static final int ORDWR = 2;
116 public static final int OEXEC = 3;
117 public static final int OTRUNC = 0x10;
118 public static final int ORCLOSE = 0x40;
119
120
121
122
123 public static final long DMDIR = 0x80000000L;
124 public static final long DMAPPEND = 0x40000000L;
125 public static final long DMEXCL = 0x20000000L;
126
127 public static final long DMAUTH = 0x8000000L;
128
129
130 private static final String charsetName = "UTF-8";
131 public static final Charset UTF8 = Charset.forName(charsetName);
132
133 public static final String NEWLINE = "\n";
134 public static final String SYSTEM_NEWLINE = System.getProperty("line.separator");
135 public static final String SYSTEM_FILE_SEPARATOR = System.getProperty("file.separator");
136
137 /***
138 * The username for an anonymous user
139 */
140 public static final String ANONYMOUS_USER = "nobody";
141 /***
142 * When a client creates a file on the Styx server, this is the default
143 * group for the file. All users belong to this group.
144 */
145 public static final String DEFAULT_GROUP = "users";
146
147
148
149 private static SimpleDateFormat XSD_DATE_TIME_FORMAT
150 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
151
152 /***
153 * Converts a string to a byte array in UTF-8
154 */
155 public static byte[] strToUTF8(String str)
156 {
157 try
158 {
159
160 return str.getBytes(charsetName);
161 }
162 catch (UnsupportedEncodingException uee)
163 {
164
165 throw new InternalError("Fatal error: " + charsetName +
166 " is not supported on this platform!");
167 }
168 }
169
170 /***
171 * Converts an array of bytes in UTF-8 to a String
172 */
173 public static String utf8ToString(byte[] bytes)
174 {
175 return utf8ToString(bytes, 0, bytes.length);
176 }
177
178 /***
179 * Converts an array of bytes in UTF-8 to a String
180 * @param bytes The array of bytes to convert
181 * @param offset The index of the first byte in the array to convert
182 * @param length The number of bytes to convert
183 */
184 public static String utf8ToString(byte[] bytes, int offset, int length)
185 {
186 try
187 {
188 return new String(bytes, offset, length, charsetName);
189 }
190 catch (UnsupportedEncodingException uee)
191 {
192
193 throw new InternalError("Fatal error: " + charsetName +
194 " is not supported on this platform!");
195 }
196 }
197
198 /***
199 * Gets the remaining contents of the given ByteBuffer (i.e. the bytes
200 * between its position and limit) as a String. Leaves the position of the
201 * ByteBuffer unchanged.
202 */
203 public static String dataToString(ByteBuffer buf)
204 {
205
206
207 byte[] bytes;
208 synchronized (buf)
209 {
210
211 int pos = buf.position();
212 bytes = new byte[buf.remaining()];
213 buf.get(bytes);
214
215 buf.position(pos);
216 }
217 return utf8ToString(bytes);
218 }
219
220 /***
221 * Gets the remaining contents of the given java.nio.ByteBuffer (i.e. the bytes
222 * between its position and limit) as a String. Leaves the position of the
223 * ByteBuffer unchanged.
224 */
225 public static String dataToString(java.nio.ByteBuffer buf)
226 {
227
228
229 byte[] bytes;
230 if (buf.hasArray())
231 {
232 bytes = buf.array();
233 return utf8ToString(bytes, buf.position(), buf.remaining());
234 }
235 else
236 {
237 synchronized (buf)
238 {
239
240 int pos = buf.position();
241 bytes = new byte[buf.remaining()];
242 buf.get(bytes);
243
244 buf.position(pos);
245 }
246 return utf8ToString(bytes);
247 }
248 }
249
250 /***
251 * @return the first n bytes of the data in the given buffer as a String
252 * (in quotes), then the number of bytes remaining. Leaves the position of
253 * the ByteBuffer unchanged.
254 */
255 public static String getDataSummary(int n, ByteBuffer data)
256 {
257 byte[] bytes;
258 synchronized(data)
259 {
260 int numBytes = data.remaining() < n ? data.remaining() : n;
261 bytes = new byte[numBytes];
262 int pos = data.position();
263 data.get(bytes);
264
265 data.position(pos);
266 }
267 return getDataSummary(bytes.length, bytes);
268 }
269
270 /***
271 * @return the first n bytes of the data in the given byte array as a String
272 * (in quotes), then the number of bytes remaining.
273 */
274 public static String getDataSummary(int n, byte[] bytes)
275 {
276 StringBuffer s = new StringBuffer("\"");
277 int bytesToWrite = bytes.length < n ? bytes.length : n;
278 s.append(StyxUtils.utf8ToString(bytes, 0, bytesToWrite));
279 s.append("\"");
280 int moreBytes = bytes.length - bytesToWrite;
281 if (moreBytes > 0)
282 {
283 s.append(" (plus " + moreBytes + " more bytes)");
284 }
285 return s.toString();
286 }
287
288 /***
289 * @return the current time in seconds since the epoch (Jan 1 00:00 1970 GMT),
290 * suitable for use in stat messages
291 */
292 public static long now()
293 {
294
295 return System.currentTimeMillis() / 1000;
296 }
297
298 /***
299 * Returns a date formatted according to the xsd:dateTime data type
300 * @param date the date to format.
301 * @return the formatted date.
302 */
303 public static String formatAsXsdDateTime(Date date)
304 {
305
306 XSD_DATE_TIME_FORMAT.setTimeZone(TimeZone.getDefault());
307
308 StringBuffer buffer = new StringBuffer(XSD_DATE_TIME_FORMAT.format(date));
309
310 buffer.insert(buffer.length() - 2, ':');
311
312 return buffer.toString();
313 }
314
315 /***
316 * Parses a String that is formatted according to the xsd:dateTime data type
317 * and returns it as a Date
318 * @param date the String to format.
319 * @return the parse date.
320 */
321 public static Date parseXsdDateTime(String date) throws ParseException
322 {
323
324 String newDate = date.trim();
325 if (newDate.endsWith("Z"))
326 {
327
328 newDate = newDate.substring(0, newDate.length() - 1) + "+0000";
329 }
330 else
331 {
332
333 int colonPos = newDate.lastIndexOf(":");
334 newDate = newDate.substring(0, colonPos) +
335 newDate.substring(colonPos + 1, newDate.length());
336 }
337 return XSD_DATE_TIME_FORMAT.parse(newDate);
338 }
339
340 /***
341 * Simple test routine for the date parsing routines
342 */
343 public static void main(String[] args) throws Exception
344 {
345 Date now = java.util.Calendar.getInstance().getTime();
346 System.out.println(now.toString());
347 String xsdStr = formatAsXsdDateTime(now);
348 System.out.println(xsdStr);
349 System.out.println(parseXsdDateTime(xsdStr));
350 }
351
352 }