pt 1 in reviving the android build (copied from pm 28a1, wish me luck)

This commit is contained in:
wuggy 2026-04-08 15:43:25 -07:00
commit d7788a6d6d
4249 changed files with 468189 additions and 0 deletions

View file

@ -0,0 +1,111 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.util.Collection;
public class Args {
public static void check(final boolean expression, final String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}
public static void check(final boolean expression, final String message, final Object... args) {
if (!expression) {
throw new IllegalArgumentException(String.format(message, args));
}
}
public static <T> T notNull(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
return argument;
}
public static <T extends CharSequence> T notEmpty(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (TextUtils.isEmpty(argument)) {
throw new IllegalArgumentException(name + " may not be empty");
}
return argument;
}
public static <T extends CharSequence> T notBlank(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (TextUtils.isBlank(argument)) {
throw new IllegalArgumentException(name + " may not be blank");
}
return argument;
}
public static <E, T extends Collection<E>> T notEmpty(final T argument, final String name) {
if (argument == null) {
throw new IllegalArgumentException(name + " may not be null");
}
if (argument.isEmpty()) {
throw new IllegalArgumentException(name + " may not be empty");
}
return argument;
}
public static int positive(final int n, final String name) {
if (n <= 0) {
throw new IllegalArgumentException(name + " may not be negative or zero");
}
return n;
}
public static long positive(final long n, final String name) {
if (n <= 0) {
throw new IllegalArgumentException(name + " may not be negative or zero");
}
return n;
}
public static int notNegative(final int n, final String name) {
if (n < 0) {
throw new IllegalArgumentException(name + " may not be negative");
}
return n;
}
public static long notNegative(final long n, final String name) {
if (n < 0) {
throw new IllegalArgumentException(name + " may not be negative");
}
return n;
}
}

View file

@ -0,0 +1,62 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
public class Asserts {
public static void check(final boolean expression, final String message) {
if (!expression) {
throw new IllegalStateException(message);
}
}
public static void check(final boolean expression, final String message, final Object... args) {
if (!expression) {
throw new IllegalStateException(String.format(message, args));
}
}
public static void notNull(final Object object, final String name) {
if (object == null) {
throw new IllegalStateException(name + " is null");
}
}
public static void notEmpty(final CharSequence s, final String name) {
if (TextUtils.isEmpty(s)) {
throw new IllegalStateException(name + " is empty");
}
}
public static void notBlank(final CharSequence s, final String name) {
if (TextUtils.isBlank(s)) {
throw new IllegalStateException(name + " is blank");
}
}
}

View file

