Source Code Cross Referenced for PaymentModule.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 javax.microedition.payment.TransactionListener;
0030:        import javax.microedition.payment.TransactionRecord;
0031:        import javax.microedition.payment.TransactionModuleException;
0032:
0033:        import com.sun.midp.security.*;
0034:
0035:        import com.sun.midp.util.DateParser;
0036:        import com.sun.midp.io.Util;
0037:
0038:        import java.io.*;
0039:        import java.util.Hashtable;
0040:        import java.util.Vector;
0041:        import javax.microedition.lcdui.*;
0042:        import javax.microedition.io.Connector;
0043:        import javax.microedition.io.Connection;
0044:        import javax.microedition.io.HttpConnection;
0045:        import javax.microedition.io.ConnectionNotFoundException;
0046:
0047:        /**
0048:         * This class represents a payment module. An instance of this class accepts
0049:         * payment requests from transaction modules. For each payment request it
0050:         * creates an instance of the <code>Transaction</code> class, set itself as
0051:         * an initial transaction processor of this transaction and adds it to the
0052:         * internal queue.
0053:         * <p>
0054:         * The internal queue is processed by a background thread created by the
0055:         * instance of the payment module. This thread iterates through the queued
0056:         * transactions and calls their <code>process</code> methods. This changes the
0057:         * internal states of the transactions until they are fully processed and are
0058:         * removed from the queue.
0059:         * <p>
0060:         * The <code>process</code> method of a transaction delegates the call to the
0061:         * associated transaction processor. This is initially the payment module. That
0062:         * allows him to show a provider selection form. After the user selects the
0063:         * provider for the transaction, the payment module changes the transaction
0064:         * processor of the transaction to the provider's payment adapter. This adapter
0065:         * gets the control over the transaction till it finishes the transaction and
0066:         * returns the control over it back to the payment module. The payment module
0067:         * finally removes the transaction from the transaction queue and notifies the
0068:         * application about the result of the payment.
0069:         * <p>
0070:         * The notification is done by creating a new transaction record for the
0071:         * finished transaction and adding it to the transaction notification
0072:         * queue which is processed by an extra thread which handles the notifications.
0073:         * Each transaction record is automatically added to the transaction store, so
0074:         * it can be obtained after crashing of the emulator.
0075:         *
0076:         * @version 
0077:         */
0078:        public abstract class PaymentModule implements  TransactionProcessor {
0079:            /**
0080:             * Inner class to request security token from SecurityInitializer.
0081:             * SecurityInitializer should be able to check this inner class name.
0082:             */
0083:            static private class SecurityTrusted implements 
0084:                    ImplicitlyTrustedClass {
0085:            };
0086:
0087:            /** This class has a different security domain than the MIDlet suite. */
0088:            private static SecurityToken classSecurityToken = SecurityInitializer
0089:                    .requestToken(new SecurityTrusted());
0090:
0091:            /** Standard timeout for alerts. */
0092:            private static final int ALERT_TIMEOUT = 1250;
0093:
0094:            /** The property that contains payment module class name. */
0095:            private static final String PAYMENT_MODULE = "microedition.payment.paymentmodule";
0096:
0097:            /** Payment module singleton. */
0098:            private static PaymentModule paymentModule;
0099:
0100:            /** Transaction processing thread. */
0101:            private TransactionProcessingThread processingThread;
0102:
0103:            /** Transaction state notification thread. */
0104:            private TransactionNotificationThread notificationThread;
0105:
0106:            /**
0107:             * Creates a new instance of PaymentModule.
0108:             */
0109:            protected PaymentModule() {
0110:            }
0111:
0112:            /**
0113:             * Returns an instance of the <code>PaymentModule</code> class. It creates
0114:             * only one instance and reuses it each time the method is called.
0115:             *
0116:             * @return the instance
0117:             */
0118:            public static PaymentModule getInstance() {
0119:                if (paymentModule == null) {
0120:                    String className = System.getProperty(PAYMENT_MODULE);
0121:                    if (className != null) {
0122:                        try {
0123:                            paymentModule = (PaymentModule) Class.forName(
0124:                                    className).newInstance();
0125:                        } catch (ClassNotFoundException cnfe) {
0126:                            // intentionally ignored
0127:                        } catch (InstantiationException ie) {
0128:                            // intentionally ignored
0129:                        } catch (IllegalAccessException iae) {
0130:                            // intentionally ignored
0131:                        }
0132:                    }
0133:                    //            if (paymentModule == null) {
0134:                    //                paymentModule = new PaymentModule();
0135:                    //            }
0136:                }
0137:                return paymentModule;
0138:            }
0139:
0140:            /**
0141:             * It's a factory method for <code>TransactionModuleImpl</code>.
0142:             *
0143:             * @param object the application MIDlet initiating a payment transaction
0144:             * @return a new instance of a <code>TransactionModuleImpl</code> subclass.
0145:             * @throws TransactionModuleException indicates a creation failure
0146:             */
0147:            public abstract TransactionModuleImpl createTransactionModule(
0148:                    Object object) throws TransactionModuleException;
0149:
0150:            /**
0151:             * Returns an instrance of the <code>TransactionStore</code> wich is used
0152:             * for storing of all transaction records produced in the payment module.
0153:             * There is only one such instance, which is returned each time the method
0154:             * is called. This instance is used from both internal threads of the
0155:             * payment module (<code>TransactionProcessingThread</code> and
0156:             * <code>TransactionNotificationThread</code>) and it is left to an
0157:             * implementation of the <code>TransactionStore</code> to be thread safe.
0158:             *
0159:             * @return the transaction store
0160:             */
0161:            protected abstract TransactionStore getTransactionStore();
0162:
0163:            /**
0164:             * Returns an instance of <code>Utils</code> subclass.
0165:             *
0166:             * @return the instance
0167:             */
0168:            protected abstract Utils getUtilities();
0169:
0170:            /**
0171:             * Returns a new application ID, which can be used to store transaction
0172:             * records to the transaction store.
0173:             *
0174:             * @return the new application ID
0175:             * @throws IOException if there is a I/O failure while working with the
0176:             *      store
0177:             */
0178:            public final int getNextApplicationID() throws IOException {
0179:                return getTransactionStore().getNextApplicationID();
0180:            }
0181:
0182:            /**
0183:             * Returns the associated payment information for the given transaction.
0184:             *
0185:             * @param transaction the transaction
0186:             * @return the payment information
0187:             */
0188:            protected static PaymentInfo getPaymentInfo(Transaction transaction) {
0189:                return transaction.getTransactionModule().getPaymentInfo();
0190:            }
0191:
0192:            /**
0193:             * Saves the payment information for the given transaction into storage.
0194:             *
0195:             * @param transaction the transaction
0196:             */
0197:            protected static void savePaymentInfo(Transaction transaction) {
0198:                try {
0199:                    transaction.getTransactionModule().savePaymentInfo();
0200:                } catch (IOException e) {
0201:                    // ignore
0202:                }
0203:            }
0204:
0205:            /**
0206:             * This class represents a transaction processing thread. It iterates
0207:             * through the queued transactions and executes the <code>process</code>
0208:             * method on them.
0209:             */
0210:            private class TransactionProcessingThread extends Thread {
0211:
0212:                /** List of transactions being processing. */
0213:                private Transaction[] transactionQueue = new Transaction[16];
0214:
0215:                /** Processing thread exit flag. */
0216:                private boolean finished;
0217:
0218:                /** Wait for next transaction flag. */
0219:                private boolean wait = true;
0220:
0221:                /**
0222:                 * This method is run when the thread starts. It implements the
0223:                 * selection and execution of the queued transactions.
0224:                 */
0225:                public void run() {
0226:                    // transaction processing queue
0227:                    while (!finished) {
0228:                        boolean blockUI = false;
0229:                        for (int i = 0; i < transactionQueue.length; ++i) {
0230:                            Transaction transaction = transactionQueue[i];
0231:                            if (transaction == null) {
0232:                                continue;
0233:                            }
0234:                            if (blockUI && transaction.needsUI()) {
0235:                                continue;
0236:                            }
0237:                            if (transaction.needsUI()) {
0238:                                blockUI = true;
0239:                            }
0240:                            if (transaction.isWaiting()) {
0241:                                continue;
0242:                            }
0243:
0244:                            transaction = transaction.process();
0245:                            if ((transaction != null) && transaction.needsUI()) {
0246:                                blockUI = true;
0247:                            }
0248:
0249:                            transactionQueue[i] = transaction;
0250:                            wait = false;
0251:                        }
0252:
0253:                        synchronized (transactionQueue) {
0254:                            if (wait) {
0255:                                try {
0256:                                    transactionQueue.wait();
0257:                                } catch (InterruptedException e) {
0258:                                }
0259:                            }
0260:                            wait = true;
0261:                        }
0262:                    }
0263:                }
0264:
0265:                /**
0266:                 * Adds a transaction to the transaction queue and makes the
0267:                 * transaction processing thread to continue its work.
0268:                 *
0269:                 * @param transaction the transaction
0270:                 * @throws TransactionModuleException if there is no more space for the
0271:                 *      new transaction in the queue
0272:                 */
0273:                public void addTransaction(Transaction transaction)
0274:                        throws TransactionModuleException {
0275:                    int i;
0276:                    for (i = 0; i < transactionQueue.length; ++i) {
0277:                        if (transactionQueue[i] == null) {
0278:                            transactionQueue[i] = transaction;
0279:                            // signal to the transaction processing thread, that there
0280:                            // is something to do
0281:                            continueWork();
0282:                            break;
0283:                        }
0284:                    }
0285:
0286:                    if (i == transactionQueue.length) {
0287:                        throw new TransactionModuleException(
0288:                                "No more space for " + "new transactions");
0289:                    }
0290:                }
0291:
0292:                /**
0293:                 * Tells the transaction processing thread to continue processing the
0294:                 * transactions.
0295:                 */
0296:                public void continueWork() {
0297:                    synchronized (transactionQueue) {
0298:                        wait = false;
0299:                        transactionQueue.notify();
0300:                    }
0301:                }
0302:            }
0303:
0304:            /**
0305:             * This class represents a transaction notification thread. It notifies
0306:             * the transaction listeners associated with the transactions about the
0307:             * final state of the transactions. After a successful notification it
0308:             * clears the transaction record's "was missed" flag.
0309:             * <p>
0310:             * It gets the transactions for the notification from its internal
0311:             * transaction notification queue and it has methods allowing the addition
0312:             * of new transaction records to this queue. Each transaction in the queue
0313:             * has associated a transaction module (<code>TransactionModuleImpl</code>)
0314:             * which in turn holds a reference to the transaction listener, that should
0315:             * be notified.
0316:             */
0317:            private class TransactionNotificationThread extends Thread {
0318:
0319:                /** Transaction listeners array */
0320:                private Vector notificationQueue = new Vector();
0321:
0322:                /** Notification thread exit flag. */
0323:                private boolean finished;
0324:
0325:                /** Wait for next transaction flag. */
0326:                private boolean wait = true;
0327:
0328:                /** 
0329:                 * Offset of TransactionRecord object 
0330:                 * inside notificationQueue element. 
0331:                 */
0332:                private static final int RECORD = 0;
0333:
0334:                /**
0335:                 * Offset of TransactionModuleImpl object
0336:                 * inside notificationQueue element. 
0337:                 */
0338:                private static final int MODULE = 1;
0339:
0340:                /**
0341:                 * This method is run when the thread starts.
0342:                 */
0343:                public void run() {
0344:                    TransactionStore transactionStore = getTransactionStore();
0345:
0346:                    // listeners notification queue
0347:                    while (!finished) {
0348:                        int count = notificationQueue.size();
0349:
0350:                        while (count > 0) {
0351:                            Object[] element = (Object[]) notificationQueue
0352:                                    .elementAt(0);
0353:
0354:                            // synchronized with the transaction module setListener
0355:                            // method => if the application invokes rhe
0356:                            // <code>TransactionModule.setListener</code> method with
0357:                            // <code>null</code>, after the call ends, there will be
0358:                            // no further notifications and no notification will be in
0359:                            // progress at that time
0360:                            synchronized (element[MODULE]) {
0361:                                TransactionRecord record = (TransactionRecord) element[RECORD];
0362:                                TransactionListener listener = ((TransactionModuleImpl) element[MODULE])
0363:                                        .getListener();
0364:
0365:                                if (listener != null) {
0366:                                    try {
0367:                                        int transactionID = record
0368:                                                .getTransactionID();
0369:                                        // test if the record has been delivered before,
0370:                                        // because of for example 2 successive calls to 
0371:                                        // deliverMissedTransactions
0372:                                        if (!transactionStore
0373:                                                .wasDelivered(transactionID)) {
0374:                                            listener.processed(record);
0375:                                            transactionStore
0376:                                                    .setDelivered(transactionID);
0377:                                        }
0378:                                    } catch (IOException e) {
0379:                                        // failed to notify or a transaction store
0380:                                        // failure
0381:                                        // ignore
0382:                                    }
0383:                                }
0384:
0385:                                notificationQueue.removeElementAt(0);
0386:                                --count;
0387:                            }
0388:                        }
0389:
0390:                        synchronized (notificationQueue) {
0391:                            if (wait) {
0392:                                try {
0393:                                    notificationQueue.wait();
0394:                                } catch (InterruptedException e) {
0395:                                }
0396:                            }
0397:                            wait = true;
0398:                        }
0399:                    }
0400:                }
0401:
0402:                /**
0403:                 * Add the given transaction record and transaction module to the
0404:                 * transaction notification queue. It wakes up the transaction
0405:                 * notification thread if necessary.
0406:                 *
0407:                 * @param record the transaction record
0408:                 * @param module the transaction module
0409:                 */
0410:                public void addTransaction(TransactionRecord record,
0411:                        TransactionModuleImpl module) {
0412:                    Object[] element = new Object[] { record, module };
0413:
0414:                    notificationQueue.addElement(element);
0415:                    continueWork();
0416:                }
0417:
0418:                /**
0419:                 * Adds the given transaction records to the transaction notification
0420:                 * queue. Each transaction record is associated with the given
0421:                 * transaction module. If the transaction notification thread is not
0422:                 * running at the time the method is executed, it is woken up by the
0423:                 * method.
0424:                 *
0425:                 * @param records an array of the transaction records
0426:                 * @param module the module associated with the records
0427:                 */
0428:                public void addTransactions(TransactionRecord[] records,
0429:                        TransactionModuleImpl module) {
0430:                    Object[] element;
0431:
0432:                    for (int i = 0; i < records.length; ++i) {
0433:                        element = new Object[2];
0434:                        element[RECORD] = records[i];
0435:                        element[MODULE] = module;
0436:                        notificationQueue.addElement(element);
0437:                    }
0438:
0439:                    continueWork();
0440:                }
0441:
0442:                /**
0443:                 * This method makes the transaction notification thread to continue
0444:                 * notification.
0445:                 */
0446:                public void continueWork() {
0447:                    synchronized (notificationQueue) {
0448:                        wait = false;
0449:                        notificationQueue.notify();
0450:                    }
0451:                }
0452:            }
0453:
0454:            /**
0455:             * Signals the transaction processing thread to continue processing of the
0456:             * queued transactions. It means that there is at least one transaction in
0457:             * the queue, which is not waiting for some event (an user action,
0458:             * finishing of some payment adapter's thread, etc.).
0459:             */
0460:            final void continueProcessing() {
0461:                processingThread.continueWork();
0462:            }
0463:
0464:            /**
0465:             * Creates a new transaction from the given payment requests. It sets the
0466:             * payment module as a transaction processor and adds the new transaction
0467:             * to the transaction queue. Returns a generated identification number,
0468:             * which identifies the new transaction.
0469:             *
0470:             * @param transactionModule the transaction module, which called the method
0471:             * @param featureID the identifier of the feature to be paid for
0472:             * @param featureTitle the title of the feature
0473:             * @param featureDescription the description of the feature
0474:             * @param payload the payload to be transfered as a part of the payment or
0475:             *      <code>null</code> if no such payload required
0476:             * @return the identification number of the transaction
0477:             * @throws TransactionModuleException if there is no more space to store
0478:             *      the new transaction
0479:             */
0480:            synchronized public final int addTransaction(
0481:                    TransactionModuleImpl transactionModule, int featureID,
0482:                    String featureTitle, String featureDescription,
0483:                    byte[] payload) throws TransactionModuleException {
0484:
0485:                // execute the transaction processing thread if not running
0486:                if (processingThread == null) {
0487:                    processingThread = new TransactionProcessingThread();
0488:                    processingThread.start();
0489:                }
0490:
0491:                TransactionStore transactionStore = getTransactionStore();
0492:
0493:                Transaction transaction = new Transaction(this ,
0494:                        transactionModule, featureID, featureTitle,
0495:                        featureDescription, payload);
0496:
0497:                int transactionID;
0498:                try {
0499:                    transactionID = transactionStore.reserve(transactionModule
0500:                            .getApplicationID(), transaction);
0501:                } catch (IOException e) {
0502:                    throw new TransactionModuleException("No more space for "
0503:                            + "transaction records");
0504:                }
0505:                transaction.setTransactionID(transactionID);
0506:
0507:                PaymentInfo paymentInfo = getPaymentInfo(transaction);
0508:                synchronized (paymentInfo) {
0509:                    processingThread.addTransaction(transaction);
0510:
0511:                    if (paymentInfo.needsUpdate()) {
0512:                        try {
0513:                            paymentInfo.wait();
0514:                        } catch (InterruptedException e) {
0515:                            // ignore
0516:                        }
0517:
0518:                        if (paymentInfo.needsUpdate()) {
0519:                            throw new TransactionModuleException(
0520:                                    "The provisioning "
0521:                                            + "information needs an update");
0522:                        }
0523:                    }
0524:                }
0525:
0526:                return transactionID;
0527:            }
0528:
0529:            /**
0530:             * Adds the given transaction record to the transaction notification queue
0531:             * and associates it with the given payment module. The payment module holds
0532:             * a reference to the listener, which should be notified.
0533:             *
0534:             * @param record the transaction record
0535:             * @param module the transaction module
0536:             */
0537:            final void addTransactionForNotification(TransactionRecord record,
0538:                    TransactionModuleImpl module) {
0539:                // execute the transaction notification thread if not running
0540:                if (notificationThread == null) {
0541:                    notificationThread = new TransactionNotificationThread();
0542:                    notificationThread.start();
0543:                }
0544:
0545:                notificationThread.addTransaction(record, module);
0546:            }
0547:
0548:            /**
0549:             * Adds the given transaction records to the transaction notification
0550:             * queue and associates them with the given payment module. The payment
0551:             * module holds a reference to the listener, which should be notified.
0552:             *
0553:             * @param records an array of the transaction records
0554:             * @param module the transaction module
0555:             */
0556:            final void addTransactionsForNotification(
0557:                    TransactionRecord[] records, TransactionModuleImpl module) {
0558:                // execute the transaction notification thread if not running
0559:                if (notificationThread == null) {
0560:                    notificationThread = new TransactionNotificationThread();
0561:                    notificationThread.start();
0562:                }
0563:
0564:                notificationThread.addTransactions(records, module);
0565:            }
0566:
0567:            /** Pointer to utility methods class. */
0568:            private final Utils utilities = getUtilities();
0569:
0570:            /** 'NEVER' string */
0571:            private final String NEVER = utilities
0572:                    .getString(Utils.PAYMENT_PROV_SEL_DLG_NEVER);
0573:
0574:            /**
0575:             * This class represents an UI for displaying and updating of payment
0576:             * information and selecting a payment provider for the payment. The
0577:             * payment is represented by an instance of the <code>Transaction</code>
0578:             * class.
0579:             */
0580:            private class PaymentModuleUI implements  CommandListener,
0581:                    ItemCommandListener, ItemStateListener {
0582:
0583:                /** A transaction which represents the payment. */
0584:                private Transaction transaction;
0585:
0586:                /** Reject payment command. */
0587:                private final Command rejectCommand = new Command(utilities
0588:                        .getString(Utils.PAYMENT_PROV_SEL_DLG_NO),
0589:                        Command.CANCEL, 1);
0590:
0591:                /** Accept payment command. */
0592:                private final Command acceptCommand = new Command(utilities
0593:                        .getString(Utils.PAYMENT_PROV_SEL_DLG_YES), Command.OK,
0594:                        1);
0595:
0596:                /** Update payment info command. */
0597:                private final Command updateCommand = new Command(utilities
0598:                        .getString(Utils.PAYMENT_PROV_SEL_DLG_UPDATE),
0599:                        Command.ITEM, 2);
0600:
0601:                /** Cancel payment info update command. */
0602:                private final Command stopCommand = new Command(utilities
0603:                        .getString(Utils.PAYMENT_UPDATE_DLG_STOP),
0604:                        Command.STOP, 1);
0605:
0606:                /** Provider selection form. */
0607:                private Form providerSelectionForm;
0608:
0609:                /** Question string max length. */
0610:                private static final int QUESTION_LENGTH = 90;
0611:
0612:                /** Feature description form item. */
0613:                private StringItem featureDescriptionItem;
0614:
0615:                /** Payment question form item. */
0616:                private StringItem paymentQuestionItem;
0617:
0618:                /** Provider selection choice group. */
0619:                private ChoiceGroup providerSelectionChoice;
0620:
0621:                /** Payment info update date item. */
0622:                private StringItem updateDateItem;
0623:
0624:                /** Last update stamp item. */
0625:                private StringItem updateStampItem;
0626:
0627:                /** Provider identifiers array. */
0628:                private int[] providers;
0629:
0630:                /** Payment info update form. */
0631:                private Form paymentUpdateForm;
0632:
0633:                /** Payment info update progress gauge. */
0634:                private Gauge progressGauge;
0635:
0636:                /** Payment info update state. */
0637:                private int updateState = -1;
0638:
0639:                /** Flag indicates that payment info update was canceled. */
0640:                private boolean cancel;
0641:
0642:                /**
0643:                 * Creates an instance of the <code>PaymentModuleUI</code> class.
0644:                 * It requires a transaction which represents the payment.
0645:                 *
0646:                 * @param transaction the transaction
0647:                 */
0648:                public PaymentModuleUI(Transaction transaction) {
0649:                    this .transaction = transaction;
0650:                }
0651:
0652:                /** Displays a payment update form for the transaction. */
0653:                public void showPaymentUpdateForm() {
0654:                    if (paymentUpdateForm == null) {
0655:                        // create the form
0656:                        paymentUpdateForm = new Form(utilities
0657:                                .getString(Utils.PAYMENT_UPDATE_DLG_CAPTION));
0658:
0659:                        progressGauge = new Gauge(null, false,
0660:                                Gauge.INDEFINITE, Gauge.CONTINUOUS_RUNNING);
0661:                        progressGauge.setPreferredSize(paymentUpdateForm
0662:                                .getWidth(), -1);
0663:
0664:                        paymentUpdateForm.append(progressGauge);
0665:
0666:                        paymentUpdateForm.addCommand(stopCommand);
0667:                        paymentUpdateForm.setCommandListener(this );
0668:                    }
0669:
0670:                    updatePaymentUpdateForm();
0671:                    preemptDisplay(classSecurityToken, paymentUpdateForm);
0672:                }
0673:
0674:                /** Displays a provider selection form for the transaction. */
0675:                public void showProviderSelectionForm() {
0676:                    if (providerSelectionForm == null) {
0677:                        // create the form
0678:                        providerSelectionForm = new Form(transaction
0679:                                .getFeatureTitle());
0680:
0681:                        featureDescriptionItem = new StringItem(transaction
0682:                                .getFeatureDescription(), null);
0683:                        paymentQuestionItem = new StringItem(null, null);
0684:                        providerSelectionChoice = new ChoiceGroup(utilities
0685:                                .getString(Utils.PAYMENT_PROV_SEL_DLG_PAY_BY),
0686:                                ChoiceGroup.POPUP);
0687:                        updateDateItem = new StringItem(
0688:                                utilities
0689:                                        .getString(Utils.PAYMENT_PROV_SEL_DLG_UPDATE_DATE),
0690:                                null);
0691:                        updateStampItem = new StringItem(
0692:                                utilities
0693:                                        .getString(Utils.PAYMENT_PROV_SEL_DLG_UPDATE_STAMP),
0694:                                null);
0695:
0696:                        featureDescriptionItem
0697:                                .setLayout(Item.LAYOUT_NEWLINE_BEFORE
0698:                                        | Item.LAYOUT_NEWLINE_AFTER);
0699:                        paymentQuestionItem
0700:                                .setLayout(Item.LAYOUT_NEWLINE_BEFORE
0701:                                        | Item.LAYOUT_NEWLINE_AFTER);
0702:                        providerSelectionChoice
0703:                                .setLayout(Item.LAYOUT_NEWLINE_BEFORE
0704:                                        | Item.LAYOUT_NEWLINE_AFTER);
0705:                        updateDateItem.setLayout(Item.LAYOUT_NEWLINE_BEFORE
0706:                                | Item.LAYOUT_NEWLINE_AFTER);
0707:                        updateStampItem.setLayout(Item.LAYOUT_NEWLINE_BEFORE
0708:                                | Item.LAYOUT_NEWLINE_AFTER);
0709:
0710:                        Font defaultFont = Font.getDefaultFont();
0711:                        StringItem separator;
0712:                        int separatorHeight = defaultFont.getHeight() >>> 1;
0713:                        int separatorWidth = providerSelectionForm.getWidth() >>> 1;
0714:
0715:                        int reserveLines = defaultFont.charWidth('M')
0716:                                * QUESTION_LENGTH
0717:                                / providerSelectionForm.getWidth() + 1;
0718:                        paymentQuestionItem.setPreferredSize(-1, reserveLines
0719:                                * defaultFont.getHeight());
0720:
0721:                        separator = new StringItem(null, null);
0722:                        separator.setPreferredSize(separatorWidth,
0723:                                separatorHeight);
0724:                        separator.setLayout(Item.LAYOUT_NEWLINE_BEFORE
0725:                                | Item.LAYOUT_NEWLINE_AFTER);
0726:                        providerSelectionForm.append(featureDescriptionItem);
0727:                        providerSelectionForm.append(separator);
0728:                        providerSelectionForm.append(paymentQuestionItem);
0729:                        providerSelectionForm.append(providerSelectionChoice);
0730:
0731:                        separator = new StringItem(null, null);
0732:                        separator.setPreferredSize(separatorWidth,
0733:                                separatorHeight);
0734:                        separator.setLayout(Item.LAYOUT_NEWLINE_BEFORE
0735:                                | Item.LAYOUT_NEWLINE_AFTER);
0736:                        providerSelectionForm.append(separator);
0737:                        providerSelectionForm.append(updateDateItem);
0738:                        providerSelectionForm.append(updateStampItem);
0739:
0740:                        StringItem updateItem = new StringItem(null,
0741:                                updateCommand.getLabel(), Item.BUTTON);
0742:
0743:                        updateItem.setLayout(Item.LAYOUT_NEWLINE_BEFORE
0744:                                | Item.LAYOUT_RIGHT);
0745:                        updateItem.setDefaultCommand(updateCommand);
0746:                        updateItem.setItemCommandListener(this );
0747:
0748:                        separator = new StringItem(null, null);
0749:                        separator.setPreferredSize(separatorWidth,
0750:                                separatorHeight);
0751:                        separator.setLayout(Item.LAYOUT_NEWLINE_BEFORE
0752:                                | Item.LAYOUT_NEWLINE_AFTER);
0753:                        providerSelectionForm.append(separator);
0754:                        providerSelectionForm.append(updateItem);
0755:
0756:                        // reset the layout to the left
0757:                        StringItem lastItem = new StringItem(null, null);
0758:                        lastItem.setLayout(Item.LAYOUT_LEFT);
0759:                        providerSelectionForm.append(lastItem);
0760:
0761:                        providerSelectionForm.addCommand(acceptCommand);
0762:                        providerSelectionForm.addCommand(rejectCommand);
0763:
0764:                        providerSelectionForm.setCommandListener(this );
0765:                        providerSelectionForm.setItemStateListener(this );
0766:                    }
0767:
0768:                    PaymentInfo paymentInfo = getPaymentInfo(transaction);
0769:                    providers = getValidProviders(paymentInfo);
0770:
0771:                    // fill the provider selection choice group
0772:                    int oldIndex = providerSelectionChoice.getSelectedIndex();
0773:                    providerSelectionChoice.deleteAll();
0774:                    for (int i = 0; i < providers.length; ++i) {
0775:                        ProviderInfo providerInfo = paymentInfo
0776:                                .getProvider(providers[i]);
0777:
0778:                        PaymentAdapter adapter = null;
0779:                        try {
0780:                            adapter = getAdapter(providerInfo.getAdapter(),
0781:                                    providerInfo.getConfiguration());
0782:                        } catch (PaymentException e) {
0783:                        }
0784:
0785:                        providerSelectionChoice.append(adapter.getDisplayName()
0786:                                + " - " + providerInfo.getName(), null);
0787:                    }
0788:                    if (oldIndex >= providers.length) {
0789:                        oldIndex = providers.length - 1;
0790:                    }
0791:                    if (oldIndex < 0) {
0792:                        oldIndex = 0;
0793:                    }
0794:                    providerSelectionChoice.setSelectedIndex(oldIndex, true);
0795:
0796:                    updateProviderSelectionForm();
0797:                    preemptDisplay(classSecurityToken, providerSelectionForm);
0798:                }
0799:
0800:                /**
0801:                 * Displays an alert with the given title and message.
0802:                 *
0803:                 * @param title the title
0804:                 * @param message the message
0805:                 */
0806:                private void displayException(String title, String message) {
0807:                    Alert a = new Alert(title, message, null, AlertType.ERROR);
0808:
0809:                    a.setTimeout(Alert.FOREVER);
0810:                    a.setCommandListener(this );
0811:
0812:                    preemptDisplay(classSecurityToken, a);
0813:                }
0814:
0815:                /**
0816:                 * Updates the user interface of the provider selection form to reflect
0817:                 * changes made by the user.
0818:                 */
0819:                private void updateProviderSelectionForm() {
0820:                    int providerID = providers[providerSelectionChoice
0821:                            .getSelectedIndex()];
0822:
0823:                    PaymentInfo paymentInfo = getPaymentInfo(transaction);
0824:                    int priceTag = paymentInfo
0825:                            .getPriceTagForFeature(transaction.getFeatureID());
0826:
0827:                    updateDateItem
0828:                            .setText((paymentInfo.getUpdateDate() == null) ? NEVER
0829:                                    : paymentInfo.getUpdateDate().toString());
0830:                    updateStampItem.setText(paymentInfo.getUpdateStamp()
0831:                            .toString());
0832:
0833:                    ProviderInfo providerInfo = paymentInfo
0834:                            .getProvider(providerID);
0835:                    PaymentAdapter adapter = null;
0836:                    try {
0837:                        adapter = getAdapter(providerInfo.getAdapter(),
0838:                                providerInfo.getConfiguration());
0839:                    } catch (PaymentException e) {
0840:                    }
0841:
0842:                    String question = adapter.getPaymentQuestion(providerInfo
0843:                            .getName(), providerInfo.getPrice(priceTag),
0844:                            providerInfo.getCurrency());
0845:
0846:                    paymentQuestionItem.setText(question);
0847:                }
0848:
0849:                /**
0850:                 * Updates the payment update form to reflect the state the payment
0851:                 * update is in.
0852:                 */
0853:                private void updatePaymentUpdateForm() {
0854:                    int key;
0855:                    int retry = 0;
0856:
0857:                    if (updateState == -1) {
0858:                        progressGauge.setLabel(null);
0859:                        return;
0860:                    }
0861:
0862:                    if (cancel) {
0863:                        progressGauge
0864:                                .setLabel(utilities
0865:                                        .getString(Utils.PAYMENT_UPDATE_DLG_CANCELLING));
0866:                        return;
0867:                    }
0868:
0869:                    if (updateState < STATE_DOWNLOADING) {
0870:                        retry = updateState >>> RETRY_SHIFT;
0871:                        updateState &= (1 << RETRY_SHIFT) - 1;
0872:                    }
0873:
0874:                    switch (updateState) {
0875:                    case STATE_CONNECTING:
0876:                        key = Utils.PAYMENT_UPDATE_DLG_CONNECTING;
0877:                        break;
0878:                    case STATE_SENDING_REQUEST:
0879:                        key = Utils.PAYMENT_UPDATE_DLG_SENDING;
0880:                        break;
0881:                    case STATE_RETRY_WAITING:
0882:                        key = Utils.PAYMENT_UPDATE_DLG_WAITING;
0883:                        break;
0884:                    case STATE_DOWNLOADING:
0885:                        key = Utils.PAYMENT_UPDATE_DLG_DOWNLOADING;
0886:                        break;
0887:                    case STATE_VERIFYING:
0888:                        key = Utils.PAYMENT_UPDATE_DLG_VERIFYING;
0889:                        break;
0890:                    default:
0891:                        return;
0892:                    }
0893:
0894:                    String message = utilities.getString(key);
0895:
0896:                    if (retry > 0) {
0897:                        String[] params = { Integer.toString(retry),
0898:                                Integer.toString(MAX_RETRY_COUNT) };
0899:
0900:                        message += "\n"
0901:                                + utilities.getString(
0902:                                        Utils.PAYMENT_UPDATE_DLG_RETRY, params);
0903:                    }
0904:
0905:                    progressGauge.setLabel(message);
0906:                }
0907:
0908:                /** Time of payment update form last update. */
0909:                private long lastUIUpdate;
0910:
0911:                /**
0912:                 * A method which is called by the payment module when the state of the
0913:                 * payment update changes.
0914:                 *
0915:                 * @param newState the new state of the payment update
0916:                 * @throws InterruptedException if the payment update has been
0917:                 *      interrupted by the user
0918:                 */
0919:                public void notifyStateChange(int newState)
0920:                        throws InterruptedException {
0921:                    if (cancel) {
0922:                        throw new InterruptedException("stopped");
0923:                    }
0924:                    if (updateState != newState) {
0925:                        long sleepTime = lastUIUpdate + ALERT_TIMEOUT
0926:                                - System.currentTimeMillis();
0927:
0928:                        if (sleepTime > 0) {
0929:                            Thread.sleep(sleepTime);
0930:                        }
0931:
0932:                        updateState = newState;
0933:                        updatePaymentUpdateForm();
0934:
0935:                        lastUIUpdate = System.currentTimeMillis();
0936:                    }
0937:                }
0938:
0939:                /**
0940:                 * Implements a response to user actions.
0941:                 *
0942:                 * @param c the executed command
0943:                 * @param d the <code>Displayable</code> on which the command has
0944:                 *      been executed
0945:                 */
0946:                public void commandAction(Command c, Displayable d) {
0947:                    if (c == acceptCommand) {
0948:                        preemptDisplay(classSecurityToken, null);
0949:                        currentUI = null;
0950:
0951:                        assignTransaction(transaction,
0952:                                providers[providerSelectionChoice
0953:                                        .getSelectedIndex()]);
0954:                        transaction.setWaiting(false);
0955:                    } else if (c == rejectCommand) {
0956:                        preemptDisplay(classSecurityToken, null);
0957:                        currentUI = null;
0958:
0959:                        // reject the transaction
0960:                        transaction.setState(Transaction.REJECTED);
0961:                        transaction.setNeedsUI(false);
0962:                        transaction.setWaiting(false);
0963:                    } else if (c == Alert.DISMISS_COMMAND) {
0964:                        preemptDisplay(classSecurityToken, null);
0965:                        PaymentInfo paymentInfo = getPaymentInfo(transaction);
0966:                        if (paymentInfo.needsUpdate()) {
0967:                            // we failed to update and the current information can't
0968:                            // be used => fail the transaction
0969:                            currentUI = null;
0970:
0971:                            // discard the transaction
0972:                            transaction.setState(Transaction.DISCARDED);
0973:                            transaction.setNeedsUI(false);
0974:                            transaction.setWaiting(false);
0975:                        } else {
0976:                            transaction.setState(Transaction.ENTERED);
0977:                            transaction.setWaiting(false);
0978:                            //                    showProviderSelectionForm();
0979:                        }
0980:
0981:                        // release the process method if waiting for an update
0982:                        synchronized (paymentInfo) {
0983:                            paymentInfo.notifyAll();
0984:                        }
0985:                    } else if (c == stopCommand) {
0986:                        if (!cancel) {
0987:                            cancel = true;
0988:                            updatePaymentUpdateForm();
0989:                            //                  processingThread.interrupt();
0990:                        }
0991:                    }
0992:                }
0993:
0994:                /**
0995:                 * Implements a response to user actions.
0996:                 *
0997:                 * @param c the executed command
0998:                 * @param item the item associated with the executed command
0999:                 */
1000:                public void commandAction(Command c, Item item) {
1001:                    if (c == updateCommand) {
1002:                        preemptDisplay(classSecurityToken, null);
1003:                        updateState = -1;
1004:                        cancel = false;
1005:                        transaction.setState(Transaction.UPDATE);
1006:                        transaction.setWaiting(false);
1007:                    }
1008:                }
1009:
1010:                /**
1011:                 * Called when internal state of an Item has been changed by the user.
1012:                 *
1013:                 * @param item the item that was changed
1014:                 */
1015:                public void itemStateChanged(Item item) {
1016:                    if (item == providerSelectionChoice) {
1017:                        updateProviderSelectionForm();
1018:                    }
1019:                }
1020:            }
1021:
1022:            /**
1023:             * Assigns the given transaction to the provider identified by its
1024:             * identification number. It sets the transaction processor of the
1025:             * transaction to the provider's payment adapter.
1026:             *
1027:             * @param transaction the transaction
1028:             * @param providerID the provider id
1029:             */
1030:            protected void assignTransaction(Transaction transaction,
1031:                    int providerID) {
1032:                PaymentInfo paymentInfo = getPaymentInfo(transaction);
1033:                int priceTag = paymentInfo.getPriceTagForFeature(transaction
1034:                        .getFeatureID());
1035:
1036:                ProviderInfo providerInfo = paymentInfo.getProvider(providerID);
1037:                // get the adapter instance for the given provider
1038:                PaymentAdapter adapter = null;
1039:                try {
1040:                    adapter = getAdapter(providerInfo.getAdapter(),
1041:                            providerInfo.getConfiguration());
1042:                } catch (PaymentException e) {
1043:                }
1044:
1045:                // fill the transaction fields with the provider specific values
1046:                transaction.setProviderName(providerInfo.getName());
1047:                transaction.setCurrency(providerInfo.getCurrency());
1048:                transaction.setPrice(providerInfo.getPrice(priceTag));
1049:                transaction.setSpecificPriceInfo(providerInfo
1050:                        .getPaySpecificPriceInfo(priceTag));
1051:
1052:                // === DEBUG MODE ===
1053:                // let a subclass to handle the transaction in the debug mode, if it
1054:                // does, don't forward the control over the transaction to the payment 
1055:                // adapter
1056:                if (handleTransactionDebugMode(transaction)) {
1057:                    return;
1058:                }
1059:                // === DEBUG MODE ===
1060:
1061:                // set the adapter to be a transaction processor for the transaction
1062:                transaction.setTransactionProcessor(adapter);
1063:
1064:                // update the state of the transaction
1065:                transaction.setState(Transaction.ASSIGNED);
1066:            }
1067:
1068:            /**
1069:             * Returns an array of provider identifiers, which could be used to pay
1070:             * for features.
1071:             *
1072:             * @param paymentInfo the payment information for the MIDlet which
1073:             *      initiated the payment
1074:             * @return the array of provider identifiers
1075:             */
1076:            protected final int[] getValidProviders(PaymentInfo paymentInfo) {
1077:                int numProviders = paymentInfo.getNumProviders();
1078:                int numAccepted = 0;
1079:                boolean[] accepted = new boolean[numProviders];
1080:
1081:                for (int i = 0; i < numProviders; ++i) {
1082:                    accepted[i] = false;
1083:
1084:                    ProviderInfo providerInfo = paymentInfo.getProvider(i);
1085:
1086:                    PaymentAdapter adapter = null;
1087:                    try {
1088:                        adapter = getAdapter(providerInfo.getAdapter(),
1089:                                providerInfo.getConfiguration());
1090:                    } catch (PaymentException e) {
1091:                    }
1092:                    if (adapter == null) {
1093:                        continue;
1094:                    }
1095:
1096:                    accepted[i] = true;
1097:                    ++numAccepted;
1098:                }
1099:
1100:                int[] providers = new int[numAccepted];
1101:                for (int i = 0, j = 0; i < numProviders; ++i) {
1102:                    if (accepted[i]) {
1103:                        providers[j++] = i;
1104:                    }
1105:                }
1106:
1107:                return providers;
1108:            }
1109:
1110:            /** Array of created payment adapters. */
1111:            private Hashtable paymentAdapters = new Hashtable();
1112:
1113:            /**
1114:             * Indicates if the given adapter is supported by the device.
1115:             *
1116:             * @param name the name of the adapter
1117:             * @return <code>true</code> if the given adapter is supported
1118:             */
1119:            public boolean isSupportedAdapter(String name) {
1120:                if ("PPSMS".equals(name)) {
1121:                    return true;
1122:                }
1123:                return false;
1124:            }
1125:
1126:            /**
1127:             * Creates the payment adapter for the given registered adapter name and
1128:             * the adapter configuration string. It returns <code>null</code> if no
1129:             * such adapter can be created.
1130:             *
1131:             * @param adapter the registered adapter name
1132:             * @param configuration the adapter configuration string
1133:             * @return the instance of the payment adapter or <code>null</code>
1134:             * @throws PaymentException if the adapter configuration string
1135:             *      has an invalid format
1136:             */
1137:            protected PaymentAdapter createAdapter(String adapter,
1138:                    String configuration) throws PaymentException {
1139:                if ("PPSMS".equals(adapter)) {
1140:                    if (configuration.indexOf(',') != -1) {
1141:                        String mcc = configuration.substring(0, configuration
1142:                                .indexOf(','));
1143:                        String mnc = configuration.substring(configuration
1144:                                .indexOf(',') + 1);
1145:
1146:                        if ((mcc != null) && (mnc != null)) {
1147:                            mcc = mcc.trim();
1148:                            mnc = mnc.trim();
1149:
1150:                            try {
1151:                                Integer.parseInt(mcc);
1152:                                Integer.parseInt(mnc);
1153:                            } catch (NumberFormatException nfe) {
1154:                                throw new PaymentException(
1155:                                        PaymentException.INVALID_ADAPTER_CONFIGURATION,
1156:                                        configuration);
1157:                            }
1158:
1159:                            if ((mcc.length() != 3) || (mnc.length() < 2)
1160:                                    || (mnc.length() > 3)) {
1161:                                throw new PaymentException(
1162:                                        PaymentException.INVALID_ADAPTER_CONFIGURATION,
1163:                                        configuration);
1164:                            }
1165:
1166:                            // get system property
1167:                            String MCC = System.getProperty("MCC");
1168:                            // get jsr default property
1169:                            if (null == MCC) {
1170:                                MCC = System.getProperty("payment.mcc");
1171:                            }
1172:                            // get system property
1173:                            String MNC = System.getProperty("MNC");
1174:                            // get jsr default property
1175:                            if (null == MNC) {
1176:                                MNC = System.getProperty("payment.mnc");
1177:                            }
1178:
1179:                            if (mcc.equals(MCC) && mnc.equals(MNC)) {
1180:                                return PPSMSAdapter.getInstance(configuration);
1181:                            } else {
1182:                                return null;
1183:                            }
1184:                        } else {
1185:                            throw new PaymentException(
1186:                                    PaymentException.INVALID_ADAPTER_CONFIGURATION,
1187:                                    configuration);
1188:                        }
1189:                    } else {
1190:                        throw new PaymentException(
1191:                                PaymentException.INVALID_ADAPTER_CONFIGURATION,
1192:                                configuration);
1193:                    }
1194:                }
1195:                return null;
1196:            }
1197:
1198:            /**
1199:             * Returns the payment adapter for the given registered adapter name and
1200:             * the adapter configuration string. It either returns an adapter created
1201:             * before for the given combination of <code>name</code> and
1202:             * <code>providerString</code> or creates a new instance if the old one
1203:             * doesn't exist. It returns <code>null</code> if no adapter of the given
1204:             * parameters can be created.
1205:             *
1206:             * @param name the registered adapter name
1207:             * @param configuration the adapter configuration string
1208:             * @return the instance of the payment adapter or <code>null</code>
1209:             * @throws PaymentException if the adapter configuration string
1210:             *      has an invalid format
1211:             */
1212:            PaymentAdapter getAdapter(String name, String configuration)
1213:                    throws PaymentException {
1214:                String adapterLookupString = name + "#"
1215:                        + normalizeConfigurationString(configuration);
1216:                PaymentAdapter adapter = (PaymentAdapter) paymentAdapters
1217:                        .get(adapterLookupString);
1218:                if (adapter == null) {
1219:                    adapter = createAdapter(name, configuration);
1220:                    if (adapter != null) {
1221:                        paymentAdapters.put(adapterLookupString, adapter);
1222:                    }
1223:                }
1224:                return adapter;
1225:            }
1226:
1227:            /**
1228:             * Replaces the current <code>Displayable</code> with the new one if the
1229:             * <code>nextDisplayable</code> is not <code>null</code> or it recovers
1230:             * the previous <code>Displayable</code> if the <code>nextDisplayable</code>
1231:             * is <code>null</code>.
1232:             *
1233:             * @param token a security token, which allows preempting
1234:             * @param nextDisplayable the <code>Displayable</code> to show or
1235:             *      <code>null</code> if the recovery of the old
1236:             *      <code>Displayable</code> is requested
1237:             */
1238:            protected abstract void preemptDisplay(SecurityToken token,
1239:                    Displayable nextDisplayable);
1240:
1241:            /** Current payment module UI. */
1242:            private PaymentModuleUI currentUI;
1243:
1244:            /**
1245:             * A method which is responsible for processing of transactions which are
1246:             * not yet assigned to the provider specific adapters or they are finished
1247:             * and need to be removed from the transaction processing queue.
1248:             *
1249:             * @param transaction the transaction to be processed
1250:             * @return the processed transaction or <code>null</code> if the transaction
1251:             *      should be removed from the transaction queue
1252:             */
1253:            public Transaction process(Transaction transaction) {
1254:                PaymentInfo paymentInfo;
1255:                boolean needsUpdate;
1256:
1257:                switch (transaction.getState()) {
1258:                case Transaction.ENTERED:
1259:                    paymentInfo = getPaymentInfo(transaction);
1260:                    needsUpdate = paymentInfo.needsUpdate();
1261:                    // === DEBUG MODE ===
1262:                    if (!needsUpdate && handleAutoRequestMode(transaction)) {
1263:                        break;
1264:                    }
1265:                    // === DEBUG MODE ===
1266:                    currentUI = new PaymentModuleUI(transaction);
1267:                    if (needsUpdate) {
1268:                        transaction.setState(Transaction.UPDATE);
1269:                    } else {
1270:                        transaction.setWaiting(true);
1271:                        currentUI.showProviderSelectionForm();
1272:                    }
1273:                    break;
1274:
1275:                case Transaction.UPDATE:
1276:                    // currentUI != null
1277:                    paymentInfo = getPaymentInfo(transaction);
1278:
1279:                    // validate the http or https connection now (before we preempt
1280:                    // the display)
1281:                    try {
1282:                        String name = paymentInfo.getUpdateURL();
1283:                        int permission = name.startsWith("https") ? Permissions.HTTPS
1284:                                : Permissions.HTTP;
1285:                        int colon = name.indexOf(':');
1286:                        if (colon != -1) {
1287:                            if (colon < name.length() - 1) {
1288:                                name = name.substring(colon + 1);
1289:                            } else {
1290:                                name = "";
1291:                            }
1292:                        }
1293:                        transaction.getTransactionModule().checkForPermission(
1294:                                permission, name);
1295:                    } catch (InterruptedException e) {
1296:                        // ignore, let the download fail
1297:                    }
1298:
1299:                    transaction.setWaiting(true);
1300:                    currentUI.showPaymentUpdateForm();
1301:
1302:                    Exception ex = null;
1303:                    try {
1304:                        synchronized (paymentInfo) {
1305:                            updatePaymentInfo(paymentInfo);
1306:                        }
1307:
1308:                        if (paymentInfo.cache()) {
1309:                            savePaymentInfo(transaction);
1310:                        }
1311:
1312:                        preemptDisplay(classSecurityToken, null);
1313:                        // === DEBUG MODE ===
1314:                        if (handleAutoRequestMode(transaction)) {
1315:                            transaction.setWaiting(false);
1316:                            currentUI = null;
1317:                            break;
1318:                        }
1319:                        // === DEBUG MODE ===
1320:                        currentUI.showProviderSelectionForm();
1321:                    } catch (InterruptedException e) {
1322:                        preemptDisplay(classSecurityToken, null);
1323:                        if (paymentInfo.needsUpdate()) {
1324:                            currentUI = null;
1325:
1326:                            // discard the transaction
1327:                            transaction.setState(Transaction.DISCARDED);
1328:                            transaction.setNeedsUI(false);
1329:                            transaction.setWaiting(false);
1330:                        } else {
1331:                            currentUI.showProviderSelectionForm();
1332:                        }
1333:                    } catch (PaymentException pe) {
1334:                        ex = pe;
1335:                    } catch (IOException ioe) {
1336:                        ex = ioe;
1337:                    }
1338:                    if (ex != null) {
1339:                        preemptDisplay(classSecurityToken, null);
1340:                        currentUI.displayException(utilities
1341:                                .getString(Utils.PAYMENT_ERROR_DLG_CAPTION),
1342:                                getErrorMessage(ex));
1343:
1344:                        // don't release the process method if waiting for an
1345:                        // update yet
1346:                        break;
1347:                    }
1348:
1349:                    // release the process method if waiting for an update
1350:                    synchronized (paymentInfo) {
1351:                        paymentInfo.notifyAll();
1352:                    }
1353:
1354:                    break;
1355:
1356:                case Transaction.REJECTED:
1357:                case Transaction.SUCCESSFUL:
1358:                case Transaction.FAILED:
1359:                    TransactionStore transactionStore = getTransactionStore();
1360:
1361:                    try {
1362:                        // create a transaction record for the transaction and add
1363:                        // it to the transaction notification queue
1364:                        TransactionRecord transactionRecord = transactionStore
1365:                                .addTransaction(transaction);
1366:                        addTransactionForNotification(transactionRecord,
1367:                                transaction.getTransactionModule());
1368:                    } catch (IOException e) {
1369:                    }
1370:
1371:                    // fall through
1372:
1373:                case Transaction.DISCARDED:
1374:                    return null;
1375:                }
1376:
1377:                return transaction;
1378:            }
1379:
1380:            /** Number of payment update file download attempts. */
1381:            private static final int MAX_RETRY_COUNT = 3;
1382:
1383:            /** UI update constant. */
1384:            private static final int RETRY_SHIFT = 2;
1385:
1386:            /** Payment info update stage. */
1387:            private static final int STATE_CONNECTING = 0;
1388:            /** Payment info update stage. */
1389:            private static final int STATE_SENDING_REQUEST = 1;
1390:            /** Payment info update stage. */
1391:            private static final int STATE_RETRY_WAITING = 2;
1392:            /** Payment info update stage. */
1393:            private static final int STATE_DOWNLOADING = 0x100;
1394:            /** Payment info update stage. */
1395:            private static final int STATE_VERIFYING = 0x101;
1396:            /** Payment info update stage. */
1397:            private static final int STATE_FINISHED = 0x200;
1398:
1399:            /** Index of MIME type object inside content type array. */
1400:            private static final int MIME_TYPE = 0;
1401:
1402:            /** Index of CHARSET type object inside content type array. */
1403:            private static final int CHARSET = 1;
1404:
1405:            /** Maximum size of payment update file. */
1406:            private static final int TRANSFER_CHUNK = 1024;
1407:
1408:            /** Payment info update file MIME type. */
1409:            private static final String UPDATE_MIME_TYPE = "text/vnd.sun.pay.provision";
1410:
1411:            /**
1412:             * Returns an error message for the given exception. It handles exceptions
1413:             * thrown during a payment update.
1414:             *
1415:             * @param e the exception
1416:             * @return the error message
1417:             */
1418:            private String getErrorMessage(Exception e) {
1419:                int prefixKey = Utils.PAYMENT_ERROR_PREFIX;
1420:                int suffixKey = Utils.PAYMENT_ERROR_SUFFIX;
1421:                int key = -1;
1422:                if (e instanceof  SecurityException) {
1423:                    key = Utils.PAYMENT_ERROR_PERMISSIONS;
1424:                    suffixKey = -1;
1425:                } else if (e instanceof  IOException) {
1426:                    key = Utils.PAYMENT_ERROR_DOWNLOAD_FAILED;
1427:                    suffixKey = -1;
1428:                } else if (e instanceof  PaymentException) {
1429:                    PaymentException pe = (PaymentException) e;
1430:
1431:                    switch (pe.getReason()) {
1432:                    case PaymentException.UNSUPPORTED_PAYMENT_INFO:
1433:                    case PaymentException.UNSUPPORTED_ADAPTERS:
1434:                    case PaymentException.UNSUPPORTED_PROVIDERS:
1435:                    case PaymentException.UNSUPPORTED_URL_SCHEME:
1436:                    case PaymentException.UNSUPPORTED_UPDATE_CHARSET:
1437:                        key = Utils.PAYMENT_ERROR_UPDATE_NOT_SUPPORTED;
1438:                        break;
1439:                    case PaymentException.INFORMATION_NOT_YET_VALID:
1440:                        key = Utils.PAYMENT_ERROR_UPDATE_NOT_YET_VALID;
1441:                        break;
1442:                    case PaymentException.INFORMATION_EXPIRED:
1443:                        key = Utils.PAYMENT_ERROR_UPDATE_EXPIRED;
1444:                        break;
1445:                    case PaymentException.MISSING_MANDATORY_ATTRIBUTE:
1446:                    case PaymentException.INVALID_ATTRIBUTE_VALUE:
1447:                    case PaymentException.INVALID_ADAPTER_CONFIGURATION:
1448:                    case PaymentException.INVALID_PRICE_INFORMATION:
1449:                    case PaymentException.INVALID_PROPERTIES_FORMAT:
1450:                        key = Utils.PAYMENT_ERROR_UPDATE_INVALID;
1451:                        break;
1452:                    case PaymentException.INCOMPLETE_INFORMATION:
1453:                        key = Utils.PAYMENT_ERROR_UPDATE_INCOMPLETE;
1454:                        break;
1455:                    case PaymentException.UPDATE_SERVER_NOT_FOUND:
1456:                    case PaymentException.UPDATE_NOT_FOUND:
1457:                    case PaymentException.INVALID_UPDATE_URL:
1458:                        key = Utils.PAYMENT_ERROR_UPDATE_NOT_FOUND;
1459:                        break;
1460:                    case PaymentException.UPDATE_SERVER_BUSY:
1461:                    case PaymentException.UPDATE_REQUEST_ERROR:
1462:                        key = Utils.PAYMENT_ERROR_CONNECTION_FAILED;
1463:                        break;
1464:                    case PaymentException.INVALID_UPDATE_TYPE:
1465:                        key = Utils.PAYMENT_ERROR_UPDATE_INVALID_TYPE;
1466:                        break;
1467:                    case PaymentException.EXPIRED_PROVIDER_CERT:
1468:                        key = Utils.PAYMENT_ERROR_CERTIFICATE_EXPIRED;
1469:                        break;
1470:                    case PaymentException.INVALID_PROVIDER_CERT:
1471:                        key = Utils.PAYMENT_ERROR_CERTIFICATE_INCORRECT;
1472:                        break;
1473:                    case PaymentException.EXPIRED_CA_CERT:
1474:                    case PaymentException.NO_TRUSTED_CHAIN:
1475:                        key = Utils.PAYMENT_ERROR_CERTIFICATE_UNTRUSTED;
1476:                        break;
1477:                    case PaymentException.SIGNATURE_VERIFICATION_FAILED:
1478:                        key = Utils.PAYMENT_ERROR_VERIFICATION_FAILED;
1479:                        break;
1480:                    }
1481:                }
1482:
1483:                StringBuffer buffer = new StringBuffer(utilities
1484:                        .getString(prefixKey));
1485:
1486:                if (key != -1) {
1487:                    buffer.append(" ");
1488:                    buffer.append(utilities.getString(key));
1489:                    if (suffixKey != -1) {
1490:                        buffer.append(" ");
1491:                        buffer.append(utilities.getString(suffixKey));
1492:                    }
1493:                }
1494:
1495:                return buffer.toString();
1496:            }
1497:
1498:            /**
1499:             * Creates a http or https connection with the payment update server. After
1500:             * opening the connection it sends the http request for the update file and
1501:             * checks the reply. If everything is correct it returns the connection
1502:             * which can be used to get the update file.
1503:             *
1504:             * @param url the URL of the payment update file
1505:             * @return the opened connection
1506:             * @throws PaymentException indicates failure
1507:             * @throws IOException indicates failure
1508:             * @throws InterruptedException indicates that the thread has been
1509:             *      interrupted while waiting for the server
1510:             */
1511:            private HttpConnection createConnection(String url)
1512:                    throws PaymentException, IOException, InterruptedException {
1513:                HttpConnection httpConnection = null;
1514:                int responseCode = -1;
1515:
1516:                try {
1517:                    int retry = 0;
1518:                    do {
1519:                        currentUI.notifyStateChange(STATE_CONNECTING
1520:                                + (retry << RETRY_SHIFT));
1521:
1522:                        Connection connection;
1523:                        try {
1524:                            connection = Connector.open(url);
1525:                        } catch (IllegalArgumentException e) {
1526:                            throw new PaymentException(
1527:                                    PaymentException.INVALID_UPDATE_URL, url,
1528:                                    null);
1529:                        } catch (ConnectionNotFoundException e) {
1530:                            throw new PaymentException(
1531:                                    PaymentException.INVALID_UPDATE_URL, url,
1532:                                    null);
1533:                        }
1534:
1535:                        if (!(connection instanceof  HttpConnection)) {
1536:                            connection.close();
1537:                            throw new PaymentException(
1538:                                    PaymentException.INVALID_UPDATE_URL, url,
1539:                                    null);
1540:                        }
1541:
1542:                        httpConnection = (HttpConnection) connection;
1543:
1544:                        // set User-Agent
1545:                        String prof = System
1546:                                .getProperty("microedition.profiles");
1547:                        int space = prof.indexOf(' ');
1548:                        if (space != -1) {
1549:                            prof = prof.substring(0, space);
1550:                        }
1551:                        httpConnection
1552:                                .setRequestProperty(
1553:                                        "User-Agent",
1554:                                        "Profile/"
1555:                                                + prof
1556:                                                + " Configuration/"
1557:                                                + System
1558:                                                        .getProperty("microedition.configuration"));
1559:
1560:                        // set Accept-Charset
1561:                        httpConnection
1562:                                .setRequestProperty(
1563:                                        "Accept-Charset",
1564:                                        "UTF-8, "
1565:                                                + System
1566:                                                        .getProperty("microedition.encoding"));
1567:
1568:                        // set Accept-Language
1569:                        String locale = System
1570:                                .getProperty("microedition.locale");
1571:                        if (locale != null) {
1572:                            httpConnection.setRequestProperty(
1573:                                    "Accept-Language", locale);
1574:                        }
1575:
1576:                        currentUI.notifyStateChange(STATE_SENDING_REQUEST
1577:                                + (retry << RETRY_SHIFT));
1578:
1579:                        try {
1580:                            responseCode = httpConnection.getResponseCode();
1581:                        } catch (IOException e) {
1582:                            if (httpConnection.getHost() == null) {
1583:                                throw new PaymentException(
1584:                                        PaymentException.INVALID_UPDATE_URL,
1585:                                        url, null);
1586:                            }
1587:
1588:                            throw new PaymentException(
1589:                                    PaymentException.UPDATE_SERVER_NOT_FOUND,
1590:                                    url, null);
1591:                        }
1592:
1593:                        if ((responseCode != HttpConnection.HTTP_UNAVAILABLE)
1594:                                || (++retry > MAX_RETRY_COUNT)) {
1595:                            break;
1596:                        }
1597:
1598:                        long sleepTime = 10000;
1599:
1600:                        String value = httpConnection
1601:                                .getHeaderField("Retry-After");
1602:                        // parse the Retry-After field
1603:                        if (value != null) {
1604:                            try {
1605:                                sleepTime = Integer.parseInt(value) * 1000;
1606:                            } catch (NumberFormatException ne) {
1607:                                // not a number
1608:                                try {
1609:                                    sleepTime = DateParser.parse(value);
1610:                                    sleepTime -= System.currentTimeMillis();
1611:                                } catch (IllegalArgumentException de) {
1612:                                }
1613:                            }
1614:                        }
1615:
1616:                        httpConnection.close();
1617:                        httpConnection = null;
1618:
1619:                        if (sleepTime < 0) {
1620:                            sleepTime = 10000;
1621:                        } else if (sleepTime > 60000) {
1622:                            sleepTime = 60000;
1623:                        }
1624:
1625:                        currentUI.notifyStateChange(STATE_RETRY_WAITING
1626:                                + (retry << RETRY_SHIFT));
1627:
1628:                        Thread.sleep(sleepTime);
1629:
1630:                    } while (true);
1631:
1632:                    switch (responseCode) {
1633:                    case HttpConnection.HTTP_OK:
1634:                        break;
1635:                    case HttpConnection.HTTP_NOT_FOUND:
1636:                        throw new PaymentException(
1637:                                PaymentException.UPDATE_NOT_FOUND, url, null);
1638:                    case HttpConnection.HTTP_UNAVAILABLE:
1639:                        throw new PaymentException(
1640:                                PaymentException.UPDATE_SERVER_BUSY, url, null);
1641:                    default:
1642:                        throw new PaymentException(
1643:                                PaymentException.UPDATE_REQUEST_ERROR, Integer
1644:                                        .toString(responseCode), null);
1645:                    }
1646:
1647:                } catch (PaymentException e) {
1648:                    if (httpConnection != null) {
1649:                        httpConnection.close();
1650:                    }
1651:                    // rethrow
1652:                    throw e;
1653:                } catch (IOException e) {
1654:                    if (httpConnection != null) {
1655:                        httpConnection.close();
1656:                    }
1657:                    // rethrow
1658:                    throw e;
1659:                }
1660:
1661:                return httpConnection;
1662:            }
1663:
1664:            /**
1665:             * Updates the given payment information from the update URL. If an
1666:             * exception is thrown during the update, the payment information is not
1667:             * changed.
1668:             *
1669:             * @param paymentInfo the payment information
1670:             * @throws PaymentException indicates failure
1671:             * @throws IOException indicates failure
1672:             * @throws InterruptedException if the update has been stopped by the user
1673:             */
1674:            private void updatePaymentInfo(PaymentInfo paymentInfo)
1675:                    throws PaymentException, IOException, InterruptedException {
1676:                String url = paymentInfo.getUpdateURL();
1677:
1678:                // 1. CONNECT TO THE SERVER AND SEND REQUEST
1679:                HttpConnection httpConnection = createConnection(url);
1680:
1681:                String[] contentType = { null, null };
1682:                parseContentType(contentType, httpConnection.getType());
1683:
1684:                // check the mime type
1685:                if (!UPDATE_MIME_TYPE.equals(contentType[MIME_TYPE])) {
1686:                    httpConnection.close();
1687:                    throw new PaymentException(
1688:                            PaymentException.INVALID_UPDATE_TYPE,
1689:                            contentType[MIME_TYPE], null);
1690:                }
1691:
1692:                // 2. DOWNLOAD THE UPDATE FILE
1693:                byte[] data = null;
1694:
1695:                InputStream is;
1696:                try {
1697:                    currentUI.notifyStateChange(STATE_DOWNLOADING);
1698:
1699:                    is = httpConnection.openDataInputStream();
1700:                    try {
1701:                        ByteArrayOutputStream os = new ByteArrayOutputStream(
1702:                                TRANSFER_CHUNK);
1703:                        byte[] buffer = new byte[TRANSFER_CHUNK];
1704:                        int read;
1705:                        while ((read = is.read(buffer, 0, TRANSFER_CHUNK)) > 0) {
1706:                            os.write(buffer, 0, read);
1707:                        }
1708:
1709:                        // not necessary
1710:                        os.flush();
1711:
1712:                        data = os.toByteArray();
1713:                        os.close();
1714:
1715:                    } finally {
1716:                        is.close();
1717:                    }
1718:                } finally {
1719:                    httpConnection.close();
1720:                }
1721:
1722:                // 3. VERIFY AND UPDATE PAYMENT INFORMATION
1723:                currentUI.notifyStateChange(STATE_VERIFYING);
1724:                paymentInfo.updatePaymentInfo(data, contentType[CHARSET]);
1725:
1726:                currentUI.notifyStateChange(STATE_FINISHED);
1727:            }
1728:
1729:            /**
1730:             * Returns the end index of the first substring of the given string which
1731:             * matches the given mask or <code>-1</code> if no such substring can be
1732:             * found. The mask is given as a character array and it has only one
1733:             * special character '+', which represents 0..* number of space characters.
1734:             *
1735:             * @param string the string
1736:             * @param mask the mask
1737:             * @return the index or <code>-1</code>
1738:             */
1739:            private static int findEndOf(String string, char[] mask) {
1740:                char[] data = string.toCharArray();
1741:
1742:                int i = 0; // index into data
1743:                int j = 0; // index into mask
1744:                int k = 0; // saved index
1745:
1746:                while ((i < data.length) && (j < mask.length)) {
1747:                    if (mask[j] == '+') {
1748:                        if (data[i] <= ' ') {
1749:                            ++i;
1750:                        } else {
1751:                            ++j;
1752:                        }
1753:                        continue;
1754:                    }
1755:                    if (data[i] == mask[j]) {
1756:                        ++i;
1757:                        ++j;
1758:                        continue;
1759:                    }
1760:                    i = k + 1;
1761:                    j = 0;
1762:                    k = i;
1763:                }
1764:
1765:                for (; (j < mask.length) && (mask[j] == '+'); ++j) {
1766:                }
1767:
1768:                return (j == mask.length) ? i : -1;
1769:            }
1770:
1771:            /** Mask for content type searching. */
1772:            private static final char[] CHARSET_MASK = { ';', '+', 'c', 'h',
1773:                    'a', 'r', 's', 'e', 't', '+', '=' };
1774:
1775:            /**
1776:             * Extracts the MIME type and the character set from the given Content-Type
1777:             * value. It returns the extracted values in the given string array. They
1778:             * are stored under the <code>MIME_TYPE</code> and <code>CHARSET</code>
1779:             * indexes.
1780:             *
1781:             * @param values the array for extracted values
1782:             * @param contentType the Content-Type value
1783:             */
1784:            private static void parseContentType(String[] values,
1785:                    String contentType) {
1786:                int index;
1787:                String mimeType = null;
1788:                String charset = "ISO-8859-1"; // the default charset
1789:
1790:                // decode mimeType and charset
1791:                if (contentType != null) {
1792:                    index = contentType.indexOf(';');
1793:                    mimeType = contentType;
1794:                    if (index != -1) {
1795:                        mimeType = contentType.substring(0, index);
1796:                        index = findEndOf(contentType, CHARSET_MASK);
1797:                        if (index != -1) {
1798:                            int index2 = contentType.indexOf(';', index);
1799:                            if (index2 == -1) {
1800:                                index2 = contentType.length();
1801:                            }
1802:                            charset = contentType.substring(index, index2);
1803:                            charset = charset.trim().toUpperCase();
1804:                        }
1805:                    }
1806:                    mimeType = mimeType.trim().toLowerCase();
1807:                }
1808:
1809:                values[MIME_TYPE] = mimeType;
1810:                values[CHARSET] = charset;
1811:            }
1812:
1813:            /**
1814:             * Normalizes the given configuration strings. It removes all white spaces
1815:             * before and after any comma in the string.
1816:             *
1817:             * @param configuration the input string
1818:             * @return the normalized string
1819:             */
1820:            private static String normalizeConfigurationString(
1821:                    String configuration) {
1822:                StringBuffer reconstructed = new StringBuffer();
1823:                Vector elements = Util.getCommaSeparatedValues(configuration);
1824:
1825:                int count = elements.size();
1826:                if (count > 0) {
1827:                    reconstructed.append((String) elements.elementAt(0));
1828:                    for (int i = 1; i < count; ++i) {
1829:                        reconstructed.append(",");
1830:                        reconstructed.append((String) elements.elementAt(i));
1831:                    }
1832:                }
1833:
1834:                return reconstructed.toString();
1835:            }
1836:
1837:            // === DEBUG MODE ===
1838:            /**
1839:             * Handles the success/failure/random debug mode for the given transaction. 
1840:             * It's called from the parts of the <code>PaymentModule</code> code where 
1841:             * this mode can be applied. If the debug mode is in effect the transaction 
1842:             * state is set accordingly and the method returns <code>true</code>.
1843:             *
1844:             * @param transaction the transaction
1845:             * @return <code>true</code> if the transaction is handled in the method 
1846:             */
1847:            protected boolean handleTransactionDebugMode(Transaction transaction) {
1848:                return false;
1849:            }
1850:
1851:            /**
1852:             * Handles the auto request debug mode for the given transaction. It's
1853:             * called from the parts of the <code>PaymentModule</code> code where this
1854:             * mode can be applied. If the auto request mode is in effect the
1855:             * transaction state is set accordingly and the method returns
1856:             * <code>true</code>.
1857:             *
1858:             * @param transaction the transaction
1859:             * @return <code>true</code> if the transaction is handled in the method
1860:             *      (= the auto request mode is in effect)
1861:             */
1862:            protected boolean handleAutoRequestMode(Transaction transaction) {
1863:                return false;
1864:            }
1865:
1866:            // === DEBUG MODE ===
1867:
1868:            static {
1869:                /* Hand out security token */
1870:                PPSMSAdapter.initSecurityToken(classSecurityToken);
1871:            }
1872:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.