FileDocCategorySizeDatePackage
CldcTransactionRecordImpl.javaAPI DocphoneME MR2 API (J2ME)15327Wed May 02 18:00:44 BST 2007com.sun.j2me.payment

CldcTransactionRecordImpl.java

/*
 *   
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */

package com.sun.j2me.payment;

import java.util.Vector;

import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ByteArrayOutputStream;

import javax.microedition.payment.TransactionRecord;

import com.sun.j2me.payment.Transaction;
import com.sun.j2me.payment.ProviderInfo;

/**
 * This class implements <code>TransactionRecord</code>.
 *
 * @version 1.4
 * @see javax.microedition.payment.TransactionRecord
 */
final class CldcTransactionRecordImpl implements TransactionRecord {
    
    /** Status of Transaction - Reserved */
    static final int RESERVED = 0;
    /** Status of Transaction - Missed */
    static final int MISSED = 1;
    /** Status of Transaction - Passed */
    static final int PASSED = 2;

    /** Transaction ID */
    private int transactionID;
    /** Application ID */
    private int applicationID;
    /** Application Name */
    private String applicationName;
    /** Feature ID */
    private int featureID;
    /** Feature Title */
    private String featureTitle;
    /** price */
    private double price;
    /** currency */
    private String currency;
    /** state of Transaction */
    private int state;
    /** Timestamp of Transaction */
    private long timestamp;
    /** Transaction status - Reserved/Missed/Passed */
    private int status;
    /** Fake Transaction */
    private boolean fake;

    /** record ID */
    private int recordID;
    
    /** empty currency */
    private static final String EMPTY_CURRENCY = "";
    /** USD currency */
    private static final String TEMPLATE_CURRENCY = "USD";
    
    /**
     * Creates an instance of the <code>CldcTransactionRecordImpl</code> class
     * from the given application ID, name of the MIDlet suite, transaction,
     * the timestamp and the fake flag. The new transaction record has its
     * <code>wasMissed</code> flag set.
     *
     * @param applicationID the application ID
     * @param applicationName the application name
     * @param transaction the transaction
     * @param timestamp the timestamp
     * @param fake the fake flag
     */
    CldcTransactionRecordImpl(int applicationID, String applicationName, 
            Transaction transaction, long timestamp, boolean fake) {
        this.applicationID = applicationID;
        this.applicationName = applicationName;
        
        transactionID = transaction.getTransactionID();
        featureID = transaction.getFeatureID();
        featureTitle = transaction.getFeatureTitle();
        price = transaction.getPrice();
        currency = transaction.getCurrency();
        
        if (currency == null) {
            currency = EMPTY_CURRENCY;
        }

        switch (transaction.getState()) {
            case Transaction.SUCCESSFUL:
                state = TransactionRecord.TRANSACTION_SUCCESSFUL;
                break;
            case Transaction.REJECTED:
                state = TransactionRecord.TRANSACTION_REJECTED;
                break;
            case Transaction.FAILED:
                state = TransactionRecord.TRANSACTION_FAILED;
                break;
        }
        
        this.timestamp = timestamp;
        this.fake = fake;
        this.status = RESERVED;
        
        this.recordID = 0;
    }

    /**
     * Returns the exact duplicate of this transaction record except of the
     * <code>wasMissed</code> flag which is set to the value of the input
     * parameter.
     *
     * @return the new duplicate transaction record
     */
    CldcTransactionRecordImpl createDuplicateRecord() {
        CldcTransactionRecordImpl newRecord = new CldcTransactionRecordImpl();
        
        newRecord.transactionID = transactionID;
        newRecord.applicationID = applicationID;
        newRecord.applicationName = applicationName;
        newRecord.featureID = featureID;
        newRecord.featureTitle = featureTitle;
        newRecord.price = price;
        newRecord.currency = currency;
        newRecord.state = state;
        newRecord.timestamp = timestamp;
        newRecord.fake = fake;
        newRecord.recordID = recordID;

        newRecord.status = PASSED;
        
        return newRecord;
    }
    
    /**
     * Returns the feature ID.
     *
     * @return the feature ID
     */
    public int getFeatureID() {
        return featureID;
    }

    /**
     * Returns the timestamp when the transaction was finished.
     *
     * @return the timestamp
     */
    public long getFinishedTimestamp() {
        return timestamp;
    }

