From 22094368c2865dcfb6daf8366425212b721a4657 Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Thu, 05 Feb 2009 17:42:14 +0000
Subject: [PATCH] Merge ASN1 branch to trunk
---
opends/src/server/org/opends/server/util/StaticUtils.java | 512 ++++++++++++++++++++++++++++++++++++++------------------
1 files changed, 342 insertions(+), 170 deletions(-)
diff --git a/opends/src/server/org/opends/server/util/StaticUtils.java b/opends/src/server/org/opends/server/util/StaticUtils.java
index ce001b2..c14119b 100644
--- a/opends/src/server/org/opends/server/util/StaticUtils.java
+++ b/opends/src/server/org/opends/server/util/StaticUtils.java
@@ -22,52 +22,56 @@
* CDDL HEADER END
*
*
- * Copyright 2006-2008 Sun Microsystems, Inc.
+ * Copyright 2006-2009 Sun Microsystems, Inc.
*/
package org.opends.server.util;
+import static org.opends.messages.CoreMessages.*;
import static org.opends.messages.UtilityMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.ServerConstants.*;
-import org.opends.server.util.args.ArgumentException;
-import org.opends.server.util.args.Argument;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.RandomAccess;
import java.util.StringTokenizer;
-import java.util.Date;
import java.util.TimeZone;
-import java.util.Collection;
-import java.util.Iterator;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import org.opends.messages.MessageDescriptor;
import org.opends.messages.ToolMessages;
+import org.opends.server.api.ClientConnection;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeBuilder;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
+import org.opends.server.types.ByteSequence;
import org.opends.server.types.DN;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DirectoryException;
@@ -76,7 +80,8 @@
import org.opends.server.types.ObjectClass;
import org.opends.server.types.RDN;
import org.opends.server.types.ResultCode;
-import static org.opends.messages.CoreMessages.*;
+import org.opends.server.util.args.Argument;
+import org.opends.server.util.args.ArgumentException;
/**
@@ -1398,6 +1403,48 @@
/**
+ * Compare two byte arrays for order. Returns a negative integer,
+ * zero, or a positive integer as the first argument is less than,
+ * equal to, or greater than the second.
+ *
+ * @param a
+ * The first byte array to be compared.
+ * @param a2
+ * The second byte array to be compared.
+ * @return Returns a negative integer, zero, or a positive integer
+ * if the first byte array is less than, equal to, or greater
+ * than the second.
+ */
+ public static int compare(ByteSequence a, ByteSequence a2) {
+ if (a == a2) {
+ return 0;
+ }
+
+ if (a == null) {
+ return -1;
+ }
+
+ if (a2 == null) {
+ return 1;
+ }
+
+ int minLength = Math.min(a.length(), a2.length());
+ for (int i = 0; i < minLength; i++) {
+ if (a.byteAt(i) != a2.byteAt(i)) {
+ if (a.byteAt(i) < a2.byteAt(i)) {
+ return -1;
+ } else if (a.byteAt(i) > a2.byteAt(i)) {
+ return 1;
+ }
+ }
+ }
+
+ return (a.length() - a2.length());
+ }
+
+
+
+ /**
* Indicates whether the two array lists are equal. They will be
* considered equal if they have the same number of elements, and
* the corresponding elements between them are equal (in the same
@@ -2203,10 +2250,10 @@
* @return <CODE>true</CODE> if the value needs to be base64-encoded if it is
* represented in LDIF form, or <CODE>false</CODE> if not.
*/
- public static boolean needsBase64Encoding(byte[] valueBytes)
+ public static boolean needsBase64Encoding(ByteSequence valueBytes)
{
int length;
- if ((valueBytes == null) || ((length = valueBytes.length) == 0))
+ if ((valueBytes == null) || ((length = valueBytes.length()) == 0))
{
return false;
}
@@ -2214,7 +2261,7 @@
// If the value starts with a space, colon, or less than, then it needs to
// be base64-encoded.
- switch (valueBytes[0])
+ switch (valueBytes.byteAt(0))
{
case 0x20: // Space
case 0x3A: // Colon
@@ -2224,7 +2271,7 @@
// If the value ends with a space, then it needs to be base64-encoded.
- if ((length > 1) && (valueBytes[length-1] == 0x20))
+ if ((length > 1) && (valueBytes.byteAt(length-1) == 0x20))
{
return true;
}
@@ -2232,8 +2279,10 @@
// If the value contains a null, newline, or return character, then it needs
// to be base64-encoded.
- for (byte b : valueBytes)
+ byte b;
+ for (int i = 0; i < valueBytes.length(); i++)
{
+ b = valueBytes.byteAt(i);
if ((b > 127) || (b < 0))
{
return true;
@@ -2825,35 +2874,27 @@
* @param trim Indicates whether leading and trailing spaces should be
* omitted from the string representation.
*/
- public static void toLowerCase(byte[] b, StringBuilder buffer, boolean trim)
+ public static void toLowerCase(ByteSequence b, StringBuilder buffer,
+ boolean trim)
{
if (b == null)
{
return;
}
- int length = b.length;
+ int origBufferLen = buffer.length();
+ int length = b.length();
for (int i=0; i < length; i++)
{
- if ((b[i] & 0x7F) != b[i])
+ if ((b.byteAt(i) & 0x7F) != b.byteAt(i))
{
- try
- {
- buffer.append(new String(b, i, (length-i), "UTF-8").toLowerCase());
- }
- catch (Exception e)
- {
- if (debugEnabled())
- {
- TRACER.debugCaught(DebugLogLevel.ERROR, e);
- }
- buffer.append(new String(b, i, (length - i)).toLowerCase());
- }
+ buffer.replace(origBufferLen, buffer.length(),
+ b.toString().toLowerCase());
break;
}
int bufferLength = buffer.length();
- switch (b[i])
+ switch (b.byteAt(i))
{
case ' ':
// If we don't care about trimming, then we can always append the
@@ -2945,7 +2986,7 @@
buffer.append('z');
break;
default:
- buffer.append((char) b[i]);
+ buffer.append((char) b.byteAt(i));
}
}
@@ -4121,161 +4162,292 @@
- /**
- * Evaluates and converts 2 consequetive characters of the provided
- * string starting at startPos and converts them into a single escaped char.
- *
- * @param hexString The hexadecimal string containing
- * the escape sequence.
- * @param startPos The starting position of the hexadecimal escape
- * sequence.
- *
- * @return The escaped character
- *
- * @throws DirectoryException If the provided string contains invalid
- * hexadecimal digits .
+ /**
+ * Writes the contents of the provided buffer to the client,
+ * terminating the connection if the write is unsuccessful for too
+ * long (e.g., if the client is unresponsive or there is a network
+ * problem). If possible, it will attempt to use the selector returned
+ * by the {@code ClientConnection.getWriteSelector} method, but it is
+ * capable of working even if that method returns {@code null}. <BR>
+ * <BR>
+ * Note that this method has been written in a generic manner so that
+ * other connection security providers can use it to send data to the
+ * client, provided that the given buffer contains the appropriate
+ * pre-encoded information. <BR>
+ * <BR>
+ * Also note that the original position and limit values will not be
+ * preserved, so if that is important to the caller, then it should
+ * record them before calling this method and restore them after it
+ * returns.
+ *
+ * @param clientConnection
+ * The client connection to which the data is to be written.
+ * @param socketChannel
+ * The socket channel over which to write the data.
+ * @param buffer
+ * The data to be written to the client.
+ * @return <CODE>true</CODE> if all the data in the provided buffer was
+ * written to the client and the connection may remain
+ * established, or <CODE>false</CODE> if a problem occurred
+ * and the client connection is no longer valid. Note that if
+ * this method does return <CODE>false</CODE>, then it must
+ * have already disconnected the client.
+ * @throws IOException
+ * If a problem occurs while attempting to write data to the
+ * client. The caller will be responsible for catching this
+ * and terminating the client connection.
*/
- public static char hexToEscapedChar(String hexString,int startPos)
- throws DirectoryException
+ public static boolean writeWithTimeout(
+ ClientConnection clientConnection, SocketChannel socketChannel,
+ ByteBuffer buffer) throws IOException
{
+ long startTime = System.currentTimeMillis();
+ long waitTime = clientConnection.getMaxBlockedWriteTimeLimit();
+ if (waitTime <= 0)
+ {
+ // We won't support an infinite time limit, so fall back to using
+ // five minutes, which is a very long timeout given that we're
+ // blocking a worker thread.
+ waitTime = 300000L;
+ }
- // The two positions must be the hex characters that
+ long stopTime = startTime + waitTime;
+
+ Selector selector = clientConnection.getWriteSelector();
+ if (selector == null)
+ {
+ // The client connection does not provide a selector, so we'll
+ // fall back
+ // to a more inefficient way that will work without a selector.
+ while (buffer.hasRemaining()
+ && (System.currentTimeMillis() < stopTime))
+ {
+ if (socketChannel.write(buffer) < 0)
+ {
+ // The client connection has been closed.
+ return false;
+ }
+ }
+
+ if (buffer.hasRemaining())
+ {
+ // If we've gotten here, then the write timed out.
+ return false;
+ }
+
+ return true;
+ }
+
+ // Register with the selector for handling write operations.
+ SelectionKey key =
+ socketChannel.register(selector, SelectionKey.OP_WRITE);
+
+ try
+ {
+ selector.select(waitTime);
+ while (buffer.hasRemaining())
+ {
+ long currentTime = System.currentTimeMillis();
+ if (currentTime >= stopTime)
+ {
+ // We've been blocked for too long.
+ return false;
+ }
+ else
+ {
+ waitTime = stopTime - currentTime;
+ }
+
+ Iterator<SelectionKey> iterator =
+ selector.selectedKeys().iterator();
+ while (iterator.hasNext())
+ {
+ SelectionKey k = iterator.next();
+ if (k.isWritable())
+ {
+ int bytesWritten = socketChannel.write(buffer);
+ if (bytesWritten < 0)
+ {
+ // The client connection has been closed.
+ return false;
+ }
+
+ iterator.remove();
+ }
+ }
+
+ if (buffer.hasRemaining())
+ {
+ selector.select(waitTime);
+ }
+ }
+
+ return true;
+ }
+ finally
+ {
+ if (key.isValid())
+ {
+ key.cancel();
+ selector.selectNow();
+ }
+ }
+ }
+
+
+
+ /**
+ * Evaluates and converts 2 consequetive characters of the provided
+ * string starting at startPos and converts them into a single escaped
+ * char.
+ *
+ * @param hexString
+ * The hexadecimal string containing the escape sequence.
+ * @param startPos
+ * The starting position of the hexadecimal escape sequence.
+ * @return The escaped character
+ * @throws DirectoryException
+ * If the provided string contains invalid hexadecimal
+ * digits .
+ */
+ public static char hexToEscapedChar(String hexString, int startPos)
+ throws DirectoryException
+ {
+ // The two positions must be the hex characters that
// comprise the escaped value.
- if ((startPos+ 1) >= hexString.length())
+ if ((startPos + 1) >= hexString.length())
{
Message message =
- ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.
- get(hexString, startPos+1);
+ ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.get(hexString,
+ startPos + 1);
- throw new DirectoryException(ResultCode.PROTOCOL_ERROR,
- message);
+ throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
}
byte byteValue = 0;
- switch(hexString.charAt(startPos))
+ switch (hexString.charAt(startPos))
{
- case 0x30: // '0'
- break;
- case 0x31: // '1'
- byteValue = (byte) 0x10;
- break;
- case 0x32: // '2'
- byteValue = (byte) 0x20;
- break;
- case 0x33: // '3'
- byteValue = (byte) 0x30;
- break;
- case 0x34: // '4'
- byteValue = (byte) 0x40;
- break;
- case 0x35: // '5'
- byteValue = (byte) 0x50;
- break;
- case 0x36: // '6'
- byteValue = (byte) 0x60;
- break;
- case 0x37: // '7'
- byteValue = (byte) 0x70;
- break;
- case 0x38: // '8'
- byteValue = (byte) 0x80;
- break;
- case 0x39: // '9'
- byteValue = (byte) 0x90;
- break;
- case 0x41: // 'A'
- case 0x61: // 'a'
- byteValue = (byte) 0xA0;
- break;
- case 0x42: // 'B'
- case 0x62: // 'b'
- byteValue = (byte) 0xB0;
- break;
- case 0x43: // 'C'
- case 0x63: // 'c'
- byteValue = (byte) 0xC0;
- break;
- case 0x44: // 'D'
- case 0x64: // 'd'
- byteValue = (byte) 0xD0;
- break;
- case 0x45: // 'E'
- case 0x65: // 'e'
- byteValue = (byte) 0xE0;
- break;
- case 0x46: // 'F'
- case 0x66: // 'f'
- byteValue = (byte) 0xF0;
- break;
- default:
- Message message =
- ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.
- get(hexString, startPos);
- throw new DirectoryException(
- ResultCode.PROTOCOL_ERROR, message);
+ case 0x30: // '0'
+ break;
+ case 0x31: // '1'
+ byteValue = (byte) 0x10;
+ break;
+ case 0x32: // '2'
+ byteValue = (byte) 0x20;
+ break;
+ case 0x33: // '3'
+ byteValue = (byte) 0x30;
+ break;
+ case 0x34: // '4'
+ byteValue = (byte) 0x40;
+ break;
+ case 0x35: // '5'
+ byteValue = (byte) 0x50;
+ break;
+ case 0x36: // '6'
+ byteValue = (byte) 0x60;
+ break;
+ case 0x37: // '7'
+ byteValue = (byte) 0x70;
+ break;
+ case 0x38: // '8'
+ byteValue = (byte) 0x80;
+ break;
+ case 0x39: // '9'
+ byteValue = (byte) 0x90;
+ break;
+ case 0x41: // 'A'
+ case 0x61: // 'a'
+ byteValue = (byte) 0xA0;
+ break;
+ case 0x42: // 'B'
+ case 0x62: // 'b'
+ byteValue = (byte) 0xB0;
+ break;
+ case 0x43: // 'C'
+ case 0x63: // 'c'
+ byteValue = (byte) 0xC0;
+ break;
+ case 0x44: // 'D'
+ case 0x64: // 'd'
+ byteValue = (byte) 0xD0;
+ break;
+ case 0x45: // 'E'
+ case 0x65: // 'e'
+ byteValue = (byte) 0xE0;
+ break;
+ case 0x46: // 'F'
+ case 0x66: // 'f'
+ byteValue = (byte) 0xF0;
+ break;
+ default:
+ Message message =
+ ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.get(hexString,
+ startPos);
+ throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
}
switch (hexString.charAt(++startPos))
{
- case 0x30: // '0'
- break;
- case 0x31: // '1'
- byteValue |= (byte) 0x01;
- break;
- case 0x32: // '2'
- byteValue |= (byte) 0x02;
- break;
- case 0x33: // '3'
- byteValue |= (byte) 0x03;
- break;
- case 0x34: // '4'
- byteValue |= (byte) 0x04;
- break;
- case 0x35: // '5'
- byteValue |= (byte) 0x05;
- break;
- case 0x36: // '6'
- byteValue |= (byte) 0x06;
- break;
- case 0x37: // '7'
- byteValue |= (byte) 0x07;
- break;
- case 0x38: // '8'
- byteValue |= (byte) 0x08;
- break;
- case 0x39: // '9'
- byteValue |= (byte) 0x09;
- break;
- case 0x41: // 'A'
- case 0x61: // 'a'
- byteValue |= (byte) 0x0A;
- break;
- case 0x42: // 'B'
- case 0x62: // 'b'
- byteValue |= (byte) 0x0B;
- break;
- case 0x43: // 'C'
- case 0x63: // 'c'
- byteValue |= (byte) 0x0C;
- break;
- case 0x44: // 'D'
- case 0x64: // 'd'
- byteValue |= (byte) 0x0D;
- break;
- case 0x45: // 'E'
- case 0x65: // 'e'
- byteValue |= (byte) 0x0E;
- break;
- case 0x46: // 'F'
- case 0x66: // 'f'
- byteValue |= (byte) 0x0F;
- break;
- default:
- Message message =ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.
- get(hexString, startPos);
- throw new DirectoryException(
- ResultCode.PROTOCOL_ERROR, message);
+ case 0x30: // '0'
+ break;
+ case 0x31: // '1'
+ byteValue |= (byte) 0x01;
+ break;
+ case 0x32: // '2'
+ byteValue |= (byte) 0x02;
+ break;
+ case 0x33: // '3'
+ byteValue |= (byte) 0x03;
+ break;
+ case 0x34: // '4'
+ byteValue |= (byte) 0x04;
+ break;
+ case 0x35: // '5'
+ byteValue |= (byte) 0x05;
+ break;
+ case 0x36: // '6'
+ byteValue |= (byte) 0x06;
+ break;
+ case 0x37: // '7'
+ byteValue |= (byte) 0x07;
+ break;
+ case 0x38: // '8'
+ byteValue |= (byte) 0x08;
+ break;
+ case 0x39: // '9'
+ byteValue |= (byte) 0x09;
+ break;
+ case 0x41: // 'A'
+ case 0x61: // 'a'
+ byteValue |= (byte) 0x0A;
+ break;
+ case 0x42: // 'B'
+ case 0x62: // 'b'
+ byteValue |= (byte) 0x0B;
+ break;
+ case 0x43: // 'C'
+ case 0x63: // 'c'
+ byteValue |= (byte) 0x0C;
+ break;
+ case 0x44: // 'D'
+ case 0x64: // 'd'
+ byteValue |= (byte) 0x0D;
+ break;
+ case 0x45: // 'E'
+ case 0x65: // 'e'
+ byteValue |= (byte) 0x0E;
+ break;
+ case 0x46: // 'F'
+ case 0x66: // 'f'
+ byteValue |= (byte) 0x0F;
+ break;
+ default:
+ Message message =
+ ERR_SEARCH_FILTER_INVALID_ESCAPED_BYTE.get(hexString,
+ startPos);
+ throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message);
}
- return (char)byteValue;
+ return (char) byteValue;
}
}
--
Gitblit v1.10.0