Sun Java System Mobile Enterprise Platform 1.0 Developer's Guide for Enterprise Connectors

Extending the BusinessObjectProvider Class to Access a Sun JCA Adapter

To allow your Enterprise Connector to work with a Sun JCA Adapter, your BusinessObjectProvider implementation needs to create a connection to the Adapter in its initialize method, close that connection in its terminate method, and retrieve objects through the Adapter in its getBusinessObject method.

For a SAP BAPI application, for example, you import the following packages:

import com.stc.connector.appconn.common.ApplicationConnectionFactory;
import com.stc.connector.appconn.common.ApplicationConnection;
import com.stc.connector.sapbapiadapter.appconn.SAPApplicationConnection;
import com.stc.util.OtdObjectFactory;

When you create a provider for a Customer business object, you declare objects like the following. The customer.Customer class is generated by the OTD wizard.

public class CustomerProvider extends BusinessObjectProvider<Customer> {
    ...
    public static final String SAP_JNDI_DATASOURCE = "jcaps/sap";
    public static final String REPOSITORY_NAME = "SAPRepository";
    
    private ApplicationConnectionFactory mJCAsapadapter = null;
    private ApplicationConnection mJCAsapadapterConnection = null;
    private customer.Customer mJCAsapcustomerCommObj = null;

The provider's initialize method then allocates these resources. It obtains an ApplicationConnectionFactory object by means of a JNDI lookup, then uses the factory to create the ApplicationConnection object. These method calls are the same no matter which EIS/EAI system you are using:

    @Override
    public void initialize() {
        logger.debug("Initializing provider " + this);

        try {
            InitialContext ic = new InitialContext();
            // First get ApplicationConnectionFactory through JNDI lookup
            mJCAsapadapter = 
                (ApplicationConnectionFactory) ic.lookup(SAP_JNDI_DATASOURCE);

            /* Then create ApplicationConnection. One AppConn can be dynamically
             * allocated to a physical connection defined in connection pool;
             * this results in connection reuse according to JCA and Appserver
             * contract
             */
            mJCAsapadapterConnection = mJCAsapadapter.getConnection();

The initialize method then uses the OtdObjectFactory to create an instance of a SAP customer communication object. Methods called on this object are specific to the SAP OTD. The code casts the generic ApplicationConnection object mJCAsapadapterConnection to another application connection specific to SAP:

            /* Create Customer communication object
             */
            mJCAsapcustomerCommObj = 
                (customer.Customer) OtdObjectFactory.createInstance(null,
                    "customer.Customer");

            /* Set ApplicationConnection on Customer communication object
             */
            mJCAsapcustomerCommObj.setAppConn(
                (SAPApplicationConnection) mJCAsapadapterConnection);

The initialize method next uses the ECBO API SessionContext object to retrieve the user name and password. It then uses these values to create user credentials specific to SAP, and finally connects to the Sun JCA Adapter for SAP.

            // Get backend credentials from provider's context
            SessionContext sessionContext = getSessionContext();
            String param = sessionContext.getUsername();
            if (param != null) {
                mJCAsapcustomerCommObj.getSAPConnectionParams().setUserid(param);
            }
            param = sessionContext.getPassword();
            if (param != null) {
                mJCAsapcustomerCommObj.getSAPConnectionParams().setPassword(param);
            }
            mJCAsapcustomerCommObj.connectWithNewParams();

            ic.close();
        }
        catch (Exception ex) {
            logger.debug("Initializing provider exception" + ex.getMessage());
            throw new RuntimeException(ex);
        }
    }

The terminate method closes the connection created by the initialize method:

    @Override
    public void terminate() {
        logger.debug("Terminating provider " + this);

        try {
            if (mJCAsapadapterConnection != null) {
                mJCAsapadapterConnection.close();
                logger.info("terminate provider close connection" 
                        + mJCAsapadapterConnection.toString());
            }
        }
        catch (Exception e) {
            logger.debug("terminating provider exception" + e.getMessage());
            throw new RuntimeException(e);
        }
    }

The provider code also implements a utility method, getSAPCustomerClient, which retrieves the customer communication object:

    /** 
     * @return SAPCustomerClient object that can be used to 
     * operate on a Customer BAPI.
     */
    public customer.Customer getSAPCustomerClient() {
        return mJCAsapcustomerCommObj;
    }

The getBusinessObjects method uses the getSAPCustomerClient method to retrieve the SAP customer data and store it in the Enterprise Connector's Customer object. It again calls methods on the communication object generated by the OTD wizard.