    /**
     * Returns the final state of the transaction. It can be one of 
     * <code>TRANSACTION_SUCCESSFUL</code>, <code>TRANSACTION_FAILED</code>,
     * <code>TRANSACTION_REJECTED</code>.
     *
     * @return the final state
     * @see javax.microedition.payment.TransactionRecord#TRANSACTION_SUCCESSFUL
     * @see javax.microedition.payment.TransactionRecord#TRANSACTION_FAILED
     * @see javax.microedition.payment.TransactionRecord#TRANSACTION_REJECTED
     */
    public int getState() {
        return state;
    }

    /**
     * Sets the state of the transaction. It can be one of 
     * <code>TRANSACTION_SUCCESSFUL</code>, <code>TRANSACTION_FAILED</code>,
     * <code>TRANSACTION_REJECTED</code>.
     *
     * @param transaction the transaction
     */
    void update(Transaction transaction) {
            timestamp = System.currentTimeMillis();
            switch (transaction.getState()) {
            case Transaction.SUCCESSFUL:
                state = TransactionRecord.TRANSACTION_SUCCESSFUL;
                break;
            case Transaction.REJECTED:
                state = TransactionRecord.TRANSACTION_REJECTED;
                break;
            case Transaction.FAILED:
                state = TransactionRecord.TRANSACTION_FAILED;
                break;
        }
    }
    /**
     * Returns the transaction ID of the transaction.
     *
     * @return the transaction ID
     */
    public int getTransactionID() {
        return transactionID;
    }

    /**
     * Indicates if the MIDlet have or haven't been notified about the final 
     * state of the transaction.
     *
     * @return <code>true</code> if the MIDlet haven't been notified yet
     */
    public boolean wasMissed() {
        return (status != PASSED);
    }

    /**
     * Indicates status of Transaction:
     * RESERVED/MISSED/PASSED
     * @return  RESERVED if Transaction is started
     *          MISSED if confirmation is received
     *          PASSED if user was notifyed
     */
    public int getStatus() {
        return status;
    }

    /**
     * Change status of Transaction:
     * RESERVED/MISSED/PASSED
     * @param status of Transaction 
     */
    void setStatus(int status) {
        if ((status == MISSED) || (status == PASSED))
        {
            this.status = status;
        }
    }

    /**
     * Returns the appplication ID of the application (MIDlet) which initiated
     * the transaction.
     *
     * @return the application ID
     * @see com.sun.j2me.payment.TransactionStore#getNextApplicationID
     */
    public int getApplicationID() {
        return applicationID;
    }
    
    /**
     * Returns the name of the application (MIDlet) which initiated the 
     * transaction.
     *
     * @return the application name
     */
    public String getApplicationName() {
        return applicationName;
    }
    
    /**
     * Returns the title of the feature.
     *
     * @return the feature title
     */
    public String getFeatureTitle() {
        return featureTitle;
    }

    /**
     * Returns the price of the feature or <code>0</code> if it hasn't been
     * set when the transaction ended.
     *
     * @return the price
     */
    public double getPrice() {
        return price;
    }
    
    /**
     * Returns the currency of the price or an empty string if it hasn't been
     * set when the transaction ended.
     *
     * @return the currency code
     */
    public String getCurrency() {
        return currency;
    }

    /**
     * Indicates if the current transaction record is fake. A fake record isn't
     * permanently stored into the transaction store file. Fake records are 
     * produced in the debug mode and by MIDlet suites which are run without
     * beeing installed.
     *
     * @return <code>true</code> if the record is fake
     */
    public boolean isFake() {
        return fake;
    }

    /**
     * Returns the size (in bytes) which is needed to serialize the transaction
     * record.
     *
     * @return the size of the serialized transaction record
     */
    int getSerializedSize() {
        if (fake) {
            return 0;
        }
        
        int size = 0;
        try {
            size = calculateSize(applicationName, featureTitle);
        } catch (IOException e) {
        }
        
        return size;
    }
    
    /**
     * Constructs empty instance
     */
    private CldcTransactionRecordImpl() {
    }
    
