diff --git a/src/main/java/org/jboss/netty/example/localtime/LocalTimeClient.java b/src/main/java/org/jboss/netty/example/localtime/LocalTimeClient.java index 993473739e..2d185fa4c5 100644 --- a/src/main/java/org/jboss/netty/example/localtime/LocalTimeClient.java +++ b/src/main/java/org/jboss/netty/example/localtime/LocalTimeClient.java @@ -15,17 +15,18 @@ */ package org.jboss.netty.example.localtime; +import org.jboss.netty.bootstrap.ClientBootstrap; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; + import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.concurrent.Executors; - -import org.jboss.netty.bootstrap.ClientBootstrap; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelFuture; -import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +import java.util.regex.Pattern; /** * Sends a list of continent/city pairs to a {@link LocalTimeServer} to @@ -108,10 +109,12 @@ public class LocalTimeClient { " localhost 8080 America/New_York Asia/Seoul"); } + private static final Pattern CITY_PATTERN = Pattern.compile("^[_A-Za-z]+/[_A-Za-z]+$"); + private static List parseCities(String[] args, int offset) { List cities = new ArrayList(); for (int i = offset; i < args.length; i ++) { - if (!args[i].matches("^[_A-Za-z]+/[_A-Za-z]+$")) { + if (!CITY_PATTERN.matcher(args[i]).matches()) { System.err.println("Syntax error: '" + args[i] + "'"); printUsage(); return null; diff --git a/src/main/java/org/jboss/netty/example/localtime/LocalTimeClientHandler.java b/src/main/java/org/jboss/netty/example/localtime/LocalTimeClientHandler.java index 520c23b983..d230ec142e 100644 --- a/src/main/java/org/jboss/netty/example/localtime/LocalTimeClientHandler.java +++ b/src/main/java/org/jboss/netty/example/localtime/LocalTimeClientHandler.java @@ -15,15 +15,6 @@ */ package org.jboss.netty.example.localtime; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Formatter; -import java.util.List; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.logging.Level; -import java.util.logging.Logger; - import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelEvent; import org.jboss.netty.channel.ChannelHandlerContext; @@ -37,11 +28,23 @@ import org.jboss.netty.example.localtime.LocalTimeProtocol.LocalTimes; import org.jboss.netty.example.localtime.LocalTimeProtocol.Location; import org.jboss.netty.example.localtime.LocalTimeProtocol.Locations; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Formatter; +import java.util.List; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.regex.Pattern; + public class LocalTimeClientHandler extends SimpleChannelUpstreamHandler { private static final Logger logger = Logger.getLogger( LocalTimeClientHandler.class.getName()); + private static final Pattern DELIM = Pattern.compile("/"); + // Stateful properties private volatile Channel channel; private final BlockingQueue answer = new LinkedBlockingQueue(); @@ -50,7 +53,7 @@ public class LocalTimeClientHandler extends SimpleChannelUpstreamHandler { Locations.Builder builder = Locations.newBuilder(); for (String c: cities) { - String[] components = c.split("/"); + String[] components = DELIM.split(c); builder.addLocation(Location.newBuilder(). setContinent(Continent.valueOf(components[0].toUpperCase())). setCity(components[1]).build()); diff --git a/src/main/java/org/jboss/netty/handler/codec/http/CookieDecoder.java b/src/main/java/org/jboss/netty/handler/codec/http/CookieDecoder.java index fa3da0807c..0cd8d95cf7 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/CookieDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/CookieDecoder.java @@ -15,6 +15,8 @@ */ package org.jboss.netty.handler.codec.http; +import org.jboss.netty.util.internal.StringUtil; + import java.text.ParseException; import java.util.ArrayList; import java.util.Collections; @@ -39,7 +41,7 @@ import java.util.TreeSet; */ public class CookieDecoder { - private static final String COMMA = ","; + private static final char COMMA = ','; /** * Creates a new decoder. @@ -146,7 +148,7 @@ public class CookieDecoder { } else if (CookieHeaderNames.VERSION.equalsIgnoreCase(name)) { version = Integer.parseInt(value); } else if (CookieHeaderNames.PORT.equalsIgnoreCase(name)) { - String[] portList = value.split(COMMA); + String[] portList = StringUtil.split(value, COMMA); for (String s1: portList) { try { ports.add(Integer.valueOf(s1)); diff --git a/src/main/java/org/jboss/netty/handler/codec/http/HttpContentCompressor.java b/src/main/java/org/jboss/netty/handler/codec/http/HttpContentCompressor.java index bd96d6082d..9e5c2e38c5 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/HttpContentCompressor.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/HttpContentCompressor.java @@ -21,6 +21,7 @@ import org.jboss.netty.handler.codec.compression.ZlibEncoder; import org.jboss.netty.handler.codec.compression.ZlibWrapper; import org.jboss.netty.handler.codec.embedder.EncoderEmbedder; import org.jboss.netty.util.internal.DetectionUtil; +import org.jboss.netty.util.internal.StringUtil; /** * Compresses an {@link HttpMessage} and an {@link HttpChunk} in {@code gzip} or @@ -138,7 +139,7 @@ public class HttpContentCompressor extends HttpContentEncoder { float starQ = -1.0f; float gzipQ = -1.0f; float deflateQ = -1.0f; - for (String encoding : acceptEncoding.split(",")) { + for (String encoding: StringUtil.split(acceptEncoding, ',')) { float q = 1.0f; int equalsPos = encoding.indexOf('='); if (equalsPos != -1) { diff --git a/src/main/java/org/jboss/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java b/src/main/java/org/jboss/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java index fe1ab972db..52e24f3d77 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/multipart/HttpPostRequestDecoder.java @@ -26,6 +26,7 @@ import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadNo import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.SeekAheadOptimize; import org.jboss.netty.handler.codec.http.multipart.HttpPostBodyUtil.TransferEncodingMechanism; import org.jboss.netty.util.internal.CaseIgnoringComparator; +import org.jboss.netty.util.internal.StringUtil; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -966,7 +967,7 @@ public class HttpPostRequestDecoder { if (checkSecondArg) { // read next values and store them in the map as Attribute for (int i = 2; i < contents.length; i ++) { - String[] values = contents[i].split("="); + String[] values = StringUtil.split(contents[i], '='); Attribute attribute; try { attribute = factory.createAttribute(request, values[0].trim(), @@ -1012,7 +1013,7 @@ public class HttpPostRequestDecoder { // Take care of possible "multipart/mixed" if (contents[1].equalsIgnoreCase(HttpPostBodyUtil.MULTIPART_MIXED)) { if (currentStatus == MultiPartStatus.DISPOSITION) { - String[] values = contents[2].split("="); + String[] values = StringUtil.split(contents[2], '='); multipartMixedBoundary = "--" + values[1]; currentStatus = MultiPartStatus.MIXEDDELIMITER; return decodeMultipart(MultiPartStatus.MIXEDDELIMITER); @@ -1024,7 +1025,7 @@ public class HttpPostRequestDecoder { for (int i = 1; i < contents.length; i ++) { if (contents[i].toLowerCase().startsWith( HttpHeaders.Values.CHARSET)) { - String[] values = contents[i].split("="); + String[] values = StringUtil.split(contents[i], '='); Attribute attribute; try { attribute = factory.createAttribute(request, @@ -1995,10 +1996,10 @@ public class HttpPostRequestDecoder { headers.add(sb.substring(nameStart, nameEnd)); String svalue = sb.substring(valueStart, valueEnd); String[] values = null; - if (svalue.indexOf(";") >= 0) { - values = svalue.split(";"); + if (svalue.indexOf(';') >= 0) { + values = StringUtil.split(svalue, ';'); } else { - values = svalue.split(","); + values = StringUtil.split(svalue, ','); } for (String value: values) { headers.add(value.trim()); diff --git a/src/main/java/org/jboss/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java b/src/main/java/org/jboss/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java index 5a4d8f447a..ffaf944182 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/websocketx/WebSocketServerHandshaker.java @@ -15,15 +15,16 @@ */ package org.jboss.netty.handler.codec.http.websocketx; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; - import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.channel.Channels; import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.util.internal.StringUtil; + +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.Set; /** * Base class for server side web socket opening and closing handshakes @@ -90,7 +91,7 @@ public abstract class WebSocketServerHandshaker { this.version = version; this.webSocketUrl = webSocketUrl; if (subprotocols != null) { - String[] subprotocolArray = subprotocols.split(","); + String[] subprotocolArray = StringUtil.split(subprotocols, ','); for (int i = 0; i < subprotocolArray.length; i++) { subprotocolArray[i] = subprotocolArray[i].trim(); } @@ -163,7 +164,7 @@ public abstract class WebSocketServerHandshaker { return null; } - String[] requestedSubprotocolArray = requestedSubprotocols.split(","); + String[] requestedSubprotocolArray = StringUtil.split(requestedSubprotocols, ','); for (String p : requestedSubprotocolArray) { String requestedSubprotocol = p.trim(); diff --git a/src/main/java/org/jboss/netty/handler/ipfilter/IpFilterRuleList.java b/src/main/java/org/jboss/netty/handler/ipfilter/IpFilterRuleList.java index 82eae013d6..603397abbb 100644 --- a/src/main/java/org/jboss/netty/handler/ipfilter/IpFilterRuleList.java +++ b/src/main/java/org/jboss/netty/handler/ipfilter/IpFilterRuleList.java @@ -15,11 +15,12 @@ */ package org.jboss.netty.handler.ipfilter; -import java.net.UnknownHostException; -import java.util.ArrayList; - import org.jboss.netty.logging.InternalLogger; import org.jboss.netty.logging.InternalLoggerFactory; +import org.jboss.netty.util.internal.StringUtil; + +import java.net.UnknownHostException; +import java.util.ArrayList; /** * The Class IpFilterRuleList is a helper class to generate a List of Rules from a string. @@ -58,7 +59,7 @@ public class IpFilterRuleList extends ArrayList { } private void parseRules(String rules) { - String[] ruless = rules.split(","); + String[] ruless = StringUtil.split(rules, ','); for (String rule : ruless) { parseRule(rule.trim()); } diff --git a/src/main/java/org/jboss/netty/handler/ipfilter/PatternRule.java b/src/main/java/org/jboss/netty/handler/ipfilter/PatternRule.java index 96853952ad..a7d153ae3a 100644 --- a/src/main/java/org/jboss/netty/handler/ipfilter/PatternRule.java +++ b/src/main/java/org/jboss/netty/handler/ipfilter/PatternRule.java @@ -16,13 +16,14 @@ package org.jboss.netty.handler.ipfilter; +import org.jboss.netty.logging.InternalLogger; +import org.jboss.netty.logging.InternalLoggerFactory; +import org.jboss.netty.util.internal.StringUtil; + import java.net.InetAddress; import java.net.UnknownHostException; import java.util.regex.Pattern; -import org.jboss.netty.logging.InternalLogger; -import org.jboss.netty.logging.InternalLoggerFactory; - /** * The Class PatternRule represents an IP filter rule using string patterns. *
@@ -113,7 +114,7 @@ public class PatternRule implements IpFilterRule, Comparable { return; } - String[] acls = pattern.split(","); + String[] acls = StringUtil.split(pattern, ','); String ip = ""; String name = ""; diff --git a/src/main/java/org/jboss/netty/util/internal/ConversionUtil.java b/src/main/java/org/jboss/netty/util/internal/ConversionUtil.java index 73c9e48062..0753e260be 100644 --- a/src/main/java/org/jboss/netty/util/internal/ConversionUtil.java +++ b/src/main/java/org/jboss/netty/util/internal/ConversionUtil.java @@ -17,6 +17,7 @@ package org.jboss.netty.util.internal; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; /** * Conversion utility class to parse a property represented as a string or @@ -64,6 +65,8 @@ public final class ConversionUtil { } } + private static final Pattern ARRAY_DELIM = Pattern.compile("[, \\t\\n\\r\\f\\e\\a]"); + /** * Converts the specified object into an array of strings. */ @@ -84,7 +87,7 @@ public final class ConversionUtil { return answer.toArray(new String[answer.size()]); } - return String.valueOf(value).split("[, \\t\\n\\r\\f\\e\\a]"); + return ARRAY_DELIM.split(String.valueOf(value)); } private static final String[] INTEGERS = { diff --git a/src/main/java/org/jboss/netty/util/internal/StringUtil.java b/src/main/java/org/jboss/netty/util/internal/StringUtil.java index 62605699ae..ef806d8fab 100644 --- a/src/main/java/org/jboss/netty/util/internal/StringUtil.java +++ b/src/main/java/org/jboss/netty/util/internal/StringUtil.java @@ -15,7 +15,9 @@ */ package org.jboss.netty.util.internal; +import java.util.ArrayList; import java.util.Formatter; +import java.util.List; /** * String utility class. @@ -114,4 +116,47 @@ public final class StringUtil { return buf.toString(); } + + private static final String EMPTY_STRING = ""; + + /** + * Splits the specified {@link String} with the specified delimiter. This operation is a simplified and optimized + * version of {@link String#split(String)}. + */ + public static String[] split(String value, char delim) { + final int end = value.length(); + final List res = new ArrayList(); + + int start = 0; + for (int i = 0; i < end; i ++) { + if (value.charAt(i) == delim) { + if (start == i) { + res.add(EMPTY_STRING); + } else { + res.add(value.substring(start, i)); + } + start = i + 1; + } + } + + if (start == 0) { // If no delimiter was found in the value + res.add(value); + } else { + if (start != end) { + // Add the last element if it's not empty. + res.add(value.substring(start, end)); + } else { + // Truncate trailing empty elements. + for (int i = res.size() - 1; i >= 0; i --) { + if (res.get(i).length() == 0) { + res.remove(i); + } else { + break; + } + } + } + } + + return res.toArray(new String[res.size()]); + } } diff --git a/src/main/java/org/jboss/netty/util/internal/SystemPropertyUtil.java b/src/main/java/org/jboss/netty/util/internal/SystemPropertyUtil.java index 484e5925f6..2f95aa4d14 100644 --- a/src/main/java/org/jboss/netty/util/internal/SystemPropertyUtil.java +++ b/src/main/java/org/jboss/netty/util/internal/SystemPropertyUtil.java @@ -20,6 +20,7 @@ import org.jboss.netty.logging.InternalLoggerFactory; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.regex.Pattern; /** * A collection of utility methods to retrieve and parse the values of the Java system properties. @@ -122,6 +123,8 @@ public final class SystemPropertyUtil { return def; } + private static final Pattern INTEGER_PATTERN = Pattern.compile("-?[0-9]+"); + /** * Returns the value of the Java system property with the specified * {@code key}, while falling back to the specified default value if @@ -138,7 +141,7 @@ public final class SystemPropertyUtil { } value = value.trim().toLowerCase(); - if (value.matches("-?[0-9]+")) { + if (INTEGER_PATTERN.matcher(value).matches()) { try { return Integer.parseInt(value); } catch (Exception e) { @@ -169,7 +172,7 @@ public final class SystemPropertyUtil { } value = value.trim().toLowerCase(); - if (value.matches("-?[0-9]+")) { + if (INTEGER_PATTERN.matcher(value).matches()) { try { return Long.parseLong(value); } catch (Exception e) { diff --git a/src/test/java/org/jboss/netty/util/internal/StringUtilTest.java b/src/test/java/org/jboss/netty/util/internal/StringUtilTest.java index fe6a57b9d8..c760d7c9e5 100644 --- a/src/test/java/org/jboss/netty/util/internal/StringUtilTest.java +++ b/src/test/java/org/jboss/netty/util/internal/StringUtilTest.java @@ -79,4 +79,29 @@ public class StringUtilTest { final String stripped = StringUtil.stripControlCharacters(string); assertEquals("The string should be unchanged", string, stripped); } + + @Test + public void splitSimple() { + assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo:bar", ':')); + } + + @Test + public void splitWithTrailingDelimiter() { + assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo,bar,", ',')); + } + + @Test + public void splitWithTrailingDelimiters() { + assertArrayEquals(new String[] { "foo", "bar" }, StringUtil.split("foo!bar!!", '!')); + } + + @Test + public void splitWithConsecutiveDelimiters() { + assertArrayEquals(new String[] { "foo", "", "bar" }, StringUtil.split("foo$$bar", '$')); + } + + @Test + public void splitWithDelimiterAtBeginning() { + assertArrayEquals(new String[] { "", "foo", "bar" }, StringUtil.split("#foo#bar", '#')); + } }