    @Override
    //Retrieve all IDocs and map here between Customer and VendorAccount Object
    public List<Customer> getBusinessObjects() {
        logger.debug("Getting objects from provider " + this);

        HashMap<String, Customer> customerMap = new HashMap<String, Customer>();

        try {
            // Getting customer list
            getSAPCustomerClient().getGetList().getIDRANGE(0).setOPTION("CP");
            getSAPCustomerClient().getGetList().getIDRANGE(0).setLOW("*");
            logger.info("Executing Customer with the following values Option " +
                "[" + getSAPCustomerClient().getGetList().getIDRANGE(0).getLOW() 
                + "] Option [" 
                + getSAPCustomerClient().getGetList().getIDRANGE(0).getOPTION() + "]");
            getSAPCustomerClient().getGetList().execute();

            // Process returned data and populate customer list
            customer.Customer.GetList.ExportParams.RETURN ret =
                getSAPCustomerClient().getGetList().getExportParams().getRETURN();
            logger.info("Retrieved [" 
                + getSAPCustomerClient().getGetList().countADDRESSDATA() 
                + "] customers");

            customer.Customer.GetList.ADDRESSDATA[] addressList =
                getSAPCustomerClient().getGetList().getADDRESSDATA();
            for (int i = 0; i < addressList.length; i++) {
                customer.Customer.GetList.ADDRESSDATA addr = addressList[i];

                // Ignore companies whose names start with "DELETED" -- hack
                if (!addr.getNAME().startsWith("DELETED")) {
                    // Ignore customers whose names are repeated
                    if (customerMap.containsKey(addr.getNAME())) {
                        continue;
                    }

                    // Create a new Customer instance 
                    Customer comp = new Customer(this);

                    // Set unique name for business object
                    comp.setName(addr.getNAME());

                    // Set customer number and name
                    comp.setCustomerNumber(addr.getCUSTOMER());
                    comp.setCustomerName(addr.getNAME());

                    // Get sales area
                    getSAPCustomerClient().getGetSalesAreas().getImportParams()
                        .setCUSTOMERNO(comp.getCustomerNumber());
                    getSAPCustomerClient().getGetSalesAreas().execute();
                    String retNo = getSAPCustomerClient().getGetSalesAreas()
                        .getExportParams().getRETURN().getMESSAGE();
                    String retMsg = getSAPCustomerClient().getGetSalesAreas()
                        .getExportParams().getRETURN().getCODE();
                    logger.info("Return Number [" + retNo + "] retMsg [" 
                        + retMsg + "].");
                    if (retNo.length() > 0) {
                        throw new RuntimeException(retMsg);
                    }

                    // Set sales related fields
                    comp.setSalesOrg(getSAPCustomerClient().getGetSalesAreas()
                        .getSALESAREAS(0).getSALESORG());
                    comp.setDistChannel(getSAPCustomerClient().getGetSalesAreas()
                        .getSALESAREAS(0).getDISTRCHN());
                    comp.setDivision(getSAPCustomerClient().getGetSalesAreas()
                        .getSALESAREAS(0).getDIVISION());

                    // Get detail on customer
                    getSAPCustomerClient().getGetDetail1().getImportParams()
                        .setCUSTOMERNO(comp.getCustomerNumber());
                    getSAPCustomerClient().getGetDetail1().getImportParams()
                        .setPI_SALESORG(comp.getSalesOrg());
                    getSAPCustomerClient().getGetDetail1().getImportParams()
                        .setPI_DISTR_CHAN(comp.getDistChannel());
                    getSAPCustomerClient().getGetDetail1().getImportParams()
                        .setPI_DIVISION(comp.getDivision());
                    getSAPCustomerClient().getGetDetail1().execute();
                    retNo = 
                        getSAPCustomerClient().getGetDetail1().getExportParams()
                            .getRETURN().getMESSAGE();
                    retMsg = 
                        getSAPCustomerClient().getGetDetail1().getExportParams()
                            .getRETURN().getNUMBER();
                    logger.info("Return Number [" + retNo + "] retMsg [" 
                        + retMsg + "].");
                    if (retNo.length() > 0) {
                        throw new RuntimeException(retMsg);
                    }

                    // Populate customer object data
                    customer.Customer.GetDetail1.ExportParams.PE_COMPANYDATA 
                        currAddr = getSAPCustomerClient().getGetDetail1()
                            .getExportParams().getPE_COMPANYDATA();
                    comp.setCity(currAddr.getCITY());
                    comp.setPostalCode(currAddr.getPOSTL_COD1());
                    comp.setStreet(currAddr.getSTREET());
                    comp.setCountryKey(currAddr.getCOUNTRY());
                    comp.setLanguageKey(currAddr.getLANGU_ISO());
                    comp.setRegion(currAddr.getREGION());
                    comp.setTelephone(currAddr.getTEL1_NUMBR());
                    comp.setFaxNumber(currAddr.getFAX_NUMBER());
                    comp.setCurrencyKey(currAddr.getCURRENCY());

                    customerMap.put(comp.getCustomerName(), comp);
                }
            }
            return new ArrayList<Customer>(customerMap.values());
        }
        catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

The getRepositoryName and newBusinessObject methods have implementations very similar to those in the MusicAlbumProvider class:

    @Override
    public String getRepositoryName() {
        return REPOSITORY_NAME;
    }

    @Override
    public Customer newBusinessObject() {
        return new Customer(this);
    }

The other methods in the provider class use the default BusinessObjectProvider implementation: getSessionContext, setSessionContect, and getTransactionManager.