remove $Id$ keyword
[jFCPlib.git] / src / net / pterodactylus / fcp / FcpUtils.java
1 /*
2  * jSite2 - FcpUtils.java -
3  * Copyright © 2008 David Roden
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 package net.pterodactylus.fcp;
21
22 import java.io.Closeable;
23 import java.io.EOFException;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.net.Socket;
28 import java.util.StringTokenizer;
29 import java.util.concurrent.atomic.AtomicLong;
30
31 /**
32  * Helper class with utility methods for the FCP protocol.
33  * 
34  * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
35  */
36 public class FcpUtils {
37
38         /** Counter for unique identifiers. */
39         private static AtomicLong counter = new AtomicLong();
40
41         /**
42          * Returns a unique identifier.
43          * 
44          * @return A unique identifier
45          */
46         public static String getUniqueIdentifier() {
47                 return new StringBuilder().append(System.currentTimeMillis()).append('-').append(counter.getAndIncrement()).toString();
48         }
49
50         /**
51          * Parses an integer field, separated by ‘;’ and returns the parsed values.
52          * 
53          * @param field
54          *            The field to parse
55          * @return An array with the parsed values
56          * @throws NumberFormatException
57          *             if a value can not be converted to a number
58          */
59         public static int[] decodeMultiIntegerField(String field) throws NumberFormatException {
60                 StringTokenizer fieldTokens = new StringTokenizer(field, ";");
61                 int[] result = new int[fieldTokens.countTokens()];
62                 int counter = 0;
63                 while (fieldTokens.hasMoreTokens()) {
64                         String fieldToken = fieldTokens.nextToken();
65                         result[counter++] = Integer.valueOf(fieldToken);
66                 }
67                 return result;
68         }
69
70         /**
71          * Encodes the given integer array into a string, separating the values by
72          * ‘;’.
73          * 
74          * @param values
75          *            The values to encode
76          * @return The encoded values
77          */
78         public static String encodeMultiIntegerField(int[] values) {
79                 StringBuilder encodedField = new StringBuilder();
80                 for (int value: values) {
81                         if (encodedField.length() > 0) {
82                                 encodedField.append(';');
83                         }
84                         encodedField.append(value);
85                 }
86                 return encodedField.toString();
87         }
88
89         /**
90          * Encodes the given string array into a string, separating the values by
91          * ‘;’.
92          * 
93          * @param values
94          *            The values to encode
95          * @return The encoded values
96          */
97         public static String encodeMultiStringField(String[] values) {
98                 StringBuilder encodedField = new StringBuilder();
99                 for (String value: values) {
100                         if (encodedField.length() > 0) {
101                                 encodedField.append(';');
102                         }
103                         encodedField.append(value);
104                 }
105                 return encodedField.toString();
106         }
107
108         /**
109          * Tries to parse the given string into an int, returning <code>-1</code>
110          * if the string can not be parsed.
111          * 
112          * @param value
113          *            The string to parse
114          * @return The parsed int, or <code>-1</code>
115          */
116         public static int safeParseInt(String value) {
117                 return safeParseInt(value, -1);
118         }
119
120         /**
121          * Tries to parse the given string into an int, returning
122          * <code>defaultValue</code> if the string can not be parsed.
123          * 
124          * @param value
125          *            The string to parse
126          * @param defaultValue
127          *            The value to return if the string can not be parsed.
128          * @return The parsed int, or <code>defaultValue</code>
129          */
130         public static int safeParseInt(String value, int defaultValue) {
131                 try {
132                         return Integer.valueOf(value);
133                 } catch (NumberFormatException nfe1) {
134                         return defaultValue;
135                 }
136         }
137
138         /**
139          * Tries to parse the given string into an long, returning <code>-1</code>
140          * if the string can not be parsed.
141          * 
142          * @param value
143          *            The string to parse
144          * @return The parsed long, or <code>-1</code>
145          */
146         public static long safeParseLong(String value) {
147                 return safeParseLong(value, -1);
148         }
149
150         /**
151          * Tries to parse the given string into an long, returning
152          * <code>defaultValue</code> if the string can not be parsed.
153          * 
154          * @param value
155          *            The string to parse
156          * @param defaultValue
157          *            The value to return if the string can not be parsed.
158          * @return The parsed long, or <code>defaultValue</code>
159          */
160         public static long safeParseLong(String value, long defaultValue) {
161                 try {
162                         return Integer.valueOf(value);
163                 } catch (NumberFormatException nfe1) {
164                         return defaultValue;
165                 }
166         }
167
168         /**
169          * Closes the given socket.
170          * 
171          * @param socket
172          *            The socket to close
173          */
174         public static void close(Socket socket) {
175                 if (socket != null) {
176                         try {
177                                 socket.close();
178                         } catch (IOException ioe1) {
179                                 /* ignore. */
180                         }
181                 }
182         }
183
184         /**
185          * Closes the given Closeable.
186          * 
187          * @param closeable
188          *            The Closeable to close
189          */
190         public static void close(Closeable closeable) {
191                 if (closeable != null) {
192                         try {
193                                 closeable.close();
194                         } catch (IOException ioe1) {
195                                 /* ignore. */
196                         }
197                 }
198         }
199
200         /**
201          * Copies as many bytes as possible (i.e. until {@link InputStream#read()}
202          * returns <code>-1</code>) from the source input stream to the
203          * destination output stream.
204          * 
205          * @param source
206          *            The input stream to read from
207          * @param destination
208          *            The output stream to write to
209          * @throws IOException
210          *             if an I/O error occurs
211          */
212         public static void copy(InputStream source, OutputStream destination) throws IOException {
213                 copy(source, destination, -1);
214         }
215
216         /**
217          * Copies <code>length</code> bytes from the source input stream to the
218          * destination output stream. If <code>length</code> is <code>-1</code>
219          * as much bytes as possible will be copied (i.e. until
220          * {@link InputStream#read()} returns <code>-1</code> to signal the end of
221          * the stream).
222          * 
223          * @param source
224          *            The input stream to read from
225          * @param destination
226          *            The output stream to write to
227          * @param length
228          *            The number of bytes to copy
229          * @throws IOException
230          *             if an I/O error occurs
231          */
232         public static void copy(InputStream source, OutputStream destination, long length) throws IOException {
233                 copy(source, destination, length, 1 << 16);
234         }
235
236         /**
237          * Copies <code>length</code> bytes from the source input stream to the
238          * destination output stream. If <code>length</code> is <code>-1</code>
239          * as much bytes as possible will be copied (i.e. until
240          * {@link InputStream#read()} returns <code>-1</code> to signal the end of
241          * the stream).
242          * 
243          * @param source
244          *            The input stream to read from
245          * @param destination
246          *            The output stream to write to
247          * @param length
248          *            The number of bytes to copy
249          * @param bufferSize
250          *            The buffer size
251          * @throws IOException
252          *             if an I/O error occurs
253          */
254         public static void copy(InputStream source, OutputStream destination, long length, int bufferSize) throws IOException {
255                 long remaining = length;
256                 byte[] buffer = new byte[bufferSize];
257                 int read = 0;
258                 while ((remaining == -1) || (remaining > 0)) {
259                         read = source.read(buffer, 0, ((remaining > bufferSize) || (remaining == -1)) ? bufferSize : (int) remaining);
260                         if (read == -1) {
261                                 if (length == -1) {
262                                         return;
263                                 }
264                                 throw new EOFException("stream reached eof");
265                         }
266                         destination.write(buffer, 0, read);
267                         remaining -= read;
268                 }
269         }
270
271 }