2 * jSite2 - FcpUtils.java -
3 * Copyright © 2008 David Roden
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.
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.
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.
20 package net.pterodactylus.fcp;
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;
32 * Helper class with utility methods for the FCP protocol.
34 * @author <a href="mailto:dr@ina-germany.de">David Roden</a>
37 public class FcpUtils {
39 /** Counter for unique identifiers. */
40 private static AtomicLong counter = new AtomicLong();
43 * Returns a unique identifier.
45 * @return A unique identifier
47 public static String getUniqueIdentifier() {
48 return new StringBuilder().append(System.currentTimeMillis()).append('-').append(counter.getAndIncrement()).toString();
52 * Parses an integer field, separated by ‘;’ and returns the parsed values.
56 * @return An array with the parsed values
57 * @throws NumberFormatException
58 * if a value can not be converted to a number
60 public static int[] decodeMultiIntegerField(String field) throws NumberFormatException {
61 StringTokenizer fieldTokens = new StringTokenizer(field, ";");
62 int[] result = new int[fieldTokens.countTokens()];
64 while (fieldTokens.hasMoreTokens()) {
65 String fieldToken = fieldTokens.nextToken();
66 result[counter++] = Integer.valueOf(fieldToken);
72 * Encodes the given integer array into a string, separating the values by
76 * The values to encode
77 * @return The encoded values
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(';');
85 encodedField.append(value);
87 return encodedField.toString();
91 * Encodes the given string array into a string, separating the values by
95 * The values to encode
96 * @return The encoded values
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(';');
104 encodedField.append(value);
106 return encodedField.toString();
110 * Tries to parse the given string into an int, returning <code>-1</code>
111 * if the string can not be parsed.
114 * The string to parse
115 * @return The parsed int, or <code>-1</code>
117 public static int safeParseInt(String value) {
118 return safeParseInt(value, -1);
122 * Tries to parse the given string into an int, returning
123 * <code>defaultValue</code> if the string can not be parsed.
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>
131 public static int safeParseInt(String value, int defaultValue) {
133 return Integer.valueOf(value);
134 } catch (NumberFormatException nfe1) {
140 * Tries to parse the given string into an long, returning <code>-1</code>
141 * if the string can not be parsed.
144 * The string to parse
145 * @return The parsed long, or <code>-1</code>
147 public static long safeParseLong(String value) {
148 return safeParseLong(value, -1);
152 * Tries to parse the given string into an long, returning
153 * <code>defaultValue</code> if the string can not be parsed.
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>
161 public static long safeParseLong(String value, long defaultValue) {
163 return Integer.valueOf(value);
164 } catch (NumberFormatException nfe1) {
170 * Closes the given socket.
173 * The socket to close
175 public static void close(Socket socket) {
176 if (socket != null) {
179 } catch (IOException ioe1) {
186 * Closes the given Closeable.
189 * The Closeable to close
191 public static void close(Closeable closeable) {
192 if (closeable != null) {
195 } catch (IOException ioe1) {
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.
207 * The input stream to read from
209 * The output stream to write to
210 * @throws IOException
211 * if an I/O error occurs
213 public static void copy(InputStream source, OutputStream destination) throws IOException {
214 copy(source, destination, -1);
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
225 * The input stream to read from
227 * The output stream to write to
229 * The number of bytes to copy
230 * @throws IOException
231 * if an I/O error occurs
233 public static void copy(InputStream source, OutputStream destination, long length) throws IOException {
234 copy(source, destination, length, 1 << 16);
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
245 * The input stream to read from
247 * The output stream to write to
249 * The number of bytes to copy
252 * @throws IOException
253 * if an I/O error occurs
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];
259 while ((remaining == -1) || (remaining > 0)) {
260 read = source.read(buffer, 0, ((remaining > bufferSize) || (remaining == -1)) ? bufferSize : (int) remaining);
265 throw new EOFException("stream reached eof");
267 destination.write(buffer, 0, read);