package com.nimbusds.jose;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import net.minidev.json.JSONObject;
import net.jcip.annotations.Immutable;
import com.nimbusds.jose.util.Base64URL;
import com.nimbusds.jose.util.JSONObjectUtils;
/**
* Payload with JSON object, string, byte array and Base64URL views. Represents
* the original object that was signed with JWS or encrypted with JWE. This
* class is immutable.
*
* <p>Non-initial views are created on demand to conserve resources.
*
* <p>UTF-8 is the character set for all string from / to byte array
* conversions.
*
* <p>Conversion relations:
*
* <pre>
* JSONObject <=> String <=> Base64URL
* <=> byte[]
* </pre>
*
* @author Vladimir Dzhuvinov
* @version $version$ (2012-10-23)
*/
@Immutable
public class Payload {
/**
* Enumeration of the original data types used to create a
* {@link Payload}.
*/
public static enum Origin {
/**
* The payload was created from a JSON object.
*/
JSON,
/**
* The payload was created from a string.
*/
STRING,
/**
* The payload was created from a byte array.
*/
BYTE_ARRAY,
/**
* The payload was created from a Base64URL-encoded object.
*/
BASE64URL;
}
/**
* UTF-8 is the character set for all string from / to byte array
* conversions.
*/
private static final String CHARSET = "UTF-8";
/**
* The original payload data type.
*/
private Origin origin;
/**
* The JSON object view.
*/
private JSONObject jsonView = null;
/**
* The string view.
*/
private String stringView = null;
/**
* The byte array view.
*/
private byte[] bytesView = null;
/**
* The Base64URL view.
*/
private Base64URL base64URLView = null;
/**
* Converts a byte array to a string using {@link #CHARSET}.
*
* @param bytes The byte array to convert. May be {@code null}.
*
* @return The resulting string, {@code null} if conversion failed.
*/
private static String byteArrayToString(final byte[] bytes) {
if (bytes == null)
return null;
try {
return new String(bytes, CHARSET);
} catch (UnsupportedEncodingException e) {
// UTF-8 should always be supported
return null;
}
}
/**
* Converts a string to a byte array using {@link #CHARSET}.
*
* @param stirng The string to convert. May be {@code null}.
*
* @return The resulting byte array, {@code null} if conversion failed.
*/
private static byte[] stringToByteArray(final String string) {
if (string == null)
return null;
try {
return string.getBytes(CHARSET);
} catch (UnsupportedEncodingException e) {
// UTF-8 should always be supported
return null;
}
}
/**
* Creates a new payload from the specified JSON object.
*
* @param json The JSON object representing the payload. Must not be
* {@code null}.
*/
public Payload(final JSONObject json) {
if (json == null)
throw new IllegalArgumentException("The JSON object must not be null");
jsonView = json;
origin = Origin.JSON;
}
/**
* Creates a new payload from the specified string.
*
* @param string The string representing the payload. Must not be
* {@code null}.
*/
public Payload(final String string) {
if (string == null)
throw new IllegalArgumentException("The string must not be null");
stringView = string;
origin = Origin.STRING;
}
/**
* Creates a new payload from the specified byte array.
*
* @param bytes The byte array representing the payload. Must not be
* {@code null}.
*/
public Payload(final byte[] bytes) {
if (bytes == null)
throw new IllegalArgumentException("The byte array must not be null");
bytesView = bytes;
origin = Origin.BYTE_ARRAY;
}
/**
* Creates a new payload from the specified Base64URL-encoded object.
*
* @param base64URL The Base64URL-encoded object representing the
* payload. Must not be {@code null}.
*/
public Payload(final Base64URL base64URL) {
if (base64URL == null)
throw new IllegalArgumentException("The Base64URL-encoded object must not be null");
base64URLView = base64URL;
origin = Origin.BASE64URL;
}
/**
* Gets the original data type used to create this payload.
*
* @return The payload origin.
*/
public Origin getOrigin() {
return origin;
}
/**
* Returns a JSON object view of this payload.
*
* @return The JSON object view, {@code null} if the payload couldn't
* be converted to a JSON object.
*/
public JSONObject toJSONObject() {
if (jsonView != null)
return jsonView;
// Convert
if (stringView != null) {
try {
jsonView = JSONObjectUtils.parseJSONObject(stringView);
} catch (ParseException e) {
// jsonView remains null
}
}
else if (bytesView != null) {
stringView = byteArrayToString(bytesView);
try {
jsonView = JSONObjectUtils.parseJSONObject(stringView);
} catch (ParseException e) {
// jsonView remains null
}
}
else if (base64URLView != null) {
stringView = base64URLView.decodeToString();
try {
jsonView = JSONObjectUtils.parseJSONObject(stringView);
} catch (ParseException e) {
// jsonView remains null
}
}
return jsonView;
}
/**
* Returns a string view of this payload.
*
* @return The string view.
*/
public String toString() {
if (stringView != null)
return stringView;
// Convert
if (jsonView != null) {
stringView = jsonView.toString();
}
else if (bytesView != null) {
stringView = byteArrayToString(bytesView);
}
else if (base64URLView != null) {
stringView = base64URLView.decodeToString();
}
return stringView;
}
/**
* Returns a byte array view of this payload.
*
* @return The byte array view.
*/
public byte[] toBytes() {
if (bytesView != null)
return bytesView;
// Convert
if (stringView != null) {
bytesView = stringToByteArray(stringView);
}
else if (jsonView != null) {
stringView = jsonView.toString();
bytesView = stringToByteArray(stringView);
}
else if (base64URLView != null) {
bytesView = base64URLView.decode();
}
return bytesView;
}
/**
* Returns a Base64URL view of this payload.
*
* @return The Base64URL view.
*/
public Base64URL toBase64URL() {
if (base64URLView != null)
return base64URLView;
// Convert
if (stringView != null) {
base64URLView = Base64URL.encode(stringView);
}
else if (bytesView != null) {
base64URLView = Base64URL.encode(bytesView);
}
else if (jsonView != null) {
stringView = jsonView.toString();
base64URLView = Base64URL.encode(stringView);
}
return base64URLView;
}
}