rename fcplib to jFCPlib
[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  * @version $Id$
36  */
37 public class FcpUtils {
38
39         /** Counter for unique identifiers. */
40         private static AtomicLong counter = new AtomicLong();
41
42         /**
43          * Returns a unique identifier.
44          * 
45          * @return A unique identifier
46          */
47         public static String getUniqueIdentifier() {
48                 return new StringBuilder().append(System.currentTimeMillis()).append('-').append(counter.getAndIncrement()).toString();
49         }
50
51         /**
52          * Parses an integer field, separated by ‘;’ and returns the parsed values.
53          * 
54          * @param field
55          *            The field to parse
56          * @return An array with the parsed values
57          * @throws NumberFormatException
58          *             if a value can not be converted to a number
59          */
60         public static int[] decodeMultiIntegerField(String field) throws NumberFormatException {
61                 StringTokenizer fieldTokens = new StringTokenizer(field, ";");
62                 int[] result = new int[fieldTokens.countTokens()];
63                 int counter = 0;
64                 while (fieldTokens.hasMoreTokens()) {
65                         String fieldToken = fieldTokens.nextToken();
66                         result[counter++] = Integer.valueOf(fieldToken);
67                 }
68                 return result;
69         }
70
71         /**
72          * Encodes the given integer array into a string, separating the values by
73          * ‘;’.
74          * 
75          * @param values
76          *            The values to encode
77          * @return The encoded values
78          */
79         public static String encodeMultiIntegerField(int[] values) {
80                 StringBuilder encodedField = new StringBuilder();
81                 for (int value: values) {
82                         if (encodedField.length() > 0) {
83                                 encodedField.append(';');
84                         }
85                         encodedField.append(value);
86                 }
87                 return encodedField.toString();
88         }
89
90         /**
91          * Encodes the given string array into a string, separating the values by
92          * ‘;’.
93          * 
94          * @param values
95          *            The values to encode
96          * @return The encoded values
97          */
98         public static String encodeMultiStringField(String[] values) {
99                 StringBuilder encodedField = new StringBuilder();
100                 for (String value: values) {
101                         if (encodedField.length() > 0) {
102                                 encodedField.append(';');
103                         }
104                         encodedField.append(value);
105                 }
106                 return encodedField.toString();
107         }
108
109         /**
110          * Tries to parse the given string into an int, returning <code>-1</code>
111          * if the string can not be parsed.
112          * 
113          * @param value
114          *            The string to parse
115          * @return The parsed int, or <code>-1</code>
116          */
117         public static int safeParseInt(String value) {
118                 return safeParseInt(value, -1);
119         }
120
121         /**
122          * Tries to parse the given string into an int, returning
123          * <code>defaultValue</code> if the string can not be parsed.
124          * 
125          * @param value
126          *            The string to parse
127          * @param defaultValue
128          *            The value to return if the string can not be parsed.
129          * @return The parsed int, or <code>defaultValue</code>
130          */
131         public static int safeParseInt(String value, int defaultValue) {
132                 try {
133                         return Integer.valueOf(value);
134                 } catch (NumberFormatException nfe1) {
135                         return defaultValue;
136                 }
137         }
138
139         /**
140          * Tries to parse the given string into an long, returning <code>-1</code>
141          * if the string can not be parsed.
142          * 
143          * @param value
144          *            The string to parse
145          * @return The parsed long, or <code>-1</code>
146          */
147         public static long safeParseLong(String value) {
148                 return safeParseLong(value, -1);
149         }
150
151         /**
152          * Tries to parse the given string into an long, returning
153          * <code>defaultValue</code> if the string can not be parsed.
154          * 
155          * @param value
156          *            The string to parse
157          * @param defaultValue
158          *            The value to return if the string can not be parsed.
159          * @return The parsed long, or <code>defaultValue</code>
160          */
161         public static long safeParseLong(String value, long defaultValue) {
162                 try {
163                         return Integer.valueOf(value);
164                 } catch (NumberFormatException nfe1) {
165                         return defaultValue;
166                 }
167         }
168
169         /**
170          * Closes the given socket.
171          * 
172          * @param socket
173          *            The socket to close
174          */
175         public static void close(Socket socket) {
176                 if (socket != null) {
177                         try {
178                                 socket.close();
179                         } catch (IOException ioe1) {
180                                 /* ignore. */
181                         }
182                 }
183         }
184
185         /**
186          * Closes the given Closeable.
187          * 
188          * @param closeable
189          *            The Closeable to close
190          */
191         public static void close(Closeable closeable) {
192                 if (closeable != null) {
193                         try {
194                                 closeable.close();
195                         } catch (IOException ioe1) {
196                                 /* ignore. */
197                         }
198                 }
199         }
200
201         /**
202          * Copies as many bytes as possible (i.e. until {@link InputStream#read()}
203          * returns <code>-1</code>) from the source input stream to the
204          * destination output stream.
205          * 
206          * @param source
207          *            The input stream to read from
208          * @param destination
209          *            The output stream to write to
210          * @throws IOException
211          *             if an I/O error occurs
212          */
213         public static void copy(InputStream source, OutputStream destination) throws IOException {
214                 copy(source, destination, -1);
215         }
216
217         /**
218          * Copies <code>length</code> bytes from the source input stream to the
219          * destination output stream. If <code>length</code> is <code>-1</code>
220          * as much bytes as possible will be copied (i.e. until
221          * {@link InputStream#read()} returns <code>-1</code> to signal the end of
222          * the stream).
223          * 
224          * @param source
225          *            The input stream to read from
226          * @param destination
227          *            The output stream to write to
228          * @param length
229          *            The number of bytes to copy
230          * @throws IOException
231          *             if an I/O error occurs
232          */
233         public static void copy(InputStream source, OutputStream destination, long length) throws IOException {
234                 copy(source, destination, length, 1 << 16);
235         }
236
237         /**
238          * Copies <code>length</code> bytes from the source input stream to the
239          * destination output stream. If <code>length</code> is <code>-1</code>
240          * as much bytes as possible will be copied (i.e. until
241          * {@link InputStream#read()} returns <code>-1</code> to signal the end of
242          * the stream).
243          * 
244          * @param source
245          *            The input stream to read from
246          * @param destination
247          *            The output stream to write to
248          * @param length
249          *            The number of bytes to copy
250          * @param bufferSize
251          *            The buffer size
252          * @throws IOException
253          *             if an I/O error occurs
254          */
255         public static void copy(InputStream source, OutputStream destination, long length, int bufferSize) throws IOException {
256                 long remaining = length;
257                 byte[] buffer = new byte[bufferSize];
258                 int read = 0;
259                 while ((remaining == -1) || (remaining > 0)) {
260                         read = source.read(buffer, 0, ((remaining > bufferSize) || (remaining == -1)) ? bufferSize : (int) remaining);
261                         if (read == -1) {
262                                 if (length == -1) {
263                                         return;
264                                 }
265                                 throw new EOFException("stream reached eof");
266                         }
267                         destination.write(buffer, 0, read);
268                         remaining -= read;
269                 }
270         }
271
272 }