Source Code Cross Referenced for PaymentInfo.java in  » 6.0-JDK-Modules » j2me » com » sun » j2me » payment » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » j2me » com.sun.j2me.payment 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         *   
0003:         *
0004:         * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
0005:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006:         * 
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License version
0009:         * 2 only, as published by the Free Software Foundation.
0010:         * 
0011:         * This program is distributed in the hope that it will be useful, but
0012:         * WITHOUT ANY WARRANTY; without even the implied warranty of
0013:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014:         * General Public License version 2 for more details (a copy is
0015:         * included at /legal/license.txt).
0016:         * 
0017:         * You should have received a copy of the GNU General Public License
0018:         * version 2 along with this work; if not, write to the Free Software
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020:         * 02110-1301 USA
0021:         * 
0022:         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023:         * Clara, CA 95054 or visit www.sun.com if you need additional
0024:         * information or have any questions.
0025:         */
0026:
0027:        package com.sun.j2me.payment;
0028:
0029:        import java.util.Date;
0030:        import java.util.Vector;
0031:
0032:        import java.io.Writer;
0033:        import java.io.InputStream;
0034:        import java.io.ByteArrayInputStream;
0035:        import java.io.IOException;
0036:        import java.io.UnsupportedEncodingException;
0037:
0038:        import com.sun.midp.util.Properties;
0039:        import com.sun.midp.io.HttpUrl;
0040:        import com.sun.midp.io.Util;
0041:        import com.sun.midp.io.Base64;
0042:
0043:        import com.sun.midp.crypto.*;
0044:        import com.sun.midp.pki.*;
0045:        import com.sun.midp.security.*;
0046:        import com.sun.midp.publickeystore.*;
0047:
0048:        import javax.microedition.pki.CertificateException;
0049:
0050:        /**
0051:         * This class represents the payment information read from the application 
0052:         * Manifest file or obtained from the associated update URL.
0053:         *
0054:         * @version 1.11
0055:         */
0056:        public final class PaymentInfo {
0057:
0058:            /** A value indicating that the auto request mode is disabled. */
0059:            public static final int AUTO_REQUEST_OFF = 0;
0060:            /** A value indicating that the auto request mode is set to accept. */
0061:            public static final int AUTO_REQUEST_ACCEPT = 1;
0062:            /** A value indicating that the auto request mode is set to reject. */
0063:            public static final int AUTO_REQUEST_REJECT = 2;
0064:
0065:            /** The version number of the JAR-Manifest fields. */
0066:            private static final String CURRENT_VERSION = System
0067:                    .getProperty("microedition.payment.version");
0068:            /** Pay version attribute name. */
0069:            private static final String PAY_VERSION = "Pay-Version";
0070:            /** Pay-adapters attribute name. */
0071:            private static final String PAY_ADAPTERS = "Pay-Adapters";
0072:            /** Pay-Debug-DemoMode attribute name. */
0073:            private static final String PAY_DBG_DEMOMODE = "Pay-Debug-DemoMode";
0074:            /** Pay-Debug-FailInitialize attribute name. */
0075:            private static final String PAY_DBG_FAILINITIALIZE = "Pay-Debug-FailInitialize";
0076:            /** Pay-Debug-FailIO attribute name. */
0077:            private static final String PAY_DBG_FAILIO = "Pay-Debug-FailIO";
0078:            /** Pay-Debug-MissedTransactions attribute name. */
0079:            private static final String PAY_DBG_MISSEDTRANSACTIONS = "Pay-Debug-MissedTransactions";
0080:            /** Pay-Debug-RandomTests attribute name. */
0081:            private static final String PAY_DBG_RANDOMTESTS = "Pay-Debug-RandomTests";
0082:            /** Pay-Debug-AutoRequestMode attribute name. */
0083:            private static final String PAY_DBG_AUTOREQUESTMODE = "Pay-Debug-AutoRequestMode";
0084:            /** Pay-Debug-NoAdapter attribute name. */
0085:            private static final String PAY_DBG_NOADAPTER = "Pay-Debug-NoAdapter";
0086:            /** Pay-Update-Date attribute name. */
0087:            private static final String PAY_UPDATE_DATE = "Pay-Update-Date";
0088:            /** Pay-Update-Stamp attribute name. */
0089:            private static final String PAY_UPDATE_STAMP = "Pay-Update-Stamp";
0090:            /** Pay-Update-URL attribute name. */
0091:            private static final String PAY_UPDATE_URL = "Pay-Update-URL";
0092:            /** Pay-Cache attribute name. */
0093:            private static final String PAY_CACHE = "Pay-Cache";
0094:            /** Pay-Providers attribute name. */
0095:            private static final String PAY_PROVIDERS = "Pay-Providers";
0096:            /** Prefix for constructing provider specific attribute name. */
0097:            private static final String PAY_PREFIX = "Pay-";
0098:            /** Prefix for constructing feature description attribute name. */
0099:            private static final String PAY_FEATURE_PREFIX = "Pay-Feature-";
0100:            /** Suffix for constructing provider info attribute name. */
0101:            private static final String INFO_SUFFIX = "-Info";
0102:            /** 
0103:             * Suffix for constructing price and payment specific information
0104:             * attribute name. 
0105:             */
0106:            private static final String TAG = "-Tag-";
0107:            /** Pay-Certificate-(n)-(m) attribute name prefix. */
0108:            private static final String PAY_CERTIFICATE_PREFIX = "Pay-Certificate-";
0109:            /** Pay-Signature-XXX-XXX attribute name prefix. */
0110:            private static final String PAY_SIGNATURE_PREFIX = "Pay-Signature-";
0111:            /** Pay-Signature-RSA-SHA1 attribute name. */
0112:            private static final String PAY_SIGNATURE_RSA_SHA1 = "Pay-Signature-RSA-SHA1";
0113:            /** PKI prefixes are used for property strip. */
0114:            private static final char[][] PKI_PREFIXES = {
0115:                    PAY_CERTIFICATE_PREFIX.toCharArray(),
0116:                    PAY_SIGNATURE_PREFIX.toCharArray() };
0117:            /** List of supported adapters. */
0118:            private static final String[] VALID_ADAPTER_NAMES = { "PPSMS" };
0119:            /** Pointer to "yes" string. */
0120:            private static final String YES_VALUE = "yes";
0121:            /** Pointer to "no" string. */
0122:            private static final String NO_VALUE = "no";
0123:            /** Array of options could only exist in payment attributes. */
0124:            private static final String[] YES_NO_OPTIONS = { YES_VALUE,
0125:                    NO_VALUE };
0126:            /** Array of options can only exist in payment attributes. */
0127:            private static final String[] ACCEPT_REJECT_OPTIONS = { "accept",
0128:                    "reject" };
0129:            /** Instance of Utils class */
0130:            private static final Utils utilities = PaymentModule.getInstance()
0131:                    .getUtilities();
0132:
0133:            /** List of MIDlet requested adapters. */
0134:            private String[] adapters;
0135:            /** Pay-Debug-DemoMode attribute value. */
0136:            private boolean dbgDemoMode;
0137:            /** Pay-Debug-FailInitialize attribute value. */
0138:            private boolean dbgFailInitialize;
0139:            /** Pay-Debug-FailIO attribute value. */
0140:            private boolean dbgFailIO;
0141:            /** Pay-Debug-MissedTransactions attribute value. */
0142:            private int dbgMissedTransactions;
0143:            /** Pay-Debug-RandomTests attribute value. */
0144:            private boolean dbgRandomTests;
0145:            /** Pay-Debug-AutoRequestMode attribute value. */
0146:            private int dbgAutoRequestMode;
0147:            /** Pay-Update-Date attribute value. */
0148:            private Date updateDate;
0149:            /** Pay-Update-Stamp attibute value. */
0150:            private Date updateStamp;
0151:            /** Pay-Update-URL attribute value. */
0152:            private String updateURL;
0153:            /** Pay-Cache attribute value. */
0154:            private boolean cache;
0155:            /** Payment info expiration date. */
0156:            private Date expirationDate;
0157:            /** Array of features price tags. */
0158:            private int[] featureToTag;
0159:            /** List of MIDlet supported payment providers. */
0160:            private ProviderInfo[] providers;
0161:
0162:            /** Default constructor. */
0163:            private PaymentInfo() {
0164:            }
0165:
0166:            /**
0167:             * Creates an instance of the <code>PaymentInfo</code> class. It reads
0168:             * information from the provided JAD and Manifest properties.
0169:             *
0170:             * @param jadProperties the JAD properties
0171:             * @param jarProperties the Manifest properties
0172:             * @return the instance of the <code>PaymentInfo</code> class
0173:             * @throws PaymentException if some of the properties are incorrect, 
0174:             *      incomplete, unsupported, etc.
0175:             */
0176:            public static PaymentInfo createFromProperties(
0177:                    Properties jadProperties, Properties jarProperties)
0178:                    throws PaymentException {
0179:                PaymentInfo paymentInfo = new PaymentInfo();
0180:
0181:                paymentInfo.loadFromJadProperties(jadProperties);
0182:                paymentInfo.loadFromJarProperties(jarProperties);
0183:
0184:                return paymentInfo;
0185:            }
0186:
0187:            /**
0188:             * Validates JAD properties.
0189:             *
0190:             * @param jadProperties the JAD properties
0191:             * @throws PaymentException if some of the properties are incorrect, 
0192:             *      incomplete, unsupported, etc.
0193:             */
0194:            public static void validateJadProperties(Properties jadProperties)
0195:                    throws PaymentException {
0196:                PaymentInfo paymentInfo = new PaymentInfo();
0197:                paymentInfo.loadFromJadProperties(jadProperties);
0198:            }
0199:
0200:            /**
0201:             * Validates the given payment update and if correct it updates the internal
0202:             * state of the object accordingly.
0203:             *
0204:             * @param data a byte array which contains the payment update
0205:             * @param charset the character set of the payment update
0206:             * @throws PaymentException if the payment update is incorrect
0207:             */
0208:            public void updatePaymentInfo(byte[] data, String charset)
0209:                    throws PaymentException {
0210:                Properties props;
0211:
0212:                InputStream bis = new ByteArrayInputStream(data);
0213:                try {
0214:                    try {
0215:                        props = utilities.loadProperties(bis, charset);
0216:                    } finally {
0217:                        bis.close();
0218:                    }
0219:                } catch (UnsupportedEncodingException e) {
0220:                    throw new PaymentException(
0221:                            PaymentException.UNSUPPORTED_UPDATE_CHARSET,
0222:                            charset, null);
0223:                } catch (IOException e) {
0224:                    throw new PaymentException(
0225:                            PaymentException.INVALID_PROPERTIES_FORMAT, e
0226:                                    .getMessage());
0227:                }
0228:
0229:                // find a trusted provider certificate in one of the certification 
0230:                // chains of the payment update
0231:                X509Certificate trustedCertificate = findTrustedCertificate(props);
0232:
0233:                // get the public key for the trusted certificate
0234:                PublicKey publicKey;
0235:                try {
0236:                    publicKey = trustedCertificate.getPublicKey();
0237:                } catch (CertificateException e) {
0238:                    throw new PaymentException(
0239:                            PaymentException.INVALID_PROVIDER_CERT,
0240:                            trustedCertificate.getSubject(), null);
0241:                }
0242:
0243:                // get the encoded signature
0244:                String encodedSignature = props
0245:                        .getProperty(PAY_SIGNATURE_RSA_SHA1);
0246:                if (encodedSignature == null) {
0247:                    throw new PaymentException(
0248:                            PaymentException.MISSING_MANDATORY_ATTRIBUTE,
0249:                            PAY_SIGNATURE_RSA_SHA1, null);
0250:                }
0251:
0252:                byte[] signature;
0253:                try {
0254:                    signature = Base64.decode(encodedSignature);
0255:                } catch (IOException e) {
0256:                    throw new PaymentException(
0257:                            PaymentException.INVALID_ATTRIBUTE_VALUE,
0258:                            PAY_SIGNATURE_RSA_SHA1,
0259:                            "invalid or unsupported signature");
0260:                }
0261:
0262:                // get the data for verification
0263:                String propString;
0264:                byte[] testData;
0265:
0266:                try {
0267:                    propString = new String(data, charset);
0268:                    testData = removePKIProperties(propString)
0269:                            .getBytes(charset);
0270:                } catch (UnsupportedEncodingException e) {
0271:                    throw new PaymentException(
0272:                            PaymentException.UNSUPPORTED_UPDATE_CHARSET,
0273:                            charset, null);
0274:                }
0275:
0276:                // verify the signature
0277:                try {
0278:                    Signature sigVerifier = Signature
0279:                            .getInstance("SHA1withRSA");
0280:
0281:                    sigVerifier.initVerify(publicKey);
0282:
0283:                    sigVerifier.update(testData, 0, testData.length);
0284:                    if (!sigVerifier.verify(signature)) {
0285:                        throw new PaymentException(
0286:                                PaymentException.SIGNATURE_VERIFICATION_FAILED);
0287:                    }
0288:                } catch (GeneralSecurityException e) {
0289:                    throw new PaymentException(
0290:                            PaymentException.SIGNATURE_VERIFICATION_FAILED);
0291:                }
0292:
0293:                // validate and accept new values
0294:                loadFromJppProperties(props);
0295:                updateDate = new Date();
0296:            }
0297:
0298:            /**
0299:             * Exports the payment information into the given character output stream.
0300:             *
0301:             * @param os the output stream
0302:             * @throws IOException indicates an output error
0303:             */
0304:            public void export(Writer os) throws IOException {
0305:                StringBuffer buffer = new StringBuffer();
0306:
0307:                // Pay-Version: 1.0
0308:                buffer.append(PAY_VERSION);
0309:                buffer.append(": ");
0310:                buffer.append(CURRENT_VERSION);
0311:                buffer.append("\n");
0312:
0313:                // Pay-Update-Date: <Date>
0314:                if (updateDate != null) {
0315:                    buffer.append(PAY_UPDATE_DATE);
0316:                    buffer.append(": ");
0317:                    buffer
0318:                            .append(utilities.formatISODate(updateDate
0319:                                    .getTime()));
0320:                    buffer.append("\n");
0321:                }
0322:
0323:                // Pay-Update-Stamp: <Date>
0324:                buffer.append(PAY_UPDATE_STAMP);
0325:                buffer.append(": ");
0326:                buffer.append(utilities.formatISODate(updateStamp.getTime()));
0327:                buffer.append("\n");
0328:
0329:                // Pay-Update-URL: <UpdateURL>
0330:                buffer.append(PAY_UPDATE_URL);
0331:                buffer.append(": ");
0332:                buffer.append(updateURL);
0333:                buffer.append("\n");
0334:
0335:                // Pay-Cache: [yes|no|<Expiration-Date>]
0336:                buffer.append(PAY_CACHE);
0337:                buffer.append(": ");
0338:                if (expirationDate != null) {
0339:                    buffer.append(utilities.formatISODate(expirationDate
0340:                            .getTime()));
0341:                } else {
0342:                    buffer.append(cache ? YES_VALUE : NO_VALUE);
0343:                }
0344:                buffer.append("\n");
0345:
0346:                // Pay-Feature-<n>: <m>
0347:                for (int i = 0; i < featureToTag.length; ++i) {
0348:                    buffer.append(PAY_FEATURE_PREFIX);
0349:                    buffer.append(i);
0350:                    buffer.append(": ");
0351:                    buffer.append(featureToTag[i]);
0352:                    buffer.append("\n");
0353:                }
0354:
0355:                os.write(buffer.toString());
0356:                buffer.setLength(0);
0357:
0358:                // Pay-Providers: <ProviderTitles>
0359:                buffer.append(PAY_PROVIDERS);
0360:                buffer.append(": ");
0361:                buffer.append(providers[0].getName());
0362:                for (int i = 1; i < providers.length; ++i) {
0363:                    buffer.append(", ");
0364:                    buffer.append(providers[i].getName());
0365:                }
0366:                buffer.append("\n");
0367:
0368:                for (int i = 0; i < providers.length; ++i) {
0369:                    exportProvider(buffer, providers[i]);
0370:                }
0371:
0372:                os.write(buffer.toString());
0373:            }
0374:
0375:            /**
0376:             * Test if the payment information can be used for payment as is or it
0377:             * needs to be updated first from the update URL.
0378:             *
0379:             * @return <code>true</code> if the payment information needs to be updated
0380:             */
0381:            public boolean needsUpdate() {
0382:                // 1. no cache => update
0383:                if (!cache) {
0384:                    return true;
0385:                }
0386:
0387:                // 2. expired cache => update
0388:                if (expirationDate != null) {
0389:                    long currentTime = System.currentTimeMillis();
0390:                    if (currentTime > expirationDate.getTime()) {
0391:                        return true;
0392:                    }
0393:                }
0394:
0395:                // 3. missing tags => update
0396:                for (int i = 0; i < providers.length; ++i) {
0397:                    if (providers[i].getNumPriceTags() == 0) {
0398:                        return true;
0399:                    }
0400:                }
0401:
0402:                return false;
0403:            }
0404:
0405:            /**
0406:             * Returns <code>true</code> if the payment information should be stored
0407:             * for the next time.
0408:             *
0409:             * @return <code>true</code> if the payment information should be cached
0410:             */
0411:            public boolean cache() {
0412:                return cache;
0413:            }
0414:
0415:            /**
0416:             * Test for the system debug mode.
0417:             *
0418:             * @return <code>true</code> if the is running in the system debug mode
0419:             */
0420:            private native boolean isDebugMode();
0421:
0422:            /**
0423:             * Test for the debug demo mode.
0424:             *
0425:             * @return <code>true</code> if the debug demo mode should be activated
0426:             */
0427:            public boolean isDemoMode() {
0428:                return dbgDemoMode && isDebugMode();
0429:            }
0430:
0431:            /**
0432:             * Test for the debug fail initialize mode.
0433:             *
0434:             * @return <code>true</code> if the debug fail initialize mode should be
0435:             *      activated
0436:             */
0437:            public boolean getDbgFailInitialize() {
0438:                return dbgFailInitialize;
0439:            }
0440:
0441:            /**
0442:             * Test for the debug fail IO mode.
0443:             *
0444:             * @return <code>true</code> if the debug fail IO mode should be activated
0445:             */
0446:            public boolean getDbgFailIO() {
0447:                return dbgFailIO;
0448:            }
0449:
0450:            /**
0451:             * Returns the number of fake missed transactions that should be generated
0452:             * when the application starts.
0453:             *
0454:             * @return the number of missed transactions to generate or <code>-1</code>
0455:             *      if this debug mode is disabled
0456:             */
0457:            public int getDbgMissedTransactions() {
0458:                return dbgMissedTransactions;
0459:            }
0460:
0461:            /**
0462:             * Test for the debug random tests mode.
0463:             *
0464:             * @return <code>true</code> if the debug random tests mode should be
0465:             *      activated
0466:             */
0467:            public boolean getDbgRandomTests() {
0468:                return dbgRandomTests;
0469:            }
0470:
0471:            /**
0472:             * Returns the debug auto request mode setting.
0473:             *
0474:             * @return <code>AUTO_REQUEST_OFF</code> if the auto request mode is 
0475:             *      disabled, <code>AUTO_REQUEST_ACCEPT</code> if the auto request mode
0476:             *      is set to accept and <code>AUTO_REQUEST_REJECT</code> if it is set 
0477:             *      to reject
0478:             * @see #AUTO_REQUEST_OFF
0479:             * @see #AUTO_REQUEST_ACCEPT
0480:             * @see #AUTO_REQUEST_REJECT
0481:             */
0482:            public int getDbgAutoRequestMode() {
0483:                return dbgAutoRequestMode;
0484:            }
0485:
0486:            /**
0487:             * Returns the URL of the payment update.
0488:             *
0489:             * @return the update URL
0490:             */
0491:            public String getUpdateURL() {
0492:                return updateURL;
0493:            }
0494:
0495:            /**
0496:             * Returns the date of the last update or <code>null</code> if the payment
0497:             * information has been never updated.
0498:             *
0499:             * @return the last update date or <code>null</code>
0500:             */
0501:            public Date getUpdateDate() {
0502:                return updateDate;
0503:            }
0504:
0505:            /** 
0506:             * Gets the time stamp of last update.
0507:             *
0508:             * @return the time stamp
0509:             */
0510:            public Date getUpdateStamp() {
0511:                return updateStamp;
0512:            }
0513:
0514:            /** 
0515:             * Gets the number of features the application can request the user to pay
0516:             * for.
0517:             *
0518:             * @return the number of paid features
0519:             */
0520:            public int getNumFeatures() {
0521:                return featureToTag.length;
0522:            }
0523:
0524:            /** 
0525:             * Returns the price tag for the given feature id.
0526:             *
0527:             * @param index the feature id
0528:             * @return the price tag
0529:             */
0530:            public int getPriceTagForFeature(int index) {
0531:                return featureToTag[index];
0532:            }
0533:
0534:            /** 
0535:             * Returns the number of providers which can be used to pay for the 
0536:             * application features.
0537:             *
0538:             * @return the number of providers
0539:             */
0540:            public int getNumProviders() {
0541:                return providers.length;
0542:            }
0543:
0544:            /**
0545:             * Return the provider information for the given provider id.
0546:             *
0547:             * @param index the provider id
0548:             * @return the provider information
0549:             */
0550:            public ProviderInfo getProvider(int index) {
0551:                return providers[index];
0552:            }
0553:
0554:            /**
0555:             * Returns <code>true</code> if the given vector contains duplicate values.
0556:             *
0557:             * @param vector the vector of strings
0558:             * @return <code>true</code> if the vector contains duplicate values
0559:             */
0560:            private boolean hasDuplicates(Vector vector) {
0561:                int lastIndex = vector.size() - 1;
0562:                for (int i = 0; i < lastIndex; ++i) {
0563:                    if (vector.indexOf(vector.elementAt(i), i + 1) != -1) {
0564:                        return true;
0565:                    }
0566:                }
0567:
0568:                return false;
0569:            }
0570:
0571:            /**
0572:             * Constructs an string array from the given vector of strings. The 
0573:             * resulting array will contain the same strings as the vector and in the 
0574:             * same order as appeared in the vector.
0575:             *
0576:             * @param vector the vector of strings
0577:             * @return the array of strings
0578:             */
0579:            private String[] toStringArray(Vector vector) {
0580:                String[] strings = new String[vector.size()];
0581:                vector.copyInto(strings);
0582:
0583:                return strings;
0584:            }
0585:
0586:            /**
0587:             * Returns <code>true</code> if the given name is a valid adapter name.
0588:             *
0589:             * @param name the name to test
0590:             * @return <code>true</code> if the name is a valid adapter name
0591:             */
0592:            private boolean validateAdapterName(String name) {
0593:                if (name.startsWith("X-")) {
0594:                    return name.length() > 2;
0595:                }
0596:
0597:                for (int i = 0; i < VALID_ADAPTER_NAMES.length; ++i) {
0598:                    if (VALID_ADAPTER_NAMES[i].equals(name)) {
0599:                        return true;
0600:                    }
0601:                }
0602:
0603:                return false;
0604:            }
0605:
0606:            /**
0607:             * Returns <code>true</code> if the given string value represents a valid
0608:             * currency code.
0609:             *
0610:             * @param name the string to test
0611:             * @return <code>true</code> if the string is a valid currency code
0612:             */
0613:            private boolean validateCurrencyCode(String name) {
0614:                if (name.length() != 3) {
0615:                    return false;
0616:                }
0617:
0618:                for (int i = 0; i < 3; ++i) {
0619:                    if ((name.charAt(i) < 'A') || (name.charAt(i) > 'Z')) {
0620:                        return false;
0621:                    }
0622:                }
0623:
0624:                return true;
0625:            }
0626:
0627:            /**
0628:             * Parses an attribute which can have only one of the given predefined 
0629:             * values. It returns the index of the attribute's value or the 
0630:             * <code>defValue</code> if the attribute is not defined.
0631:             *
0632:             * @param props the properties to read the attribute from
0633:             * @param attribute the name of the attribute
0634:             * @param options the predefined values
0635:             * @param defValue a value to return when the attribute is not defined
0636:             * @return the index of a string from <code>options</code> which equals to
0637:             *      the attribute's value or <code>defValue</code>
0638:             * @throws PaymentException if the attribute's value doesn't match any of
0639:             *      the predefined values
0640:             */
0641:            private int readOptionalSelection(Properties props,
0642:                    String attribute, String[] options, int defValue)
0643:                    throws PaymentException {
0644:                String value = props.getProperty(attribute);
0645:                if (value == null) {
0646:                    return defValue;
0647:                }
0648:
0649:                for (int i = 0; i < options.length; ++i) {
0650:                    if (options[i].equals(value)) {
0651:                        return i;
0652:                    }
0653:                }
0654:
0655:                StringBuffer buffer = new StringBuffer();
0656:
0657:                buffer.append("expecting ");
0658:                buffer.append(options[0]);
0659:                int i;
0660:                for (i = 1; i < (options.length - 1); ++i) {
0661:                    buffer.append(", ");
0662:                    buffer.append(options[i]);
0663:                }
0664:                buffer.append(" or ");
0665:                buffer.append(options[i]);
0666:
0667:                throw new PaymentException(
0668:                        PaymentException.INVALID_ATTRIBUTE_VALUE, attribute,
0669:                        buffer.toString());
0670:            }
0671:
0672:            /**
0673:             *   Parse and check the version number of the JAR-Manifest
0674:             *   or JAD fields.
0675:             * 
0676:             *   @param payVersion version string to check
0677:             *   @throws PaymentException if the parameter contains wrong
0678:             *                            value or its value is greater than
0679:             *                            the version of the Payment API
0680:             *                            implemented in the device.
0681:             */
0682:            private void checkPayVersion(String payVersion)
0683:                    throws PaymentException {
0684:                double curVer;
0685:                double appVer;
0686:                payVersion = payVersion.trim();
0687:
0688:                // The format must be <major>.<minor>.
0689:                // First accepted version is 1.0
0690:                if ('1' > payVersion.charAt(0) || -1 == payVersion.indexOf('.')
0691:                        || 2 > payVersion.length() - payVersion.indexOf('.')) {
0692:                    // unsupported payment version
0693:                    throw new PaymentException(
0694:                            PaymentException.INVALID_ATTRIBUTE_VALUE,
0695:                            PAY_VERSION, null);
0696:                }
0697:
0698:                try {
0699:                    curVer = Float.parseFloat(CURRENT_VERSION);
0700:                    appVer = Float.parseFloat(payVersion);
0701:                } catch (NumberFormatException nfe) {
0702:                    // unsupported payment version
0703:                    throw new PaymentException(
0704:                            PaymentException.INVALID_ATTRIBUTE_VALUE,
0705:                            PAY_VERSION, null);
0706:                }
0707:
0708:                if (curVer < appVer) {
0709:                    // unsupported payment version
0710:                    throw new PaymentException(
0711:                            PaymentException.UNSUPPORTED_PAYMENT_INFO,
0712:                            PAY_VERSION, null);
0713:                }
0714:            }
0715:
0716:            /**
0717:             * Updates the payment information from the given JAD file properties. 
0718:             * If an exception is thrown during the update the original object state 
0719:             * remains intact.
0720:             *
0721:             * @param props the JAD file properties
0722:             * @throws PaymentException if the data read are incorrect or incomplete
0723:             */
0724:            private void loadFromJadProperties(Properties props)
0725:                    throws PaymentException {
0726:                String payVersion = props.getProperty(PAY_VERSION);
0727:                String payAdapters = props.getProperty(PAY_ADAPTERS);
0728:
0729:                if (payVersion != null) {
0730:                    checkPayVersion(payVersion);
0731:
0732:                    if (payAdapters == null) {
0733:                        // missing PAY_ADAPTERS attribute
0734:                        throw new PaymentException(
0735:                                PaymentException.MISSING_MANDATORY_ATTRIBUTE,
0736:                                PAY_ADAPTERS, null);
0737:                    }
0738:                } else {
0739:                    if (payAdapters != null) {
0740:                        // missing PAY_VERSION attribute
0741:                        throw new PaymentException(
0742:                                PaymentException.MISSING_MANDATORY_ATTRIBUTE,
0743:                                PAY_VERSION, null);
0744:                    }
0745:                }
0746:
0747:                String[] adapters = null;
0748:                // read & validate adapters
0749:                if (payVersion != null) {
0750:                    Vector names = Util.getCommaSeparatedValues(payAdapters);
0751:
0752:                    if (names.size() == 0) {
0753:                        throw new PaymentException(
0754:                                PaymentException.INVALID_ATTRIBUTE_VALUE,
0755:                                PAY_ADAPTERS, "the value is empty");
0756:                    }
0757:
0758:                    // avoid duplicate names
0759:                    if (hasDuplicates(names)) {
0760:                        throw new PaymentException(
0761:                                PaymentException.INVALID_ATTRIBUTE_VALUE,
0762:                                PAY_ADAPTERS, "duplicate fields in the value");
0763:                    }
0764:
0765:                    adapters = toStringArray(names);
0766:
0767:                    // validate adapter names
0768:                    for (int i = 0; i < adapters.length; ++i) {
0769:                        if (!validateAdapterName(adapters[i])) {
0770:                            throw new PaymentException(
0771:                                    PaymentException.INVALID_ATTRIBUTE_VALUE,
0772:                                    PAY_ADAPTERS, adapters[i]
0773:                                            + " is not a valid "
0774:                                            + "adapter name");
0775:                        }
0776:                    }
0777:
0778:                    // validate supported adapters
0779:                    PaymentModule paymentModule = PaymentModule.getInstance();
0780:                    int j;
0781:
0782:                    for (j = 0; j < adapters.length; ++j) {
0783:                        if (paymentModule.isSupportedAdapter(adapters[j])) {
0784:                            break;
0785:                        }
0786:                    }
0787:
0788:                    if (j == adapters.length) {
0789:                        throw new PaymentException(
0790:                                PaymentException.UNSUPPORTED_ADAPTERS,
0791:                                PAY_ADAPTERS, null);
0792:                    }
0793:                }
0794:
0795:                // read and validate Pay-Debug-* attributes
0796:                boolean dbgDemoMode = readOptionalSelection(props,
0797:                        PAY_DBG_DEMOMODE, YES_NO_OPTIONS, 1) != 1;
0798:                boolean dbgFailInitialize = readOptionalSelection(props,
0799:                        PAY_DBG_FAILINITIALIZE, YES_NO_OPTIONS, 1) != 1;
0800:                boolean dbgFailIO = readOptionalSelection(props,
0801:                        PAY_DBG_FAILIO, YES_NO_OPTIONS, 1) != 1;
0802:                int dbgMissedTransactions = -1;
0803:                boolean dbgRandomTests = readOptionalSelection(props,
0804:                        PAY_DBG_RANDOMTESTS, YES_NO_OPTIONS, 1) != 1;
0805:                int dbgAutoRequestMode = readOptionalSelection(props,
0806:                        PAY_DBG_AUTOREQUESTMODE, ACCEPT_REJECT_OPTIONS, -1) + 1;
0807:
0808:                // Peyment spec 1.1
0809:                // It is not used yet, but need for TCK passing
0810:                boolean dbgNoAdapter = readOptionalSelection(props,
0811:                        PAY_DBG_NOADAPTER, YES_NO_OPTIONS, 1) != 1;
0812:
0813:                String dbgMissedTransactionsStr = props
0814:                        .getProperty(PAY_DBG_MISSEDTRANSACTIONS);
0815:                if (dbgMissedTransactionsStr != null) {
0816:                    try {
0817:                        dbgMissedTransactions = Integer
0818:                                .parseInt(dbgMissedTransactionsStr);
0819:                    } catch (NumberFormatException e) {
0820:                    }
0821:
0822:                    if (dbgMissedTransactions < 0) {
0823:                        throw new PaymentException(
0824:                                PaymentException.INVALID_ATTRIBUTE_VALUE,
0825:                                PAY_DBG_MISSEDTRANSACTIONS,
0826:                                "expecting a positive number");
0827:                    }
0828:                }
0829:
0830:                // everything is correct, let's change the object state
0831:                this .adapters = adapters;
0832:                this .dbgDemoMode = dbgDemoMode;
0833:                this .dbgFailInitialize = dbgFailInitialize;
0834:                this .dbgFailIO = dbgFailIO;
0835:                this .dbgMissedTransactions = dbgMissedTransactions;
0836:                this .dbgRandomTests = dbgRandomTests;
0837:                this .dbgAutoRequestMode = dbgAutoRequestMode;
0838:            }
0839:
0840:            /**
0841:             * Parses and returns the provider information for the given provider name
0842:             * from the properties.
0843:             *
0844:             * @param props the properties to get provider from
0845:             * @param provider the provider name
0846:             * @return the provider information
0847:             * @throws PaymentException if the provider information is incorrect or
0848:             *      incomplete
0849:             */
0850:            private ProviderInfo loadProvider(Properties props, String provider)
0851:                    throws PaymentException {
0852:                String tempValue;
0853:                String tempKey = PAY_PREFIX + provider + INFO_SUFFIX;
0854:
0855:                tempValue = props.getProperty(tempKey);
0856:
0857:                if (tempValue == null) {
0858:                    // missing or incorrect provider
0859:                    throw new PaymentException(
0860:                            PaymentException.MISSING_MANDATORY_ATTRIBUTE,
0861:                            tempKey, null);
0862:                }
0863:
0864:                int offset = 0;
0865:                int index;
0866:
0867:                index = tempValue.indexOf(',');
0868:                if (index == -1) {
0869:                    // missing currency code
0870:                    throw new PaymentException(
0871:                            PaymentException.INVALID_ATTRIBUTE_VALUE, tempKey,
0872:                            "the currency code is not present");
0873:                }
0874:
0875:                String adapter = tempValue.substring(offset, index).trim();
0876:                // validate adapter name
0877:                if (!validateAdapterName(adapter)) {
0878:                    throw new PaymentException(
0879:                            PaymentException.INVALID_ATTRIBUTE_VALUE, tempKey,
0880:                            adapter + " is not a valid adapter name");
0881:                }
0882:
0883:                offset = index + 1;
0884:                index = tempValue.indexOf(',', offset);
0885:
0886:                String currency;
0887:                if (index == -1) {
0888:                    currency = tempValue.substring(offset).trim();
0889:                } else {
0890:                    currency = tempValue.substring(offset, index).trim();
0891:                }
0892:                // validate currency
0893:                if (!validateCurrencyCode(currency)) {
0894:                    throw new PaymentException(
0895:                            PaymentException.INVALID_ATTRIBUTE_VALUE, tempKey,
0896:                            "not a valid currency code");
0897:                }
0898:
0899:                // get configuration
0900:                String configuration;
0901:                if (index == -1) {
0902:                    throw new PaymentException(
0903:                            PaymentException.INVALID_ATTRIBUTE_VALUE, tempKey,
0904:                            "the payment specific info is not present");
0905:                }
0906:
0907:                offset = index + 1;
0908:                configuration = tempValue.substring(offset).trim();
0909:
0910:                tempKey = PAY_PREFIX + provider + TAG;
0911:                tempValue = props.getProperty(tempKey + 0);
0912:                double[] prices = null;
0913:                String[] paySpecificPriceInfo = null;
0914:                if (tempValue != null) {
0915:                    // contains tag attributes
0916:                    int numTags = 0;
0917:                    Vector tempVector = new Vector();
0918:                    do {
0919:                        tempVector.addElement(tempValue);
0920:                        tempValue = props.getProperty(tempKey + ++numTags);
0921:                    } while (tempValue != null);
0922:
0923:                    // we know the number of tags
0924:                    prices = new double[numTags];
0925:                    paySpecificPriceInfo = new String[numTags];
0926:
0927:                    for (int i = 0; i < numTags; ++i) {
0928:                        tempValue = (String) tempVector.elementAt(i);
0929:
0930:                        index = tempValue.indexOf(',');
0931:
0932:                        // parse and validate the price
0933:                        try {
0934:                            String tempPrice;
0935:                            if (index == -1) {
0936:                                tempPrice = tempValue.trim();
0937:                            } else {
0938:                                tempPrice = tempValue.substring(0, index)
0939:                                        .trim();
0940:                            }
0941:                            prices[i] = Double.parseDouble(tempPrice);
0942:                        } catch (NumberFormatException e) {
0943:                            throw new PaymentException(
0944:                                    PaymentException.INVALID_ATTRIBUTE_VALUE,
0945:                                    tempKey + i, "invalid price");
0946:                        }
0947:
0948:                        // get pay specific price info if present
0949:                        if (index != -1) {
0950:                            paySpecificPriceInfo[i] = tempValue.substring(
0951:                                    index + 1).trim();
0952:                        }
0953:                    }
0954:                }
0955:
0956:                // everything is correct, create the object
0957:                return new ProviderInfo(provider, adapter, configuration,
0958:                        currency, prices, paySpecificPriceInfo);
0959:            }
0960:
0961:            /**
0962:             * Loads the payment information from the given Manifest properties or
0963:             * update file properties. The <code>strict</code> indicates if the 
0964:             * additional tests should be executed on the data read from the properties.
0965:             * After passing these additional tests the resulting payment information 
0966:             * can be used for payment without any further update. Should an exception
0967:             * be thrown during the loading the object state will remain intact.
0968:             *
0969:             * @param props the properties
0970:             * @param strict if <code>true</code> the requirements on the data read
0971:             *      from the properties are harder
0972:             * @throws PaymentException if the data read are incorrect or incomplete
0973:             */
0974:            private void loadFromPropertiesAux(Properties props, boolean strict)
0975:                    throws PaymentException {
0976:                String tempValue;
0977:
0978:                long currentTime = System.currentTimeMillis();
0979:
0980:                tempValue = props.getProperty(PAY_VERSION);
0981:
0982:                if (tempValue == null) {
0983:                    // missing PAY_VERSION attribute
0984:                    throw new PaymentException(
0985:                            PaymentException.MISSING_MANDATORY_ATTRIBUTE,
0986:                            PAY_VERSION, null);
0987:                }
0988:
0989:                // throws Payment exception 
0990:                // if app pay version is greater than stack version
0991:                checkPayVersion(tempValue);
0992:
0993:                tempValue = props.getProperty(PAY_UPDATE_STAMP);
0994:                Date updateStamp;
0995:
0996:                if (tempValue == null) {
0997:                    // missing PAY_UPDATE_STAMP attribute
0998:                    throw new PaymentException(
0999:                            PaymentException.MISSING_MANDATORY_ATTRIBUTE,
1000:                            PAY_UPDATE_STAMP, null);
1001:                }
1002:
1003:                // parse and validate the date
1004:                try {
1005:                    long millis = utilities.parseISODate(tempValue);
1006:                    if (millis > currentTime) {
1007:                        throw new PaymentException(
1008:                                PaymentException.INFORMATION_NOT_YET_VALID);
1009:                    }
1010:                    updateStamp = new Date(millis);
1011:                } catch (IllegalArgumentException e) {
1012:                    throw new PaymentException(
1013:                            PaymentException.INVALID_ATTRIBUTE_VALUE,
1014:                            PAY_UPDATE_STAMP, e.getMessage());
1015:                }
1016:
1017:                String updateURL = props.getProperty(PAY_UPDATE_URL);
1018:
1019:                if (updateURL == null) {
1020:                    // missing PAY_UPDATE_URL attribute
1021:                    throw new PaymentException(
1022:                            PaymentException.MISSING_MANDATORY_ATTRIBUTE,
1023:                            PAY_UPDATE_URL, null);
1024:                }
1025:
1026:                // validate the URL
1027:                try {
1028:                    HttpUrl tempURL = new HttpUrl(updateURL);
1029:                    if (!"http".equals(tempURL.scheme)
1030:                            && !"https".equals(tempURL.scheme)) {
1031:                        throw new PaymentException(
1032:                                PaymentException.UNSUPPORTED_URL_SCHEME,
1033:                                tempURL.scheme, null);
1034:                    }
1035:
1036:                } catch (IllegalArgumentException e) {
1037:                    throw new PaymentException(
1038:                            PaymentException.INVALID_ATTRIBUTE_VALUE,
1039:                            PAY_UPDATE_URL, e.getMessage());
1040:                }
1041:
1042:                tempValue = props.getProperty(PAY_CACHE);
1043:                boolean cache = true;
1044:                Date expirationDate = null;
1045:
1046:                // validate and parse the PAY_CACHE attribute
1047:                if (tempValue != null) {
1048:                    if (YES_VALUE.equals(tempValue)) {
1049:                        cache = true;
1050:                    } else if (NO_VALUE.equals(tempValue)) {
1051:                        cache = false;
1052:                    } else {
1053:                        try {
1054:                            long millis = utilities.parseISODate(tempValue);
1055:                            if (strict && (millis < currentTime)) {
1056:                                throw new PaymentException(
1057:                                        PaymentException.INFORMATION_EXPIRED);
1058:                            }
1059:                            expirationDate = new Date(millis);
1060:                        } catch (IllegalArgumentException e) {
1061:                            throw new PaymentException(
1062:                                    PaymentException.INVALID_ATTRIBUTE_VALUE,
1063:                                    PAY_CACHE,
1064:                                    "expecting yes, no or a valid date");
1065:                        }
1066:                    }
1067:                }
1068:
1069:                Vector tempVector = new Vector();
1070:
1071:                tempValue = props.getProperty(PAY_FEATURE_PREFIX + 0);
1072:
1073:                if (tempValue == null) {
1074:                    throw new PaymentException(
1075:                            PaymentException.MISSING_MANDATORY_ATTRIBUTE,
1076:                            PAY_FEATURE_PREFIX + 0, null);
1077:                }
1078:
1079:                // read Pay-Feature-<n>
1080:                int index = 0;
1081:                tempVector.setSize(0);
1082:                do {
1083:                    tempVector.addElement(tempValue);
1084:                    tempValue = props.getProperty(PAY_FEATURE_PREFIX + ++index);
1085:                } while (tempValue != null);
1086:
1087:                int maxTag = 0;
1088:                int[] featureToTag = new int[index];
1089:                // parse and validate the numbers
1090:                for (int i = 0; i < index; ++i) {
1091:                    int value = -1;
1092:                    try {
1093:                        value = Integer.parseInt((String) tempVector
1094:                                .elementAt(i));
1095:                    } catch (NumberFormatException e) {
1096:                    }
1097:
1098:                    if (value < 0) {
1099:                        throw new PaymentException(
1100:                                PaymentException.INVALID_ATTRIBUTE_VALUE,
1101:                                PAY_FEATURE_PREFIX + i,
1102:                                "expecting a positive number");
1103:                    }
1104:
1105:                    if (maxTag < value) {
1106:                        maxTag = value;
1107:                    }
1108:
1109:                    featureToTag[i] = value;
1110:                }
1111:
1112:                tempValue = props.getProperty(PAY_PROVIDERS);
1113:
1114:                if (tempValue == null) {
1115:                    // missing PAY_PROVIDERS attribute
1116:                    throw new PaymentException(
1117:                            PaymentException.MISSING_MANDATORY_ATTRIBUTE,
1118:                            PAY_PROVIDERS, null);
1119:                }
1120:
1121:                Vector names = Util.getCommaSeparatedValues(tempValue);
1122:
1123:                if (names.size() == 0) {
1124:                    throw new PaymentException(
1125:                            PaymentException.INVALID_ATTRIBUTE_VALUE,
1126:                            PAY_PROVIDERS, "the value is empty");
1127:                }
1128:
1129:                // avoid duplicate names
1130:                if (hasDuplicates(names)) {
1131:                    throw new PaymentException(
1132:                            PaymentException.INVALID_ATTRIBUTE_VALUE,
1133:                            PAY_PROVIDERS, "duplicate fields in the value");
1134:                }
1135:
1136:                // IMPL_NOTE: check provider name?
1137:
1138:                ProviderInfo[] providers = new ProviderInfo[names.size()];
1139:                int numTags = maxTag + 1;
1140:                boolean hasSupportedProvider = false;
1141:                PaymentModule paymentModule = PaymentModule.getInstance();
1142:                // read and validate provider infos
1143:                for (int i = 0; i < providers.length; ++i) {
1144:                    // read provider
1145:                    ProviderInfo provider = loadProvider(props, (String) names
1146:                            .elementAt(i));
1147:
1148:                    if ((strict || (provider.getNumPriceTags() != 0))
1149:                            && (provider.getNumPriceTags() < numTags)) {
1150:                        throw new PaymentException(
1151:                                PaymentException.INCOMPLETE_INFORMATION);
1152:                    }
1153:
1154:                    // try to create an adapter for the provider
1155:                    PaymentAdapter adapter;
1156:                    try {
1157:                        adapter = paymentModule.getAdapter(provider
1158:                                .getAdapter(), provider.getConfiguration());
1159:                    } catch (PaymentException e) {
1160:                        e.setParam(PAY_PREFIX + provider.getName()
1161:                                + INFO_SUFFIX);
1162:                        throw e;
1163:                    }
1164:
1165:                    if (adapter != null) {
1166:                        // adapter has been created == we support at least one payment
1167:                        // provider
1168:                        hasSupportedProvider = true;
1169:
1170:                        int numTags2 = provider.getNumPriceTags();
1171:                        for (int j = 0; j < numTags2; ++j) {
1172:                            try {
1173:                                adapter.validatePriceInfo(provider.getPrice(j),
1174:                                        provider.getPaySpecificPriceInfo(j));
1175:                            } catch (PaymentException e) {
1176:                                e.setParam(PAY_PREFIX + provider.getName()
1177:                                        + TAG + j);
1178:                                throw e;
1179:                            }
1180:                        }
1181:                    }
1182:
1183:                    providers[i] = provider;
1184:                }
1185:
1186:                if (!hasSupportedProvider) {
1187:                    throw new PaymentException(
1188:                            PaymentException.UNSUPPORTED_PROVIDERS,
1189:                            PAY_PROVIDERS, null);
1190:                }
1191:
1192:                // everything is correct, let's change the object state
1193:                this .updateStamp = updateStamp;
1194:                this .updateURL = updateURL;
1195:                this .cache = cache;
1196:                this .expirationDate = expirationDate;
1197:                this .featureToTag = featureToTag;
1198:                this .providers = providers;
1199:            }
1200:
1201:            /**
1202:             * Updates the payment information from the given Manifest properties. If 
1203:             * an exception is thrown during the update the original object state 
1204:             * remains intact.
1205:             *
1206:             * @param props the Manifest properties
1207:             * @throws PaymentException if the data read are incorrect or incomplete
1208:             */
1209:            private void loadFromJarProperties(Properties props)
1210:                    throws PaymentException {
1211:                loadFromPropertiesAux(props, false);
1212:
1213:                // load the update date
1214:                String tempValue = props.getProperty(PAY_UPDATE_DATE);
1215:                updateDate = null;
1216:                if (tempValue != null) {
1217:                    try {
1218:                        long millis = utilities.parseISODate(tempValue);
1219:                        updateDate = new Date(millis);
1220:                    } catch (IllegalArgumentException e) {
1221:                    }
1222:                }
1223:            }
1224:
1225:            /**
1226:             * Updates the payment information from the given update file properties. 
1227:             * If an exception is thrown during the update the original object state 
1228:             * remains intact.
1229:             *
1230:             * @param props the update file properties
1231:             * @throws PaymentException if the data read are incorrect or incomplete
1232:             */
1233:            private void loadFromJppProperties(Properties props)
1234:                    throws PaymentException {
1235:                loadFromPropertiesAux(props, true);
1236:            }
1237:
1238:            /**
1239:             * Exports the given provider information into the given 
1240:             * <code>StringBuffer</code>.
1241:             *
1242:             * @param buffer the <code>StringBuffer</code>
1243:             * @param provider the provider information
1244:             */
1245:            private void exportProvider(StringBuffer buffer,
1246:                    ProviderInfo provider) {
1247:
1248:                // Pay-<ProviderTitle>
1249:                String providerPrefix = PAY_PREFIX + provider.getName();
1250:
1251:                // Pay-<ProviderTitle>-Info: <RegAdapter>, <ISO4217CurrencyCode>,
1252:                //      <PaymentSpecificInformation>
1253:                buffer.append(providerPrefix);
1254:                buffer.append(INFO_SUFFIX);
1255:                buffer.append(": ");
1256:                buffer.append(provider.getAdapter());
1257:                buffer.append(", ");
1258:                buffer.append(provider.getCurrency());
1259:                buffer.append(", ");
1260:                buffer.append(provider.getConfiguration());
1261:                buffer.append("\n");
1262:
1263:                // Pay-<ProviderTitle>-Tag-<m>: <Price>[, 
1264:                //      <PaymentSpecificPriceInformation>]
1265:                int count = provider.getNumPriceTags();
1266:                for (int i = 0; i < count; ++i) {
1267:                    buffer.append(providerPrefix);
1268:                    buffer.append(TAG);
1269:                    buffer.append(i);
1270:                    buffer.append(": ");
1271:                    buffer.append(provider.getPrice(i));
1272:                    String value = provider.getPaySpecificPriceInfo(i);
1273:                    if (value != null) {
1274:                        buffer.append(", ");
1275:                        buffer.append(value);
1276:                    }
1277:                    buffer.append("\n");
1278:                }
1279:            }
1280:
1281:            /**
1282:             * Finds a trusted provider certificate in one of the certification 
1283:             * chains read from the given properties.
1284:             *
1285:             * @param props the properties
1286:             * @return the trusted provider certificate
1287:             * @throws PaymentException if some certification chain is incorrect or
1288:             *      none of them can be trusted
1289:             */
1290:            private static X509Certificate findTrustedCertificate(
1291:                    Properties props) throws PaymentException {
1292:                int certPath = 1;
1293:                int certIndex = 1;
1294:                Vector certificates = new Vector();
1295:                String encodedCert = props.getProperty(PAY_CERTIFICATE_PREFIX
1296:                        + certPath + "-" + certIndex);
1297:
1298:                if (encodedCert == null) {
1299:                    throw new PaymentException(
1300:                            PaymentException.MISSING_MANDATORY_ATTRIBUTE,
1301:                            PAY_CERTIFICATE_PREFIX + certPath + "-" + certIndex,
1302:                            null);
1303:                }
1304:
1305:                do {
1306:                    certificates.setSize(0);
1307:
1308:                    do {
1309:                        try {
1310:                            byte[] binaryCert = Base64.decode(encodedCert);
1311:                            certificates.addElement(X509Certificate
1312:                                    .generateCertificate(binaryCert, 0,
1313:                                            binaryCert.length));
1314:                        } catch (IOException e) {
1315:                            throw new PaymentException(
1316:                                    PaymentException.INVALID_ATTRIBUTE_VALUE,
1317:                                    PAY_CERTIFICATE_PREFIX + certPath + "-"
1318:                                            + certIndex,
1319:                                    "invalid or unsupported certificate");
1320:                        }
1321:
1322:                        encodedCert = props.getProperty(PAY_CERTIFICATE_PREFIX
1323:                                + certPath + "-" + ++certIndex);
1324:                    } while (encodedCert != null);
1325:
1326:                    try {
1327:                        String[] authPath = X509Certificate.verifyChain(
1328:                                certificates,
1329:                                X509Certificate.DIGITAL_SIG_KEY_USAGE,
1330:                                X509Certificate.CODE_SIGN_EXT_KEY_USAGE,
1331:                                WebPublicKeyStore.getTrustedKeyStore());
1332:                        String domain = Permissions.UNIDENTIFIED_DOMAIN_BINDING;
1333:                        Vector keys = WebPublicKeyStore.getTrustedKeyStore()
1334:                                .findKeys(authPath[0]);
1335:                        if (keys != null) {
1336:                            domain = ((PublicKeyInfo) keys.elementAt(0))
1337:                                    .getDomain();
1338:                        }
1339:
1340:                        if (!Permissions.UNIDENTIFIED_DOMAIN_BINDING
1341:                                .equals(domain)) {
1342:                            // we verified the chain
1343:                            return (X509Certificate) certificates.elementAt(0);
1344:                        }
1345:
1346:                        // try next chain
1347:
1348:                    } catch (CertificateException e) {
1349:                        switch (e.getReason()) {
1350:                        case CertificateException.UNRECOGNIZED_ISSUER:
1351:                            // try next chain
1352:                            break;
1353:                        case CertificateException.EXPIRED:
1354:                        case CertificateException.NOT_YET_VALID:
1355:                            throw new PaymentException(
1356:                                    PaymentException.EXPIRED_PROVIDER_CERT, e
1357:                                            .getCertificate().getSubject(),
1358:                                    null);
1359:                        case CertificateException.ROOT_CA_EXPIRED:
1360:                            throw new PaymentException(
1361:                                    PaymentException.EXPIRED_CA_CERT, e
1362:                                            .getCertificate().getIssuer(), null);
1363:                        default:
1364:                            throw new PaymentException(
1365:                                    PaymentException.INVALID_PROVIDER_CERT, e
1366:                                            .getCertificate().getSubject(),
1367:                                    null);
1368:                        }
1369:                    }
1370:
1371:                    certIndex = 1;
1372:                    encodedCert = props.getProperty(PAY_CERTIFICATE_PREFIX
1373:                            + ++certPath + "-" + certIndex);
1374:                } while (encodedCert != null);
1375:
1376:                throw new PaymentException(PaymentException.NO_TRUSTED_CHAIN);
1377:            }
1378:
1379:            /**
1380:             * Strips all empty lines and lines containing any of 
1381:             * <code>Pay-Certificate-*</code> or <code>Pay-Signature-*</code> 
1382:             * attributes from the given string.
1383:             *
1384:             * @param string property containing string
1385:             * @return the altered string
1386:             */
1387:            private static String removePKIProperties(String string) {
1388:                char[] data = string.toCharArray();
1389:                int length = data.length;
1390:                StringBuffer buffer = new StringBuffer();
1391:
1392:                int i = 0;
1393:                int j, k;
1394:                do {
1395:                    // skip empty lines
1396:                    for (j = i; (j < length) && (data[j] != '\n')
1397:                            && (data[j] <= ' '); ++j) {
1398:                    }
1399:                    if (j == length) {
1400:                        break;
1401:                    }
1402:                    if (data[j] == '\n') {
1403:                        i = j + 1;
1404:                        continue;
1405:                    }
1406:
1407:                    // find matching prefix
1408:                    int prefixIdx;
1409:                    for (prefixIdx = 0; prefixIdx < PKI_PREFIXES.length; ++prefixIdx) {
1410:                        char[] prefix = PKI_PREFIXES[prefixIdx];
1411:                        for (k = 0, j = i; (j < length) && (k < prefix.length)
1412:                                && (data[j] == prefix[k]); ++j, ++k) {
1413:                        }
1414:                        if (k == prefix.length) {
1415:                            break;
1416:                        }
1417:                    }
1418:
1419:                    // find the end of the line
1420:                    for (j = i; (j < length) && (data[j] != '\n'); ++j) {
1421:                    }
1422:                    if (j < length) {
1423:                        // skip '\n'
1424:                        ++j;
1425:                    }
1426:
1427:                    // accept the lines that don't start with any of PKI_PREFIXES
1428:                    if (prefixIdx == PKI_PREFIXES.length) {
1429:                        buffer.append(data, i, j - i);
1430:                    }
1431:                    i = j;
1432:                } while (i < length);
1433:
1434:                return buffer.toString();
1435:            }
1436:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.