    // === DEBUG MODE ===
    /**
     * Creates a fake transaction record from the given information. It's
     * used in the debug mode.
     *
     * @param transactionID unique ID of transaction
     * @param applicationID the application ID
     * @param applicationName the application name
     * @param featureID the feature ID
     * @param featureTitle the title of the feature 
     * @param price the price of the feature
     * @param currency the currency to pay
     * @param state the state of the transaction
     * @param timestamp the timestamp
     *
     * @return new instance of CldcTransactionRecordImpl 
     */
    static CldcTransactionRecordImpl createFakeRecord(int transactionID,
            int applicationID, String applicationName, 
            int featureID, String featureTitle, 
            double price, String currency, int state,
            long timestamp) {
        CldcTransactionRecordImpl record = new CldcTransactionRecordImpl();
                
        record.transactionID = transactionID;
        record.applicationID = applicationID;
        record.applicationName = applicationName;
        record.featureID = featureID;
        record.featureTitle = featureTitle;
        record.price = price;
        record.currency = currency;
        record.state = state;
        record.timestamp = timestamp;
        
        record.status = RESERVED;
        record.fake = true;
        
        record.recordID = 0;
        
        return record;
    }
    // === DEBUG MODE ===
    
    /**
     * Creates a new transaction record from the data read from the given input 
     * stream.
     *
     * @param is the input stream
     * @return the new transaction record
     * @throws IOException indicates a reading failure
     */
    static CldcTransactionRecordImpl read(DataInputStream is) 
            throws IOException {
        CldcTransactionRecordImpl newRecord = new CldcTransactionRecordImpl();
        
        newRecord.transactionID = is.readInt();
        newRecord.applicationID = is.readInt();
        newRecord.applicationName = is.readUTF();
        newRecord.featureID = is.readInt();
        newRecord.featureTitle = is.readUTF();
        newRecord.price = is.readDouble();
        newRecord.currency = is.readUTF();
        newRecord.state = is.readInt();
        newRecord.timestamp = is.readLong();
        newRecord.status = is.readInt();

        return newRecord;
    }
    
    /**
     * Stores the transaction record into the given output stream.
     *
     * @param os the output stream
     * @throws IOException indicates a writing failure
     */
    void write(DataOutputStream os) throws IOException {
        os.writeInt(transactionID);
        os.writeInt(applicationID);
        os.writeUTF(applicationName);
        os.writeInt(featureID);
        os.writeUTF(featureTitle);
        os.writeDouble(price);
        os.writeUTF(currency);
        os.writeInt(state);
        os.writeLong(timestamp);
        os.writeInt(status);
    }

    /**
     * Calculates the size in bytes which will be needed to store a transaction
     * record with the specified application name and feature title.
     *
     * @param applicationName the application name
     * @param featureTitle the feature title
     * @return the size needed to store such record
     */
    static int calculateSize(String applicationName, 
            String featureTitle) throws IOException {
        // calculate the required space
        int size;
        
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DataOutputStream os = new DataOutputStream(bos);
        
        try {
            os.writeUTF(applicationName);
            os.writeUTF(featureTitle);
            os.writeUTF(TEMPLATE_CURRENCY);
            size = bos.size();
            
        } finally {
            os.close();
        }
        
        size += 4 + // transactionID
                4 + // applicationID
                4 + // featureID
                8 + // price
                4 + // state
                8 + // timestamp
                4;  // status
        
        return size;
    }
    
    /**
     * Stores Record ID for internal usage
     *
     * @param recordID unique ID of the Transaction Record 
     */
    void setRecordID(int recordID) {
        this.recordID = recordID;
    }

    /**
     * Returns Record ID of the transaction
     *
     * @return recordID of the Transaction
     */
    int getRecordID() {
        return recordID;
    }
    
    /**
     * Adds Transaction Record into the list
     * 
     * @param v the list of sorted transactions
     * @return index in the element
     */
    int add2list(Vector v) {
        int count = v.size();
        if (count == 0) {
            v.addElement(this);
        } else {
            do {
                if (((CldcTransactionRecordImpl)v.elementAt(count-1)).
                        getFinishedTimestamp() <= this.timestamp) {
                    v.insertElementAt(this,  count);
                    break;
                }
                count--;
            } while (count > 0);
            if (count == 0) {
                v.insertElementAt(this,  count);
            }
        }
        return count;
    }
}