@ -0,0 +1,347 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.io.Serializable;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
/**
* A resizable byte array.
*
* @since 4.0
*/
@NotThreadSafe
public final class ByteArrayBuffer implements Serializable {
private static final long serialVersionUID = 4359112959524048036L;
private byte[] buffer;
private int len;
/**
* Creates an instance of {@link ByteArrayBuffer} with the given initial
* capacity.
*
* @param capacity the capacity
*/
public ByteArrayBuffer(final int capacity) {
super();
Args.notNegative(capacity, "Buffer capacity");
this.buffer = new byte[capacity];
}
private void expand(final int newlen) {
final byte newbuffer[] = new byte[Math.max(this.buffer.length << 1, newlen)];
System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
this.buffer = newbuffer;
}
/**
* Appends <code>len</code> bytes to this buffer from the given source
* array starting at index <code>off</code>. The capacity of the buffer
* is increased, if necessary, to accommodate all <code>len</code> bytes.
*
* @param b the bytes to be appended.
* @param off the index of the first byte to append.
* @param len the number of bytes to append.
* @throws IndexOutOfBoundsException if <code>off</code> if out of
* range, <code>len</code> is negative, or
* <code>off</code> + <code>len</code> is out of range.
*/
public void append(final byte[] b, final int off, final int len) {
if (b == null) {
return;
}
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) < 0) || ((off + len) > b.length)) {
throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
}
if (len == 0) {
return;
}
final int newlen = this.len + len;
if (newlen > this.buffer.length) {
expand(newlen);
}
System.arraycopy(b, off, this.buffer, this.len, len);
this.len = newlen;
}
/**
* Appends <code>b</code> byte to this buffer. The capacity of the buffer
* is increased, if necessary, to accommodate the additional byte.
*
* @param b the byte to be appended.
*/
public void append(final int b) {
final int newlen = this.len + 1;
if (newlen > this.buffer.length) {
expand(newlen);
}
this.buffer[this.len] = (byte)b;
this.len = newlen;
}
/**
* Appends <code>len</code> chars to this buffer from the given source
* array starting at index <code>off</code>. The capacity of the buffer
* is increased if necessary to accommodate all <code>len</code> chars.
* <p>
* The chars are converted to bytes using simple cast.
*
* @param b the chars to be appended.
* @param off the index of the first char to append.
* @param len the number of bytes to append.
* @throws IndexOutOfBoundsException if <code>off</code> if out of
* range, <code>len</code> is negative, or
* <code>off</code> + <code>len</code> is out of range.
*/
public void append(final char[] b, final int off, final int len) {
if (b == null) {
return;
}
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) < 0) || ((off + len) > b.length)) {
throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
}
if (len == 0) {
return;
}
final int oldlen = this.len;
final int newlen = oldlen + len;
if (newlen > this.buffer.length) {
expand(newlen);
}
for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) {
this.buffer[i2] = (byte) b[i1];
}
this.len = newlen;
}
/**
* Appends <code>len</code> chars to this buffer from the given source
* char array buffer starting at index <code>off</code>. The capacity
* of the buffer is increased if necessary to accommodate all
* <code>len</code> chars.
* <p>
* The chars are converted to bytes using simple cast.
*
* @param b the chars to be appended.
* @param off the index of the first char to append.
* @param len the number of bytes to append.
* @throws IndexOutOfBoundsException if <code>off</code> if out of
* range, <code>len</code> is negative, or
* <code>off</code> + <code>len</code> is out of range.
*/
public void append(final CharArrayBuffer b, final int off, final int len) {
if (b == null) {
return;
}
append(b.buffer(), off, len);
}
/**
* Clears content of the buffer. The underlying byte array is not resized.
*/
public void clear() {
this.len = 0;
}
/**
* Converts the content of this buffer to an array of bytes.
*
* @return byte array
*/
public byte[] toByteArray() {
final byte[] b = new byte[this.len];
if (this.len > 0) {
System.arraycopy(this.buffer, 0, b, 0, this.len);
}
return b;
}
/**
* Returns the <code>byte</code> value in this buffer at the specified
* index. The index argument must be greater than or equal to
* <code>0</code>, and less than the length of this buffer.
*
* @param i the index of the desired byte value.
* @return the byte value at the specified index.
* @throws IndexOutOfBoundsException if <code>index</code> is
* negative or greater than or equal to {@link #length()}.
*/
public int byteAt(final int i) {
return this.buffer[i];
}
/**
* Returns the current capacity. The capacity is the amount of storage
* available for newly appended bytes, beyond which an allocation
* will occur.
*
* @return the current capacity
*/
public int capacity() {
return this.buffer.length;
}
/**
* Returns the length of the buffer (byte count).
*
* @return the length of the buffer
*/
public int length() {
return this.len;
}
/**
* Ensures that the capacity is at least equal to the specified minimum.
* If the current capacity is less than the argument, then a new internal
* array is allocated with greater capacity. If the <code>required</code>
* argument is non-positive, this method takes no action.
*
* @param required the minimum required capacity.
*
* @since 4.1
*/
public void ensureCapacity(final int required) {
if (required <= 0) {
return;
}
final int available = this.buffer.length - this.len;
if (required > available) {
expand(this.len + required);
}
}
/**
* Returns reference to the underlying byte array.
*
* @return the byte array.
*/
public byte[] buffer() {
return this.buffer;
}
/**
* Sets the length of the buffer. The new length value is expected to be
* less than the current capacity and greater than or equal to
* <code>0</code>.
*
* @param len the new length
* @throws IndexOutOfBoundsException if the
* <code>len</code> argument is greater than the current
* capacity of the buffer or less than <code>0</code>.
*/
public void setLength(final int len) {
if (len < 0 || len > this.buffer.length) {
throw new IndexOutOfBoundsException("len: "+len+" < 0 or > buffer len: "+this.buffer.length);
}
this.len = len;
}
/**
* Returns <code>true</code> if this buffer is empty, that is, its
* {@link #length()} is equal to <code>0</code>.
* @return <code>true</code> if this buffer is empty, <code>false</code>
* otherwise.
*/
public boolean isEmpty() {
return this.len == 0;
}
/**
* Returns <code>true</code> if this buffer is full, that is, its
* {@link #length()} is equal to its {@link #capacity()}.
* @return <code>true</code> if this buffer is full, <code>false</code>
* otherwise.
*/
public boolean isFull() {
return this.len == this.buffer.length;
}
/**
* Returns the index within this buffer of the first occurrence of the
* specified byte, starting the search at the specified
* <code>beginIndex</code> and finishing at <code>endIndex</code>.
* If no such byte occurs in this buffer within the specified bounds,
* <code>-1</code> is returned.
* <p>
* There is no restriction on the value of <code>beginIndex</code> and
* <code>endIndex</code>. If <code>beginIndex</code> is negative,
* it has the same effect as if it were zero. If <code>endIndex</code> is
* greater than {@link #length()}, it has the same effect as if it were
* {@link #length()}. If the <code>beginIndex</code> is greater than
* the <code>endIndex</code>, <code>-1</code> is returned.
*
* @param b the byte to search for.
* @param from the index to start the search from.
* @param to the index to finish the search at.
* @return the index of the first occurrence of the byte in the buffer
* within the given bounds, or <code>-1</code> if the byte does
* not occur.
*
* @since 4.1
*/
public int indexOf(final byte b, final int from, final int to) {
int beginIndex = from;
if (beginIndex < 0) {
beginIndex = 0;
}
int endIndex = to;
if (endIndex > this.len) {
endIndex = this.len;
}
if (beginIndex > endIndex) {
return -1;
}
for (int i = beginIndex; i < endIndex; i++) {
if (this.buffer[i] == b) {
return i;
}
}
return -1;
}
/**
* Returns the index within this buffer of the first occurrence of the
* specified byte, starting the search at <code>0</code> and finishing
* at {@link #length()}. If no such byte occurs in this buffer within
* those bounds, <code>-1</code> is returned.
*
* @param b the byte to search for.
* @return the index of the first occurrence of the byte in the
* buffer, or <code>-1</code> if the byte does not occur.
*
* @since 4.1
*/
public int indexOf(final byte b) {
return indexOf(b, 0, this.len);
}
}

View file

