PaymentInfopublic final class PaymentInfo extends Object This class represents the payment information read from the application
Manifest file or obtained from the associated update URL. |
Fields Summary |
---|
public static final int | AUTO_REQUEST_OFFA value indicating that the auto request mode is disabled. | public static final int | AUTO_REQUEST_ACCEPTA value indicating that the auto request mode is set to accept. | public static final int | AUTO_REQUEST_REJECTA value indicating that the auto request mode is set to reject. | private static final String | CURRENT_VERSIONThe version number of the JAR-Manifest fields. | private static final String | PAY_VERSIONPay version attribute name. | private static final String | PAY_ADAPTERSPay-adapters attribute name. | private static final String | PAY_DBG_DEMOMODEPay-Debug-DemoMode attribute name. | private static final String | PAY_DBG_FAILINITIALIZEPay-Debug-FailInitialize attribute name. | private static final String | PAY_DBG_FAILIOPay-Debug-FailIO attribute name. | private static final String | PAY_DBG_MISSEDTRANSACTIONSPay-Debug-MissedTransactions attribute name. | private static final String | PAY_DBG_RANDOMTESTSPay-Debug-RandomTests attribute name. | private static final String | PAY_DBG_AUTOREQUESTMODEPay-Debug-AutoRequestMode attribute name. | private static final String | PAY_DBG_NOADAPTERPay-Debug-NoAdapter attribute name. | private static final String | PAY_UPDATE_DATEPay-Update-Date attribute name. | private static final String | PAY_UPDATE_STAMPPay-Update-Stamp attribute name. | private static final String | PAY_UPDATE_URLPay-Update-URL attribute name. | private static final String | PAY_CACHEPay-Cache attribute name. | private static final String | PAY_PROVIDERSPay-Providers attribute name. | private static final String | PAY_PREFIXPrefix for constructing provider specific attribute name. | private static final String | PAY_FEATURE_PREFIXPrefix for constructing feature description attribute name. | private static final String | INFO_SUFFIXSuffix for constructing provider info attribute name. | private static final String | TAGSuffix for constructing price and payment specific information
attribute name. | private static final String | PAY_CERTIFICATE_PREFIXPay-Certificate-(n)-(m) attribute name prefix. | private static final String | PAY_SIGNATURE_PREFIXPay-Signature-XXX-XXX attribute name prefix. | private static final String | PAY_SIGNATURE_RSA_SHA1Pay-Signature-RSA-SHA1 attribute name. | private static final char[] | PKI_PREFIXESPKI prefixes are used for property strip. | private static final String[] | VALID_ADAPTER_NAMESList of supported adapters. | private static final String | YES_VALUEPointer to "yes" string. | private static final String | NO_VALUEPointer to "no" string. | private static final String[] | YES_NO_OPTIONSArray of options could only exist in payment attributes. | private static final String[] | ACCEPT_REJECT_OPTIONSArray of options can only exist in payment attributes. | private static final Utils | utilitiesInstance of Utils class | private String[] | adaptersList of MIDlet requested adapters. | private boolean | dbgDemoModePay-Debug-DemoMode attribute value. | private boolean | dbgFailInitializePay-Debug-FailInitialize attribute value. | private boolean | dbgFailIOPay-Debug-FailIO attribute value. | private int | dbgMissedTransactionsPay-Debug-MissedTransactions attribute value. | private boolean | dbgRandomTestsPay-Debug-RandomTests attribute value. | private int | dbgAutoRequestModePay-Debug-AutoRequestMode attribute value. | private Date | updateDatePay-Update-Date attribute value. | private Date | updateStampPay-Update-Stamp attibute value. | private String | updateURLPay-Update-URL attribute value. | private boolean | cachePay-Cache attribute value. | private Date | expirationDatePayment info expiration date. | private int[] | featureToTagArray of features price tags. | private ProviderInfo[] | providersList of MIDlet supported payment providers. |
Constructors Summary |
---|
private PaymentInfo()Default constructor.
|
Methods Summary |
---|
public boolean | cache()Returns true if the payment information should be stored
for the next time.
return cache;
| private void | checkPayVersion(java.lang.String payVersion)Parse and check the version number of the JAR-Manifest
or JAD fields.
double curVer;
double appVer;
payVersion = payVersion.trim();
// The format must be <major>.<minor>.
// First accepted version is 1.0
if ('1" > payVersion.charAt(0) ||
-1 == payVersion.indexOf('.") ||
2 > payVersion.length() - payVersion.indexOf('.") ) {
// unsupported payment version
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_VERSION, null);
}
try {
curVer = Float.parseFloat(CURRENT_VERSION);
appVer = Float.parseFloat(payVersion);
} catch ( NumberFormatException nfe ) {
// unsupported payment version
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_VERSION, null);
}
if (curVer < appVer) {
// unsupported payment version
throw new PaymentException(
PaymentException.UNSUPPORTED_PAYMENT_INFO,
PAY_VERSION, null);
}
| public static com.sun.j2me.payment.PaymentInfo | createFromProperties(com.sun.midp.util.Properties jadProperties, com.sun.midp.util.Properties jarProperties)Creates an instance of the PaymentInfo class. It reads
information from the provided JAD and Manifest properties.
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.loadFromJadProperties(jadProperties);
paymentInfo.loadFromJarProperties(jarProperties);
return paymentInfo;
| public void | export(java.io.Writer os)Exports the payment information into the given character output stream.
StringBuffer buffer = new StringBuffer();
// Pay-Version: 1.0
buffer.append(PAY_VERSION);
buffer.append(": ");
buffer.append(CURRENT_VERSION);
buffer.append("\n");
// Pay-Update-Date: <Date>
if (updateDate != null) {
buffer.append(PAY_UPDATE_DATE);
buffer.append(": ");
buffer.append(utilities.formatISODate(updateDate.getTime()));
buffer.append("\n");
}
// Pay-Update-Stamp: <Date>
buffer.append(PAY_UPDATE_STAMP);
buffer.append(": ");
buffer.append(utilities.formatISODate(updateStamp.getTime()));
buffer.append("\n");
// Pay-Update-URL: <UpdateURL>
buffer.append(PAY_UPDATE_URL);
buffer.append(": ");
buffer.append(updateURL);
buffer.append("\n");
// Pay-Cache: [yes|no|<Expiration-Date>]
buffer.append(PAY_CACHE);
buffer.append(": ");
if (expirationDate != null) {
buffer.append(utilities.formatISODate(expirationDate.getTime()));
} else {
buffer.append(cache ? YES_VALUE : NO_VALUE);
}
buffer.append("\n");
// Pay-Feature-<n>: <m>
for (int i = 0; i < featureToTag.length; ++i) {
buffer.append(PAY_FEATURE_PREFIX);
buffer.append(i);
buffer.append(": ");
buffer.append(featureToTag[i]);
buffer.append("\n");
}
os.write(buffer.toString());
buffer.setLength(0);
// Pay-Providers: <ProviderTitles>
buffer.append(PAY_PROVIDERS);
buffer.append(": ");
buffer.append(providers[0].getName());
for (int i = 1; i < providers.length; ++i) {
buffer.append(", ");
buffer.append(providers[i].getName());
}
buffer.append("\n");
for (int i = 0; i < providers.length; ++i) {
exportProvider(buffer, providers[i]);
}
os.write(buffer.toString());
| private void | exportProvider(java.lang.StringBuffer buffer, ProviderInfo provider)Exports the given provider information into the given
StringBuffer .
// Pay-<ProviderTitle>
String providerPrefix = PAY_PREFIX + provider.getName();
// Pay-<ProviderTitle>-Info: <RegAdapter>, <ISO4217CurrencyCode>,
// <PaymentSpecificInformation>
buffer.append(providerPrefix);
buffer.append(INFO_SUFFIX);
buffer.append(": ");
buffer.append(provider.getAdapter());
buffer.append(", ");
buffer.append(provider.getCurrency());
buffer.append(", ");
buffer.append(provider.getConfiguration());
buffer.append("\n");
// Pay-<ProviderTitle>-Tag-<m>: <Price>[,
// <PaymentSpecificPriceInformation>]
int count = provider.getNumPriceTags();
for (int i = 0; i < count; ++i) {
buffer.append(providerPrefix);
buffer.append(TAG);
buffer.append(i);
buffer.append(": ");
buffer.append(provider.getPrice(i));
String value = provider.getPaySpecificPriceInfo(i);
if (value != null) {
buffer.append(", ");
buffer.append(value);
}
buffer.append("\n");
}
| private static X509Certificate | findTrustedCertificate(com.sun.midp.util.Properties props)Finds a trusted provider certificate in one of the certification
chains read from the given properties.
int certPath = 1;
int certIndex = 1;
Vector certificates = new Vector();
String encodedCert = props.getProperty(PAY_CERTIFICATE_PREFIX +
certPath + "-" + certIndex);
if (encodedCert == null) {
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_CERTIFICATE_PREFIX + certPath + "-" + certIndex,
null);
}
do {
certificates.setSize(0);
do {
try {
byte[] binaryCert = Base64.decode(encodedCert);
certificates.addElement(X509Certificate.generateCertificate(
binaryCert, 0, binaryCert.length));
} catch (IOException e) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_CERTIFICATE_PREFIX + certPath + "-" + certIndex,
"invalid or unsupported certificate");
}
encodedCert = props.getProperty(PAY_CERTIFICATE_PREFIX +
certPath + "-" + ++certIndex);
} while (encodedCert != null);
try {
String[] authPath = X509Certificate.verifyChain(certificates,
X509Certificate.DIGITAL_SIG_KEY_USAGE,
X509Certificate.CODE_SIGN_EXT_KEY_USAGE,
WebPublicKeyStore.getTrustedKeyStore());
String domain = Permissions.UNIDENTIFIED_DOMAIN_BINDING;
Vector keys = WebPublicKeyStore.getTrustedKeyStore().
findKeys(authPath[0]);
if (keys != null) {
domain = ((PublicKeyInfo)keys.elementAt(0)).getDomain();
}
if (!Permissions.UNIDENTIFIED_DOMAIN_BINDING.equals(domain)) {
// we verified the chain
return (X509Certificate)certificates.elementAt(0);
}
// try next chain
} catch (CertificateException e) {
switch (e.getReason()) {
case CertificateException.UNRECOGNIZED_ISSUER:
// try next chain
break;
case CertificateException.EXPIRED:
case CertificateException.NOT_YET_VALID:
throw new PaymentException(
PaymentException.EXPIRED_PROVIDER_CERT,
e.getCertificate().getSubject(), null);
case CertificateException.ROOT_CA_EXPIRED:
throw new PaymentException(
PaymentException.EXPIRED_CA_CERT,
e.getCertificate().getIssuer(), null);
default:
throw new PaymentException(
PaymentException.INVALID_PROVIDER_CERT,
e.getCertificate().getSubject(), null);
}
}
certIndex = 1;
encodedCert = props.getProperty(PAY_CERTIFICATE_PREFIX +
++certPath + "-" + certIndex);
} while (encodedCert != null);
throw new PaymentException(PaymentException.NO_TRUSTED_CHAIN);
| public int | getDbgAutoRequestMode()Returns the debug auto request mode setting.
return dbgAutoRequestMode;
| public boolean | getDbgFailIO()Test for the debug fail IO mode.
return dbgFailIO;
| public boolean | getDbgFailInitialize()Test for the debug fail initialize mode.
return dbgFailInitialize;
| public int | getDbgMissedTransactions()Returns the number of fake missed transactions that should be generated
when the application starts.
return dbgMissedTransactions;
| public boolean | getDbgRandomTests()Test for the debug random tests mode.
return dbgRandomTests;
| public int | getNumFeatures()Gets the number of features the application can request the user to pay
for.
return featureToTag.length;
| public int | getNumProviders()Returns the number of providers which can be used to pay for the
application features.
return providers.length;
| public int | getPriceTagForFeature(int index)Returns the price tag for the given feature id.
return featureToTag[index];
| public ProviderInfo | getProvider(int index)Return the provider information for the given provider id.
return providers[index];
| public java.util.Date | getUpdateDate()Returns the date of the last update or null if the payment
information has been never updated.
return updateDate;
| public java.util.Date | getUpdateStamp()Gets the time stamp of last update.
return updateStamp;
| public java.lang.String | getUpdateURL()Returns the URL of the payment update.
return updateURL;
| private boolean | hasDuplicates(java.util.Vector vector)Returns true if the given vector contains duplicate values.
int lastIndex = vector.size() - 1;
for (int i = 0; i < lastIndex; ++i) {
if (vector.indexOf(vector.elementAt(i), i + 1) != -1) {
return true;
}
}
return false;
| private native boolean | isDebugMode()Test for the system debug mode.
| public boolean | isDemoMode()Test for the debug demo mode.
return dbgDemoMode && isDebugMode();
| private void | loadFromJadProperties(com.sun.midp.util.Properties props)Updates the payment information from the given JAD file properties.
If an exception is thrown during the update the original object state
remains intact.
String payVersion = props.getProperty(PAY_VERSION);
String payAdapters = props.getProperty(PAY_ADAPTERS);
if (payVersion != null) {
checkPayVersion(payVersion);
if (payAdapters == null) {
// missing PAY_ADAPTERS attribute
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_ADAPTERS, null);
}
} else {
if (payAdapters != null) {
// missing PAY_VERSION attribute
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_VERSION, null);
}
}
String[] adapters = null;
// read & validate adapters
if (payVersion != null) {
Vector names = Util.getCommaSeparatedValues(payAdapters);
if (names.size() == 0) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_ADAPTERS, "the value is empty");
}
// avoid duplicate names
if (hasDuplicates(names)) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_ADAPTERS, "duplicate fields in the value");
}
adapters = toStringArray(names);
// validate adapter names
for (int i = 0; i < adapters.length; ++i) {
if (!validateAdapterName(adapters[i])) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_ADAPTERS, adapters[i] + " is not a valid " +
"adapter name");
}
}
// validate supported adapters
PaymentModule paymentModule = PaymentModule.getInstance();
int j;
for (j = 0; j < adapters.length; ++j) {
if (paymentModule.isSupportedAdapter(adapters[j])) {
break;
}
}
if (j == adapters.length) {
throw new PaymentException(
PaymentException.UNSUPPORTED_ADAPTERS,
PAY_ADAPTERS, null);
}
}
// read and validate Pay-Debug-* attributes
boolean dbgDemoMode = readOptionalSelection(props,
PAY_DBG_DEMOMODE, YES_NO_OPTIONS, 1) != 1;
boolean dbgFailInitialize = readOptionalSelection(props,
PAY_DBG_FAILINITIALIZE, YES_NO_OPTIONS, 1) != 1;
boolean dbgFailIO = readOptionalSelection(props,
PAY_DBG_FAILIO, YES_NO_OPTIONS, 1) != 1;
int dbgMissedTransactions = -1;
boolean dbgRandomTests = readOptionalSelection(props,
PAY_DBG_RANDOMTESTS, YES_NO_OPTIONS, 1) != 1;
int dbgAutoRequestMode = readOptionalSelection(props,
PAY_DBG_AUTOREQUESTMODE, ACCEPT_REJECT_OPTIONS, -1) + 1;
// Peyment spec 1.1
// It is not used yet, but need for TCK passing
boolean dbgNoAdapter = readOptionalSelection(props,
PAY_DBG_NOADAPTER, YES_NO_OPTIONS, 1) != 1;
String dbgMissedTransactionsStr = props.getProperty(
PAY_DBG_MISSEDTRANSACTIONS);
if (dbgMissedTransactionsStr != null) {
try {
dbgMissedTransactions = Integer.parseInt(
dbgMissedTransactionsStr);
} catch (NumberFormatException e) {
}
if (dbgMissedTransactions < 0) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_DBG_MISSEDTRANSACTIONS,
"expecting a positive number");
}
}
// everything is correct, let's change the object state
this.adapters = adapters;
this.dbgDemoMode = dbgDemoMode;
this.dbgFailInitialize = dbgFailInitialize;
this.dbgFailIO = dbgFailIO;
this.dbgMissedTransactions = dbgMissedTransactions;
this.dbgRandomTests = dbgRandomTests;
this.dbgAutoRequestMode = dbgAutoRequestMode;
| private void | loadFromJarProperties(com.sun.midp.util.Properties props)Updates the payment information from the given Manifest properties. If
an exception is thrown during the update the original object state
remains intact.
loadFromPropertiesAux(props, false);
// load the update date
String tempValue = props.getProperty(PAY_UPDATE_DATE);
updateDate = null;
if (tempValue != null) {
try {
long millis = utilities.parseISODate(tempValue);
updateDate = new Date(millis);
} catch (IllegalArgumentException e) {
}
}
| private void | loadFromJppProperties(com.sun.midp.util.Properties props)Updates the payment information from the given update file properties.
If an exception is thrown during the update the original object state
remains intact.
loadFromPropertiesAux(props, true);
| private void | loadFromPropertiesAux(com.sun.midp.util.Properties props, boolean strict)Loads the payment information from the given Manifest properties or
update file properties. The strict indicates if the
additional tests should be executed on the data read from the properties.
After passing these additional tests the resulting payment information
can be used for payment without any further update. Should an exception
be thrown during the loading the object state will remain intact.
String tempValue;
long currentTime = System.currentTimeMillis();
tempValue = props.getProperty(PAY_VERSION);
if (tempValue == null) {
// missing PAY_VERSION attribute
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_VERSION, null);
}
// throws Payment exception
// if app pay version is greater than stack version
checkPayVersion(tempValue);
tempValue = props.getProperty(PAY_UPDATE_STAMP);
Date updateStamp;
if (tempValue == null) {
// missing PAY_UPDATE_STAMP attribute
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_UPDATE_STAMP, null);
}
// parse and validate the date
try {
long millis = utilities.parseISODate(tempValue);
if (millis > currentTime) {
throw new PaymentException(
PaymentException.INFORMATION_NOT_YET_VALID);
}
updateStamp = new Date(millis);
} catch (IllegalArgumentException e) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_UPDATE_STAMP, e.getMessage());
}
String updateURL = props.getProperty(PAY_UPDATE_URL);
if (updateURL == null) {
// missing PAY_UPDATE_URL attribute
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_UPDATE_URL, null);
}
// validate the URL
try {
HttpUrl tempURL = new HttpUrl(updateURL);
if (!"http".equals(tempURL.scheme) &&
!"https".equals(tempURL.scheme)) {
throw new PaymentException(
PaymentException.UNSUPPORTED_URL_SCHEME,
tempURL.scheme, null);
}
} catch (IllegalArgumentException e) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_UPDATE_URL, e.getMessage());
}
tempValue = props.getProperty(PAY_CACHE);
boolean cache = true;
Date expirationDate = null;
// validate and parse the PAY_CACHE attribute
if (tempValue != null) {
if (YES_VALUE.equals(tempValue)) {
cache = true;
} else if (NO_VALUE.equals(tempValue)) {
cache = false;
} else {
try {
long millis = utilities.parseISODate(tempValue);
if (strict && (millis < currentTime)) {
throw new PaymentException(
PaymentException.INFORMATION_EXPIRED);
}
expirationDate = new Date(millis);
} catch (IllegalArgumentException e) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_CACHE, "expecting yes, no or a valid date");
}
}
}
Vector tempVector = new Vector();
tempValue = props.getProperty(PAY_FEATURE_PREFIX + 0);
if (tempValue == null) {
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_FEATURE_PREFIX + 0, null);
}
// read Pay-Feature-<n>
int index = 0;
tempVector.setSize(0);
do {
tempVector.addElement(tempValue);
tempValue = props.getProperty(PAY_FEATURE_PREFIX + ++index);
} while (tempValue != null);
int maxTag = 0;
int[] featureToTag = new int[index];
// parse and validate the numbers
for (int i = 0; i < index; ++i) {
int value = -1;
try {
value = Integer.parseInt((String)tempVector.elementAt(i));
} catch (NumberFormatException e) {
}
if (value < 0) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_FEATURE_PREFIX + i, "expecting a positive number");
}
if (maxTag < value) {
maxTag = value;
}
featureToTag[i] = value;
}
tempValue = props.getProperty(PAY_PROVIDERS);
if (tempValue == null) {
// missing PAY_PROVIDERS attribute
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_PROVIDERS, null);
}
Vector names = Util.getCommaSeparatedValues(tempValue);
if (names.size() == 0) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_PROVIDERS, "the value is empty");
}
// avoid duplicate names
if (hasDuplicates(names)) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_PROVIDERS, "duplicate fields in the value");
}
// IMPL_NOTE: check provider name?
ProviderInfo[] providers = new ProviderInfo[names.size()];
int numTags = maxTag + 1;
boolean hasSupportedProvider = false;
PaymentModule paymentModule = PaymentModule.getInstance();
// read and validate provider infos
for (int i = 0; i < providers.length; ++i) {
// read provider
ProviderInfo provider = loadProvider(
props, (String)names.elementAt(i));
if ((strict || (provider.getNumPriceTags() != 0))
&& (provider.getNumPriceTags() < numTags)) {
throw new PaymentException(
PaymentException.INCOMPLETE_INFORMATION);
}
// try to create an adapter for the provider
PaymentAdapter adapter;
try {
adapter = paymentModule.getAdapter(provider.getAdapter(),
provider.getConfiguration());
} catch (PaymentException e) {
e.setParam(PAY_PREFIX + provider.getName() + INFO_SUFFIX);
throw e;
}
if (adapter != null) {
// adapter has been created == we support at least one payment
// provider
hasSupportedProvider = true;
int numTags2 = provider.getNumPriceTags();
for (int j = 0; j < numTags2; ++j) {
try {
adapter.validatePriceInfo(provider.getPrice(j),
provider.getPaySpecificPriceInfo(j));
} catch (PaymentException e) {
e.setParam(PAY_PREFIX + provider.getName() + TAG + j);
throw e;
}
}
}
providers[i] = provider;
}
if (!hasSupportedProvider) {
throw new PaymentException(
PaymentException.UNSUPPORTED_PROVIDERS,
PAY_PROVIDERS, null);
}
// everything is correct, let's change the object state
this.updateStamp = updateStamp;
this.updateURL = updateURL;
this.cache = cache;
this.expirationDate = expirationDate;
this.featureToTag = featureToTag;
this.providers = providers;
| private ProviderInfo | loadProvider(com.sun.midp.util.Properties props, java.lang.String provider)Parses and returns the provider information for the given provider name
from the properties.
String tempValue;
String tempKey = PAY_PREFIX + provider + INFO_SUFFIX;
tempValue = props.getProperty(tempKey);
if (tempValue == null) {
// missing or incorrect provider
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
tempKey, null);
}
int offset = 0;
int index;
index = tempValue.indexOf(',");
if (index == -1) {
// missing currency code
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
tempKey, "the currency code is not present");
}
String adapter = tempValue.substring(offset, index).trim();
// validate adapter name
if (!validateAdapterName(adapter)) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
tempKey, adapter + " is not a valid adapter name");
}
offset = index + 1;
index = tempValue.indexOf(',", offset);
String currency;
if (index == -1) {
currency = tempValue.substring(offset).trim();
} else {
currency = tempValue.substring(offset, index).trim();
}
// validate currency
if (!validateCurrencyCode(currency)) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
tempKey, "not a valid currency code");
}
// get configuration
String configuration;
if (index == -1) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
tempKey, "the payment specific info is not present");
}
offset = index + 1;
configuration = tempValue.substring(offset).trim();
tempKey = PAY_PREFIX + provider + TAG;
tempValue = props.getProperty(tempKey + 0);
double[] prices = null;
String[] paySpecificPriceInfo = null;
if (tempValue != null) {
// contains tag attributes
int numTags = 0;
Vector tempVector = new Vector();
do {
tempVector.addElement(tempValue);
tempValue = props.getProperty(tempKey + ++numTags);
} while (tempValue != null);
// we know the number of tags
prices = new double[numTags];
paySpecificPriceInfo = new String[numTags];
for (int i = 0; i < numTags; ++i) {
tempValue = (String)tempVector.elementAt(i);
index = tempValue.indexOf(',");
// parse and validate the price
try {
String tempPrice;
if (index == -1) {
tempPrice = tempValue.trim();
} else {
tempPrice = tempValue.substring(0, index).trim();
}
prices[i] = Double.parseDouble(tempPrice);
} catch (NumberFormatException e) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
tempKey + i, "invalid price");
}
// get pay specific price info if present
if (index != -1) {
paySpecificPriceInfo[i] =
tempValue.substring(index + 1).trim();
}
}
}
// everything is correct, create the object
return new ProviderInfo(provider, adapter, configuration, currency,
prices, paySpecificPriceInfo);
| public boolean | needsUpdate()Test if the payment information can be used for payment as is or it
needs to be updated first from the update URL.
// 1. no cache => update
if (!cache) {
return true;
}
// 2. expired cache => update
if (expirationDate != null) {
long currentTime = System.currentTimeMillis();
if (currentTime > expirationDate.getTime()) {
return true;
}
}
// 3. missing tags => update
for (int i = 0; i < providers.length; ++i) {
if (providers[i].getNumPriceTags() == 0) {
return true;
}
}
return false;
| private int | readOptionalSelection(com.sun.midp.util.Properties props, java.lang.String attribute, java.lang.String[] options, int defValue)Parses an attribute which can have only one of the given predefined
values. It returns the index of the attribute's value or the
defValue if the attribute is not defined.
String value = props.getProperty(attribute);
if (value == null) {
return defValue;
}
for (int i = 0; i < options.length; ++i) {
if (options[i].equals(value)) {
return i;
}
}
StringBuffer buffer = new StringBuffer();
buffer.append("expecting ");
buffer.append(options[0]);
int i;
for (i = 1; i < (options.length - 1); ++i) {
buffer.append(", ");
buffer.append(options[i]);
}
buffer.append(" or ");
buffer.append(options[i]);
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
attribute, buffer.toString());
| private static java.lang.String | removePKIProperties(java.lang.String string)Strips all empty lines and lines containing any of
Pay-Certificate-* or Pay-Signature-*
attributes from the given string.
char[] data = string.toCharArray();
int length = data.length;
StringBuffer buffer = new StringBuffer();
int i = 0;
int j, k;
do {
// skip empty lines
for (j = i; (j < length) && (data[j] != '\n") && (data[j] <= ' ");
++j) {
}
if (j == length) {
break;
}
if (data[j] == '\n") {
i = j + 1;
continue;
}
// find matching prefix
int prefixIdx;
for (prefixIdx = 0; prefixIdx < PKI_PREFIXES.length; ++prefixIdx) {
char[] prefix = PKI_PREFIXES[prefixIdx];
for (k = 0, j = i; (j < length) && (k < prefix.length) &&
(data[j] == prefix[k]); ++j, ++k) {
}
if (k == prefix.length) {
break;
}
}
// find the end of the line
for (j = i; (j < length) && (data[j] != '\n"); ++j) {
}
if (j < length) {
// skip '\n'
++j;
}
// accept the lines that don't start with any of PKI_PREFIXES
if (prefixIdx == PKI_PREFIXES.length) {
buffer.append(data, i, j - i);
}
i = j;
} while (i < length);
return buffer.toString();
| private java.lang.String[] | toStringArray(java.util.Vector vector)Constructs an string array from the given vector of strings. The
resulting array will contain the same strings as the vector and in the
same order as appeared in the vector.
String[] strings = new String[vector.size()];
vector.copyInto(strings);
return strings;
| public void | updatePaymentInfo(byte[] data, java.lang.String charset)Validates the given payment update and if correct it updates the internal
state of the object accordingly.
Properties props;
InputStream bis = new ByteArrayInputStream(data);
try {
try {
props = utilities.loadProperties(bis, charset);
} finally {
bis.close();
}
} catch (UnsupportedEncodingException e) {
throw new PaymentException(
PaymentException.UNSUPPORTED_UPDATE_CHARSET,
charset, null);
} catch (IOException e) {
throw new PaymentException(
PaymentException.INVALID_PROPERTIES_FORMAT,
e.getMessage());
}
// find a trusted provider certificate in one of the certification
// chains of the payment update
X509Certificate trustedCertificate = findTrustedCertificate(
props);
// get the public key for the trusted certificate
PublicKey publicKey;
try {
publicKey = trustedCertificate.getPublicKey();
} catch (CertificateException e) {
throw new PaymentException(
PaymentException.INVALID_PROVIDER_CERT,
trustedCertificate.getSubject(), null);
}
// get the encoded signature
String encodedSignature = props.getProperty(PAY_SIGNATURE_RSA_SHA1);
if (encodedSignature == null) {
throw new PaymentException(
PaymentException.MISSING_MANDATORY_ATTRIBUTE,
PAY_SIGNATURE_RSA_SHA1, null);
}
byte[] signature;
try {
signature = Base64.decode(encodedSignature);
} catch (IOException e) {
throw new PaymentException(
PaymentException.INVALID_ATTRIBUTE_VALUE,
PAY_SIGNATURE_RSA_SHA1, "invalid or unsupported signature");
}
// get the data for verification
String propString;
byte[] testData;
try {
propString = new String(data, charset);
testData = removePKIProperties(propString).getBytes(charset);
} catch (UnsupportedEncodingException e) {
throw new PaymentException(
PaymentException.UNSUPPORTED_UPDATE_CHARSET,
charset, null);
}
// verify the signature
try {
Signature sigVerifier = Signature.getInstance("SHA1withRSA");
sigVerifier.initVerify(publicKey);
sigVerifier.update(testData, 0, testData.length);
if (!sigVerifier.verify(signature)) {
throw new PaymentException(
PaymentException.SIGNATURE_VERIFICATION_FAILED);
}
} catch (GeneralSecurityException e) {
throw new PaymentException(
PaymentException.SIGNATURE_VERIFICATION_FAILED);
}
// validate and accept new values
loadFromJppProperties(props);
updateDate = new Date();
| private boolean | validateAdapterName(java.lang.String name)Returns true if the given name is a valid adapter name.
if (name.startsWith("X-")) {
return name.length() > 2;
}
for (int i = 0; i < VALID_ADAPTER_NAMES.length; ++i) {
if (VALID_ADAPTER_NAMES[i].equals(name)) {
return true;
}
}
return false;
| private boolean | validateCurrencyCode(java.lang.String name)Returns true if the given string value represents a valid
currency code.
if (name.length() != 3) {
return false;
}
for (int i = 0; i < 3; ++i) {
if ((name.charAt(i) < 'A") ||
(name.charAt(i) > 'Z")) {
return false;
}
}
return true;
| public static void | validateJadProperties(com.sun.midp.util.Properties jadProperties)Validates JAD properties.
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.loadFromJadProperties(jadProperties);
|
|