@ -0,0 +1,464 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.io.Serializable;
import ch.boye.httpclientandroidlib.annotation.NotThreadSafe;
import ch.boye.httpclientandroidlib.protocol.HTTP;
/**
* A resizable char array.
*
* @since 4.0
*/
@NotThreadSafe
public final class CharArrayBuffer implements Serializable {
private static final long serialVersionUID = -6208952725094867135L;
private char[] buffer;
private int len;
/**
* Creates an instance of {@link CharArrayBuffer} with the given initial
* capacity.
*
* @param capacity the capacity
*/
public CharArrayBuffer(final int capacity) {
super();
Args.notNegative(capacity, "Buffer capacity");
this.buffer = new char[capacity];
}
private void expand(final int newlen) {
final char newbuffer[] = new char[Math.max(this.buffer.length << 1, newlen)];
System.arraycopy(this.buffer, 0, newbuffer, 0, this.len);
this.buffer = newbuffer;
}
/**
* Appends <code>len</code> chars to this buffer from the given source
* array starting at index <code>off</code>. The capacity of the buffer
* is increased, if necessary, to accommodate all <code>len</code> chars.
*
* @param b the chars to be appended.
* @param off the index of the first char to append.
* @param len the number of chars to append.
* @throws IndexOutOfBoundsException if <code>off</code> is out of
* range, <code>len</code> is negative, or
* <code>off</code> + <code>len</code> is out of range.
*/
public void append(final char[] b, final int off, final int len) {
if (b == null) {
return;
}
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) < 0) || ((off + len) > b.length)) {
throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
}
if (len == 0) {
return;
}
final int newlen = this.len + len;
if (newlen > this.buffer.length) {
expand(newlen);
}
System.arraycopy(b, off, this.buffer, this.len, len);
this.len = newlen;
}
/**
* Appends chars of the given string to this buffer. The capacity of the
* buffer is increased, if necessary, to accommodate all chars.
*
* @param str the string.
*/
public void append(final String str) {
final String s = str != null ? str : "null";
final int strlen = s.length();
final int newlen = this.len + strlen;
if (newlen > this.buffer.length) {
expand(newlen);
}
s.getChars(0, strlen, this.buffer, this.len);
this.len = newlen;
}
/**
* Appends <code>len</code> chars to this buffer from the given source
* buffer starting at index <code>off</code>. The capacity of the
* destination buffer is increased, if necessary, to accommodate all
* <code>len</code> chars.
*
* @param b the source buffer to be appended.
* @param off the index of the first char to append.
* @param len the number of chars to append.
* @throws IndexOutOfBoundsException if <code>off</code> is out of
* range, <code>len</code> is negative, or
* <code>off</code> + <code>len</code> is out of range.
*/
public void append(final CharArrayBuffer b, final int off, final int len) {
if (b == null) {
return;
}
append(b.buffer, off, len);
}
/**
* Appends all chars to this buffer from the given source buffer starting
* at index <code>0</code>. The capacity of the destination buffer is
* increased, if necessary, to accommodate all {@link #length()} chars.
*
* @param b the source buffer to be appended.
*/
public void append(final CharArrayBuffer b) {
if (b == null) {
return;
}
append(b.buffer,0, b.len);
}
/**
* Appends <code>ch</code> char to this buffer. The capacity of the buffer
* is increased, if necessary, to accommodate the additional char.
*
* @param ch the char to be appended.
*/
public void append(final char ch) {
final int newlen = this.len + 1;
if (newlen > this.buffer.length) {
expand(newlen);
}
this.buffer[this.len] = ch;
this.len = newlen;
}
/**
* Appends <code>len</code> bytes to this buffer from the given source
* array starting at index <code>off</code>. The capacity of the buffer
* is increased, if necessary, to accommodate all <code>len</code> bytes.
* <p>
* The bytes are converted to chars using simple cast.
*
* @param b the bytes to be appended.
* @param off the index of the first byte to append.
* @param len the number of bytes to append.
* @throws IndexOutOfBoundsException if <code>off</code> is out of
* range, <code>len</code> is negative, or
* <code>off</code> + <code>len</code> is out of range.
*/
public void append(final byte[] b, final int off, final int len) {
if (b == null) {
return;
}
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) < 0) || ((off + len) > b.length)) {
throw new IndexOutOfBoundsException("off: "+off+" len: "+len+" b.length: "+b.length);
}
if (len == 0) {
return;
}
final int oldlen = this.len;
final int newlen = oldlen + len;
if (newlen > this.buffer.length) {
expand(newlen);
}
for (int i1 = off, i2 = oldlen; i2 < newlen; i1++, i2++) {
this.buffer[i2] = (char) (b[i1] & 0xff);
}
this.len = newlen;
}
/**
* Appends <code>len</code> bytes to this buffer from the given source
* array starting at index <code>off</code>. The capacity of the buffer
* is increased, if necessary, to accommodate all <code>len</code> bytes.
* <p>
* The bytes are converted to chars using simple cast.
*
* @param b the bytes to be appended.
* @param off the index of the first byte to append.
* @param len the number of bytes to append.
* @throws IndexOutOfBoundsException if <code>off</code> is out of
* range, <code>len</code> is negative, or
* <code>off</code> + <code>len</code> is out of range.
*/
public void append(final ByteArrayBuffer b, final int off, final int len) {
if (b == null) {
return;
}
append(b.buffer(), off, len);
}
/**
* Appends chars of the textual representation of the given object to this
* buffer. The capacity of the buffer is increased, if necessary, to
* accommodate all chars.
*
* @param obj the object.
*/
public void append(final Object obj) {
append(String.valueOf(obj));
}
/**
* Clears content of the buffer. The underlying char array is not resized.
*/
public void clear() {
this.len = 0;
}
/**
* Converts the content of this buffer to an array of chars.
*
* @return char array
*/
public char[] toCharArray() {
final char[] b = new char[this.len];
if (this.len > 0) {
System.arraycopy(this.buffer, 0, b, 0, this.len);
}
return b;
}
/**
* Returns the <code>char</code> value in this buffer at the specified
* index. The index argument must be greater than or equal to
* <code>0</code>, and less than the length of this buffer.
*
* @param i the index of the desired char value.
* @return the char value at the specified index.
* @throws IndexOutOfBoundsException if <code>index</code> is
* negative or greater than or equal to {@link #length()}.
*/
public char charAt(final int i) {
return this.buffer[i];
}
/**
* Returns reference to the underlying char array.
*
* @return the char array.
*/
public char[] buffer() {
return this.buffer;
}
/**
* Returns the current capacity. The capacity is the amount of storage
* available for newly appended chars, beyond which an allocation will
* occur.
*
* @return the current capacity
*/
public int capacity() {
return this.buffer.length;
}
/**
* Returns the length of the buffer (char count).
*
* @return the length of the buffer
*/
public int length() {
return this.len;
}
/**
* Ensures that the capacity is at least equal to the specified minimum.
* If the current capacity is less than the argument, then a new internal
* array is allocated with greater capacity. If the <code>required</code>
* argument is non-positive, this method takes no action.
*
* @param required the minimum required capacity.
*/
public void ensureCapacity(final int required) {
if (required <= 0) {
return;
}
final int available = this.buffer.length - this.len;
if (required > available) {
expand(this.len + required);
}
}
/**
* Sets the length of the buffer. The new length value is expected to be
* less than the current capacity and greater than or equal to
* <code>0</code>.
*
* @param len the new length
* @throws IndexOutOfBoundsException if the
* <code>len</code> argument is greater than the current
* capacity of the buffer or less than <code>0</code>.
*/
public void setLength(final int len) {
if (len < 0 || len > this.buffer.length) {
throw new IndexOutOfBoundsException("len: "+len+" < 0 or > buffer len: "+this.buffer.length);
}
this.len = len;
}
/**
* Returns <code>true</code> if this buffer is empty, that is, its
* {@link #length()} is equal to <code>0</code>.
* @return <code>true</code> if this buffer is empty, <code>false</code>
* otherwise.
*/
public boolean isEmpty() {
return this.len == 0;
}
/**
* Returns <code>true</code> if this buffer is full, that is, its
* {@link #length()} is equal to its {@link #capacity()}.
* @return <code>true</code> if this buffer is full, <code>false</code>
* otherwise.
*/
public boolean isFull() {
return this.len == this.buffer.length;
}
/**
* Returns the index within this buffer of the first occurrence of the
* specified character, starting the search at the specified
* <code>beginIndex</code> and finishing at <code>endIndex</code>.
* If no such character occurs in this buffer within the specified bounds,
* <code>-1</code> is returned.
* <p>
* There is no restriction on the value of <code>beginIndex</code> and
* <code>endIndex</code>. If <code>beginIndex</code> is negative,
* it has the same effect as if it were zero. If <code>endIndex</code> is
* greater than {@link #length()}, it has the same effect as if it were
* {@link #length()}. If the <code>beginIndex</code> is greater than
* the <code>endIndex</code>, <code>-1</code> is returned.
*
* @param ch the char to search for.
* @param from the index to start the search from.
* @param to the index to finish the search at.
* @return the index of the first occurrence of the character in the buffer
* within the given bounds, or <code>-1</code> if the character does
* not occur.
*/
public int indexOf(final int ch, final int from, final int to) {
int beginIndex = from;
if (beginIndex < 0) {
beginIndex = 0;
}
int endIndex = to;
if (endIndex > this.len) {
endIndex = this.len;
}
if (beginIndex > endIndex) {
return -1;
}
for (int i = beginIndex; i < endIndex; i++) {
if (this.buffer[i] == ch) {
return i;
}
}
return -1;
}
/**
* Returns the index within this buffer of the first occurrence of the
* specified character, starting the search at <code>0</code> and finishing
* at {@link #length()}. If no such character occurs in this buffer within
* those bounds, <code>-1</code> is returned.
*
* @param ch the char to search for.
* @return the index of the first occurrence of the character in the
* buffer, or <code>-1</code> if the character does not occur.
*/
public int indexOf(final int ch) {
return indexOf(ch, 0, this.len);
}
/**
* Returns a substring of this buffer. The substring begins at the specified
* <code>beginIndex</code> and extends to the character at index
* <code>endIndex - 1</code>.
*
* @param beginIndex the beginning index, inclusive.
* @param endIndex the ending index, exclusive.
* @return the specified substring.
* @exception StringIndexOutOfBoundsException if the
* <code>beginIndex</code> is negative, or
* <code>endIndex</code> is larger than the length of this
* buffer, or <code>beginIndex</code> is larger than
* <code>endIndex</code>.
*/
public String substring(final int beginIndex, final int endIndex) {
return new String(this.buffer, beginIndex, endIndex - beginIndex);
}
/**
* Returns a substring of this buffer with leading and trailing whitespace
* omitted. The substring begins with the first non-whitespace character
* from <code>beginIndex</code> and extends to the last
* non-whitespace character with the index lesser than
* <code>endIndex</code>.
*
* @param from the beginning index, inclusive.
* @param to the ending index, exclusive.
* @return the specified substring.
* @exception IndexOutOfBoundsException if the
* <code>beginIndex</code> is negative, or
* <code>endIndex</code> is larger than the length of this
* buffer, or <code>beginIndex</code> is larger than
* <code>endIndex</code>.
*/
public String substringTrimmed(final int from, final int to) {
int beginIndex = from;
int endIndex = to;
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("Negative beginIndex: "+beginIndex);
}
if (endIndex > this.len) {
throw new IndexOutOfBoundsException("endIndex: "+endIndex+" > length: "+this.len);
}
if (beginIndex > endIndex) {
throw new IndexOutOfBoundsException("beginIndex: "+beginIndex+" > endIndex: "+endIndex);
}
while (beginIndex < endIndex && HTTP.isWhitespace(this.buffer[beginIndex])) {
beginIndex++;
}
while (endIndex > beginIndex && HTTP.isWhitespace(this.buffer[endIndex - 1])) {
endIndex--;
}
return new String(this.buffer, beginIndex, endIndex - beginIndex);
}
@Override
public String toString() {
return new String(this.buffer, 0, this.len);
}
}

View file

@ -0,0 +1,58 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
public class CharsetUtils {
public static Charset lookup(final String name) {
if (name == null) {
return null;
}
try {
return Charset.forName(name);
} catch (final UnsupportedCharsetException ex) {
return null;
}
}
public static Charset get(final String name) throws UnsupportedEncodingException {
if (name == null) {
return null;
}
try {
return Charset.forName(name);
} catch (final UnsupportedCharsetException ex) {
throw new UnsupportedEncodingException(name);
}
}
}

View file

@ -0,0 +1,152 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.io.UnsupportedEncodingException;
import ch.boye.httpclientandroidlib.Consts;
/**
* The home for utility methods that handle various encoding tasks.
*
*
* @since 4.0
*/
public final class EncodingUtils {
/**
* Converts the byte array of HTTP content characters to a string. If
* the specified charset is not supported, default system encoding
* is used.
*
* @param data the byte array to be encoded
* @param offset the index of the first byte to encode
* @param length the number of bytes to encode
* @param charset the desired character encoding
* @return The result of the conversion.
*/
public static String getString(
final byte[] data,
final int offset,
final int length,
final String charset) {
Args.notNull(data, "Input");
Args.notEmpty(charset, "Charset");
try {
return new String(data, offset, length, charset);
} catch (final UnsupportedEncodingException e) {
return new String(data, offset, length);
}
}
/**
* Converts the byte array of HTTP content characters to a string. If
* the specified charset is not supported, default system encoding
* is used.
*
* @param data the byte array to be encoded
* @param charset the desired character encoding
* @return The result of the conversion.
*/
public static String getString(final byte[] data, final String charset) {
Args.notNull(data, "Input");
return getString(data, 0, data.length, charset);
}
/**
* Converts the specified string to a byte array. If the charset is not supported the
* default system charset is used.
*
* @param data the string to be encoded
* @param charset the desired character encoding
* @return The resulting byte array.
*/
public static byte[] getBytes(final String data, final String charset) {
Args.notNull(data, "Input");
Args.notEmpty(charset, "Charset");
try {
return data.getBytes(charset);
} catch (final UnsupportedEncodingException e) {
return data.getBytes();
}
}
/**
* Converts the specified string to byte array of ASCII characters.
*
* @param data the string to be encoded
* @return The string as a byte array.
*/
public static byte[] getAsciiBytes(final String data) {
Args.notNull(data, "Input");
try {
return data.getBytes(Consts.ASCII.name());
} catch (final UnsupportedEncodingException e) {
throw new Error("ASCII not supported");
}
}
/**
* Converts the byte array of ASCII characters to a string. This method is
* to be used when decoding content of HTTP elements (such as response
* headers)
*
* @param data the byte array to be encoded
* @param offset the index of the first byte to encode
* @param length the number of bytes to encode
* @return The string representation of the byte array
*/
public static String getAsciiString(final byte[] data, final int offset, final int length) {
Args.notNull(data, "Input");
try {
return new String(data, offset, length, Consts.ASCII.name());
} catch (final UnsupportedEncodingException e) {
throw new Error("ASCII not supported");
}
}
/**
* Converts the byte array of ASCII characters to a string. This method is
* to be used when decoding content of HTTP elements (such as response
* headers)
*
* @param data the byte array to be encoded
* @return The string representation of the byte array
*/
public static String getAsciiString(final byte[] data) {
Args.notNull(data, "Input");
return getAsciiString(data, 0, data.length);
}
/**
* This class should not be instantiated.
*/
private EncodingUtils() {
}
}

View file

@ -0,0 +1,291 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import ch.boye.httpclientandroidlib.HeaderElement;
import ch.boye.httpclientandroidlib.HttpEntity;
import ch.boye.httpclientandroidlib.HttpResponse;
import ch.boye.httpclientandroidlib.NameValuePair;
import ch.boye.httpclientandroidlib.ParseException;
import ch.boye.httpclientandroidlib.entity.ContentType;
import ch.boye.httpclientandroidlib.protocol.HTTP;
/**
* Static helpers for dealing with {@link HttpEntity}s.
*
* @since 4.0
*/
public final class EntityUtils {
private EntityUtils() {
}
/**
* Ensures that the entity content is fully consumed and the content stream, if exists,
* is closed. The process is done, <i>quietly</i> , without throwing any IOException.
*
* @param entity the entity to consume.
*
*
* @since 4.2
*/
public static void consumeQuietly(final HttpEntity entity) {
try {
consume(entity);
} catch (final IOException ignore) {
}
}
/**
* Ensures that the entity content is fully consumed and the content stream, if exists,
* is closed.
*
* @param entity the entity to consume.
* @throws IOException if an error occurs reading the input stream
*
* @since 4.1
*/
public static void consume(final HttpEntity entity) throws IOException {
if (entity == null) {
return;
}
if (entity.isStreaming()) {
final InputStream instream = entity.getContent();
if (instream != null) {
instream.close();
}
}
}
/**
* Updates an entity in a response by first consuming an existing entity, then setting the new one.
*
* @param response the response with an entity to update; must not be null.
* @param entity the entity to set in the response.
* @throws IOException if an error occurs while reading the input stream on the existing
* entity.
* @throws IllegalArgumentException if response is null.
*
* @since 4.3
*/
public static void updateEntity(
final HttpResponse response, final HttpEntity entity) throws IOException {
Args.notNull(response, "Response");
consume(response.getEntity());
response.setEntity(entity);
}
/**
* Read the contents of an entity and return it as a byte array.
*
* @param entity the entity to read from=
* @return byte array containing the entity content. May be null if
* {@link HttpEntity#getContent()} is null.
* @throws IOException if an error occurs reading the input stream
* @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE
*/
public static byte[] toByteArray(final HttpEntity entity) throws IOException {
Args.notNull(entity, "Entity");
final InputStream instream = entity.getContent();
if (instream == null) {
return null;
}
try {
Args.check(entity.getContentLength() <= Integer.MAX_VALUE,
"HTTP entity too large to be buffered in memory");
int i = (int)entity.getContentLength();
if (i < 0) {
i = 4096;
}
final ByteArrayBuffer buffer = new ByteArrayBuffer(i);
final byte[] tmp = new byte[4096];
int l;
while((l = instream.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
return buffer.toByteArray();
} finally {
instream.close();
}
}
/**
* Obtains character set of the entity, if known.
*
* @param entity must not be null
* @return the character set, or null if not found
* @throws ParseException if header elements cannot be parsed
* @throws IllegalArgumentException if entity is null
*
* @deprecated (4.1.3) use {@link ContentType#getOrDefault(HttpEntity)}
*/
@Deprecated
public static String getContentCharSet(final HttpEntity entity) throws ParseException {
Args.notNull(entity, "Entity");
String charset = null;
if (entity.getContentType() != null) {
final HeaderElement values[] = entity.getContentType().getElements();
if (values.length > 0) {
final NameValuePair param = values[0].getParameterByName("charset");
if (param != null) {
charset = param.getValue();
}
}
}
return charset;
}
/**
* Obtains MIME type of the entity, if known.
*
* @param entity must not be null
* @return the character set, or null if not found
* @throws ParseException if header elements cannot be parsed
* @throws IllegalArgumentException if entity is null
*
* @since 4.1
*
* @deprecated (4.1.3) use {@link ContentType#getOrDefault(HttpEntity)}
*/
@Deprecated
public static String getContentMimeType(final HttpEntity entity) throws ParseException {
Args.notNull(entity, "Entity");
String mimeType = null;
if (entity.getContentType() != null) {
final HeaderElement values[] = entity.getContentType().getElements();
if (values.length > 0) {
mimeType = values[0].getName();
}
}
return mimeType;
}
/**
* Get the entity content as a String, using the provided default character set
* if none is found in the entity.
* If defaultCharset is null, the default "ISO-8859-1" is used.
*
* @param entity must not be null
* @param defaultCharset character set to be applied if none found in the entity
* @return the entity content as a String. May be null if
* {@link HttpEntity#getContent()} is null.
* @throws ParseException if header elements cannot be parsed
* @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE
* @throws IOException if an error occurs reading the input stream
* @throws UnsupportedCharsetException Thrown when the named charset is not available in
* this instance of the Java virtual machine
*/
public static String toString(
final HttpEntity entity, final Charset defaultCharset) throws IOException, ParseException {
Args.notNull(entity, "Entity");
final InputStream instream = entity.getContent();
if (instream == null) {
return null;
}
try {
Args.check(entity.getContentLength() <= Integer.MAX_VALUE,
"HTTP entity too large to be buffered in memory");
int i = (int)entity.getContentLength();
if (i < 0) {
i = 4096;
}
Charset charset = null;
try {
final ContentType contentType = ContentType.get(entity);
if (contentType != null) {
charset = contentType.getCharset();
}
} catch (final UnsupportedCharsetException ex) {
throw new UnsupportedEncodingException(ex.getMessage());
}
if (charset == null) {
charset = defaultCharset;
}
if (charset == null) {
charset = HTTP.DEF_CONTENT_CHARSET;
}
final Reader reader = new InputStreamReader(instream, charset);
final CharArrayBuffer buffer = new CharArrayBuffer(i);
final char[] tmp = new char[1024];
int l;
while((l = reader.read(tmp)) != -1) {
buffer.append(tmp, 0, l);
}
return buffer.toString();
} finally {
instream.close();
}
}
/**
* Get the entity content as a String, using the provided default character set
* if none is found in the entity.
* If defaultCharset is null, the default "ISO-8859-1" is used.
*
* @param entity must not be null
* @param defaultCharset character set to be applied if none found in the entity
* @return the entity content as a String. May be null if
* {@link HttpEntity#getContent()} is null.
* @throws ParseException if header elements cannot be parsed
* @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE
* @throws IOException if an error occurs reading the input stream
* @throws UnsupportedCharsetException Thrown when the named charset is not available in
* this instance of the Java virtual machine
*/
public static String toString(
final HttpEntity entity, final String defaultCharset) throws IOException, ParseException {
return toString(entity, defaultCharset != null ? Charset.forName(defaultCharset) : null);
}
/**
* Read the contents of an entity and return it as a String.
* The content is converted using the character set from the entity (if any),
* failing that, "ISO-8859-1" is used.
*
* @param entity the entity to convert to a string; must not be null
* @return String containing the content.
* @throws ParseException if header elements cannot be parsed
* @throws IllegalArgumentException if entity is null or if content length > Integer.MAX_VALUE
* @throws IOException if an error occurs reading the input stream
* @throws UnsupportedCharsetException Thrown when the named charset is not available in
* this instance of the Java virtual machine
*/
public static String toString(final HttpEntity entity)
throws IOException, ParseException {
return toString(entity, (Charset)null);
}
}

View file

@ -0,0 +1,82 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.lang.reflect.Method;
/**
* The home for utility methods that handle various exception-related tasks.
*
*
* @since 4.0
*
* @deprecated (4.2) no longer used
*/
@Deprecated
public final class ExceptionUtils {
/** A reference to Throwable's initCause method, or null if it's not there in this JVM */
static private final Method INIT_CAUSE_METHOD = getInitCauseMethod();
/**
* Returns a <code>Method<code> allowing access to
* {@link Throwable#initCause(Throwable) initCause} method of {@link Throwable},
* or <code>null</code> if the method
* does not exist.
*
* @return A <code>Method<code> for <code>Throwable.initCause</code>, or
* <code>null</code> if unavailable.
*/
static private Method getInitCauseMethod() {
try {
final Class<?>[] paramsClasses = new Class[] { Throwable.class };
return Throwable.class.getMethod("initCause", paramsClasses);
} catch (final NoSuchMethodException e) {
return null;
}
}
/**
* If we're running on JDK 1.4 or later, initialize the cause for the given throwable.
*
* @param throwable The throwable.
* @param cause The cause of the throwable.
*/
public static void initCause(final Throwable throwable, final Throwable cause) {
if (INIT_CAUSE_METHOD != null) {
try {
INIT_CAUSE_METHOD.invoke(throwable, cause);
} catch (final Exception e) {
// Well, with no logging, the only option is to munch the exception
}
}
}
private ExceptionUtils() {
}
}

View file

@ -0,0 +1,101 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
/**
* A set of utility methods to help produce consistent
* {@link Object#equals equals} and {@link Object#hashCode hashCode} methods.
*
*
* @since 4.0
*/
public final class LangUtils {
public static final int HASH_SEED = 17;
public static final int HASH_OFFSET = 37;
/** Disabled default constructor. */
private LangUtils() {
}
public static int hashCode(final int seed, final int hashcode) {
return seed * HASH_OFFSET + hashcode;
}
public static int hashCode(final int seed, final boolean b) {
return hashCode(seed, b ? 1 : 0);
}
public static int hashCode(final int seed, final Object obj) {
return hashCode(seed, obj != null ? obj.hashCode() : 0);
}
/**
* Check if two objects are equal.
*
* @param obj1 first object to compare, may be {@code null}
* @param obj2 second object to compare, may be {@code null}
* @return {@code true} if the objects are equal or both null
*/
public static boolean equals(final Object obj1, final Object obj2) {
return obj1 == null ? obj2 == null : obj1.equals(obj2);
}
/**
* Check if two object arrays are equal.
* <p>
* <ul>
* <li>If both parameters are null, return {@code true}</li>
* <li>If one parameter is null, return {@code false}</li>
* <li>If the array lengths are different, return {@code false}</li>
* <li>Compare array elements using .equals(); return {@code false} if any comparisons fail.</li>
* <li>Return {@code true}</li>
* </ul>
*
* @param a1 first array to compare, may be {@code null}
* @param a2 second array to compare, may be {@code null}
* @return {@code true} if the arrays are equal or both null
*/
public static boolean equals(final Object[] a1, final Object[] a2) {
if (a1 == null) {
return a2 == null;
} else {
if (a2 != null && a1.length == a2.length) {
for (int i = 0; i < a1.length; i++) {
if (!equals(a1[i], a2[i])) {
return false;
}
}
return true;
} else {
return false;
}
}
}
}

View file

@ -0,0 +1,54 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
/**
* @since 4.3
*/
public final class NetUtils {
public static void formatAddress(
final StringBuilder buffer,
final SocketAddress socketAddress) {
Args.notNull(buffer, "Buffer");
Args.notNull(socketAddress, "Socket address");
if (socketAddress instanceof InetSocketAddress) {
final InetSocketAddress socketaddr = ((InetSocketAddress) socketAddress);
final InetAddress inetaddr = socketaddr.getAddress();
buffer.append(inetaddr != null ? inetaddr.getHostAddress() : inetaddr)
.append(':').append(socketaddr.getPort());
} else {
buffer.append(socketAddress);
}
}
}

View file

@ -0,0 +1,54 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
/**
* @since 4.3
*/
public final class TextUtils {
public static boolean isEmpty(final CharSequence s) {
if (s == null) {
return true;
}
return s.length() == 0;
}
public static boolean isBlank(final CharSequence s) {
if (s == null) {
return true;
}
for (int i = 0; i < s.length(); i++) {
if (!Character.isWhitespace(s.charAt(i))) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,324 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package ch.boye.httpclientandroidlib.util;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* Provides access to version information for HTTP components.
* Static methods are used to extract version information from property
* files that are automatically packaged with HTTP component release JARs.
* <br/>
* All available version information is provided in strings, where
* the string format is informal and subject to change without notice.
* Version information is provided for debugging output and interpretation
* by humans, not for automated processing in applications.
*
* @since 4.0
*/
public class VersionInfo {
/** A string constant for unavailable information. */
public final static String UNAVAILABLE = "UNAVAILABLE";
/** The filename of the version information files. */
public final static String VERSION_PROPERTY_FILE = "version.properties";
// the property names
public final static String PROPERTY_MODULE = "info.module";
public final static String PROPERTY_RELEASE = "info.release";
public final static String PROPERTY_TIMESTAMP = "info.timestamp";
/** The package that contains the version information. */
private final String infoPackage;
/** The module from the version info. */
private final String infoModule;
/** The release from the version info. */
private final String infoRelease;
/** The timestamp from the version info. */
private final String infoTimestamp;
/** The classloader from which the version info was obtained. */
private final String infoClassloader;
/**
* Instantiates version information.
*
* @param pckg the package
* @param module the module, or <code>null</code>
* @param release the release, or <code>null</code>
* @param time the build time, or <code>null</code>
* @param clsldr the class loader, or <code>null</code>
*/
protected VersionInfo(final String pckg, final String module,
final String release, final String time, final String clsldr) {
Args.notNull(pckg, "Package identifier");
infoPackage = pckg;
infoModule = (module != null) ? module : UNAVAILABLE;
infoRelease = (release != null) ? release : UNAVAILABLE;
infoTimestamp = (time != null) ? time : UNAVAILABLE;
infoClassloader = (clsldr != null) ? clsldr : UNAVAILABLE;
}
/**
* Obtains the package name.
* The package name identifies the module or informal unit.
*
* @return the package name, never <code>null</code>
*/
public final String getPackage() {
return infoPackage;
}
/**
* Obtains the name of the versioned module or informal unit.
* This data is read from the version information for the package.
*
* @return the module name, never <code>null</code>
*/
public final String getModule() {
return infoModule;
}
/**
* Obtains the release of the versioned module or informal unit.
* This data is read from the version information for the package.
*
* @return the release version, never <code>null</code>
*/
public final String getRelease() {
return infoRelease;
}
/**
* Obtains the timestamp of the versioned module or informal unit.
* This data is read from the version information for the package.
*
* @return the timestamp, never <code>null</code>
*/
public final String getTimestamp() {
return infoTimestamp;
}
/**
* Obtains the classloader used to read the version information.
* This is just the <code>toString</code> output of the classloader,
* since the version information should not keep a reference to
* the classloader itself. That could prevent garbage collection.
*
* @return the classloader description, never <code>null</code>
*/
public final String getClassloader() {
return infoClassloader;
}
/**
* Provides the version information in human-readable format.
*
* @return a string holding this version information
*/
@Override
public String toString() {
final StringBuilder sb = new StringBuilder
(20 + infoPackage.length() + infoModule.length() +
infoRelease.length() + infoTimestamp.length() +
infoClassloader.length());
sb.append("VersionInfo(")
.append(infoPackage).append(':').append(infoModule);
// If version info is missing, a single "UNAVAILABLE" for the module
// is sufficient. Everything else just clutters the output.
if (!UNAVAILABLE.equals(infoRelease)) {
sb.append(':').append(infoRelease);
}
if (!UNAVAILABLE.equals(infoTimestamp)) {
sb.append(':').append(infoTimestamp);
}
sb.append(')');
if (!UNAVAILABLE.equals(infoClassloader)) {
sb.append('@').append(infoClassloader);
}
return sb.toString();
}
/**
* Loads version information for a list of packages.
*
* @param pckgs the packages for which to load version info
* @param clsldr the classloader to load from, or
* <code>null</code> for the thread context classloader
*
* @return the version information for all packages found,
* never <code>null</code>
*/
public static VersionInfo[] loadVersionInfo(final String[] pckgs,
final ClassLoader clsldr) {
Args.notNull(pckgs, "Package identifier array");
final List<VersionInfo> vil = new ArrayList<VersionInfo>(pckgs.length);
for (final String pckg : pckgs) {
final VersionInfo vi = loadVersionInfo(pckg, clsldr);
if (vi != null) {
vil.add(vi);
}
}
return vil.toArray(new VersionInfo[vil.size()]);
}
/**
* Loads version information for a package.
*
* @param pckg the package for which to load version information,
* for example "ch.boye.httpclientandroidlib".
* The package name should NOT end with a dot.
* @param clsldr the classloader to load from, or
* <code>null</code> for the thread context classloader
*
* @return the version information for the argument package, or
* <code>null</code> if not available
*/
public static VersionInfo loadVersionInfo(final String pckg,
final ClassLoader clsldr) {
Args.notNull(pckg, "Package identifier");
final ClassLoader cl = clsldr != null ? clsldr : Thread.currentThread().getContextClassLoader();
Properties vip = null; // version info properties, if available
try {
// ch.boye.httpclientandroidlib becomes
// org/apache/http/version.properties
final InputStream is = cl.getResourceAsStream
(pckg.replace('.', '/') + "/" + VERSION_PROPERTY_FILE);
if (is != null) {
try {
final Properties props = new Properties();
props.load(is);
vip = props;
} finally {
is.close();
}
}
} catch (final IOException ex) {
// shamelessly munch this exception
}
VersionInfo result = null;
if (vip != null) {
result = fromMap(pckg, vip, cl);
}
return result;
}
/**
* Instantiates version information from properties.
*
* @param pckg the package for the version information
* @param info the map from string keys to string values,
* for example {@link java.util.Properties}
* @param clsldr the classloader, or <code>null</code>
*
* @return the version information
*/
protected static VersionInfo fromMap(final String pckg, final Map<?, ?> info,
final ClassLoader clsldr) {
Args.notNull(pckg, "Package identifier");
String module = null;
String release = null;
String timestamp = null;
if (info != null) {
module = (String) info.get(PROPERTY_MODULE);
if ((module != null) && (module.length() < 1)) {
module = null;
}
release = (String) info.get(PROPERTY_RELEASE);
if ((release != null) && ((release.length() < 1) ||
(release.equals("${pom.version}")))) {
release = null;
}
timestamp = (String) info.get(PROPERTY_TIMESTAMP);
if ((timestamp != null) &&
((timestamp.length() < 1) ||
(timestamp.equals("${mvn.timestamp}")))
) {
timestamp = null;
}
} // if info
String clsldrstr = null;
if (clsldr != null) {
clsldrstr = clsldr.toString();
}
return new VersionInfo(pckg, module, release, timestamp, clsldrstr);
}
/**
* Sets the user agent to {@code "<name>/<release> (Java 1.5 minimum; Java/<java.version>)"}.
* <p/>
* For example:
* <pre>"Apache-HttpClient/4.3 (Java 1.5 minimum; Java/1.6.0_35)"</pre>
*
* @param name the component name, like "Apache-HttpClient".
* @param pkg
* the package for which to load version information, for example "ch.boye.httpclientandroidlib". The package name
* should NOT end with a dot.
* @param cls
* the class' class loader to load from, or <code>null</code> for the thread context class loader
* @since 4.3
*/
public static String getUserAgent(final String name, final String pkg, final Class<?> cls) {
// determine the release version from packaged version info
final VersionInfo vi = VersionInfo.loadVersionInfo(pkg, cls.getClassLoader());
final String release = (vi != null) ? vi.getRelease() : VersionInfo.UNAVAILABLE;
final String javaVersion = System.getProperty("java.version");
return name + "/" + release + " (Java 1.5 minimum; Java/" + javaVersion + ")";
}
} // class VersionInfo

View file

@ -0,0 +1,31 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
/**
* Core utility classes.
*/
package ch.boye.httpclientandroidlib.util;