Sunday, November 28, 2010

Oracle AF Trains

Steps

1. create a shared (standalone) train region

2. create your train pages (the individual steps)


3. create the links in the shared region
- configure the Destination URI to point on the individual pages
- also configure the Text parameter (this will be the one shown above the pages)






4. In your page's layout region, add a location
- configure the Extends property to point to the shared train region you created in the first step


*make sure you have Application Modules configured on your pages (in contrast to pages, this attribute follows the java package syntax)





5. create a page for your Navigation Bar


6. well, finally create the Navigation Bar region
- configure the First Step and Last Step attributes. Normally you would like to configure First Step to 1 and Last Step to the number of the last page (in this case, 2)


7. create links inside that region
- configure the Destination URI in this format OA.jsp?page=/xxx/xxx/xxx/xxxPG
- configure the text visual property

8. create a pageButtonBar region for each individual step pages (you may create the first then copy paste to the rest)

*make sure the Nav Bar links text and the Train links text are identical

Thursday, November 25, 2010

Adding Time Units to SYSDATE

SELECT SYSDATE + INTERVAL '30' MINUTE
FROM SYS.DUAL


simply nice ^^ <3

l_performance_rating_year1 VARCHAR2(10) := TO_CHAR(SYSDATE - INTERVAL '3' YEAR, 'YYYY');
l_performance_rating_year2 VARCHAR2(10) := TO_CHAR(SYSDATE - INTERVAL '2' YEAR, 'YYYY');
l_performance_rating_year3 VARCHAR2(10) := TO_CHAR(SYSDATE - INTERVAL '1' YEAR, 'YYYY');

SYS.DUAL

First time seeing it XD

SELECT WF_NOTIFICATIONS_S.NEXTVAL
INTO nid
FROM SYS.DUAL;


got used to the plain DUAL, I didn't noticed it's from SYS schema XD? just something trivial

(String) Object vs Object.toString()

well, just a thought - I searched around and it seems casting is preferred over the toString() method call XD It's slightly "faster" .. but prolly this info would only be useful if you're dealing with tons of Objects to convert into Strings ^^;;

Oracle DECODE

Well I've used this a dozen of times .. just noting myself :D

SELECT DECODE(XXHLS_STAFF_PKG.GET_CATEGORY_FN(SYSDATE,PERSON_ID), 'PS', 'LIBOR Interest Rate', 'SS', 'Interest Rate') AS TYPE
FROM XXHLS.XXHLS_LOAN_APPLICATION


=A=

Wednesday, November 24, 2010

Commit in DML Procedure

PROCEDURE armageddon
    IS
    BEGIN
        purge_usr_loan_data_fn(113814);
        commit;
    END armageddon;


Well just a note to myself. If you want your DML changes reflected in the database, issue the command commit =A=

The procedure above calls on another procedure programmed to delete all data I persisted in the database ^^ Having tons of test data could be annoying most of the time, so I need to clean them up once in a while.

Monday, November 22, 2010

Dynamic Messages Using Tokens


First you must create a message in Oracle Apps and tag the dynamic part of the message with an ampersand "&". By convention these tags must be in uppercase. - &LOAN_ENTRIES

Java Code in Controller

MessageToken[] tokens = {new MessageToken("LOAN_ENTRIES", getInstructionLoanEntries(loanTypeCode,am)) };
 oaRawTextBean.setText(pageContext.getMessage("XXHLS", "XXHLS_SIMULATE_PS_INST", tokens));


Import MessageToken class and create an array of it with elements containing the tags you used in the message. Take note of the application short name and the message name - parameters that will be used for the getMessage method.

Random Rant =w=

JDeveloper's intellisense is buggy - when there is an error in the code, the reflector cannot properly detect the methods in the class anymore .. wtf TwT and so as the refactor function .. rawr

Tuesday, November 16, 2010

Date Manipulation in Java

java.util.Date doesn't have explicit methods for adding days, months, years, etc. However you can indirectly accomplish these operations through the java.util.Calendar class:
       
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.YEAR, 3);
Date applicationDate =
calendar.getTime();

This example gets the current date (aka SYSDATE) then adds 3 years to it; then assigns it to applicationDate variable.

If you already have an existing Date object, just get a Calendar instance then call:

setTime(Date date)

function =A=

Sunday, November 14, 2010

DBMS_OUTPUT Function Using SQL*PLUS

you must first enable message output through this panel:



then issue a command like:


SQL> EXEC DBMS_OUTPUT.PUT_LINE('Pogi Ako')
Pogi Ako

PL/SQL procedure successfully completed.

Utility PLSQL Function for Retrieving MEANING from FND_LOOKUP_VALUES

 Java function from the utility class

    public static String getFndLookupValue(Date effectiveDate,
                                            String lookupType,
                                            String lookupCode,
                                            OADBTransaction oaDBTransaction) {

        CallableStatement callableStatement = null;
        String s = "BEGIN ? := xxhls_util_pkg.get_fnd_meaning_fn(?,?,?); END;";

        try {

            callableStatement = oaDBTransaction.createCallableStatement(s, -1);
            callableStatement.registerOutParameter(1, OracleTypes.VARCHAR);
            callableStatement.setDate(2, effectiveDate);
            callableStatement.setString(3, lookupType);
            callableStatement.setString(4, lookupCode);
            callableStatement.execute();
           
            return callableStatement.getString(1);
          
        } catch (Exception sqlexception) {

            throw new OAException(sqlexception.getMessage());

        } finally {

            try {
                if (callableStatement != null)
                    callableStatement.close();               
            } catch (SQLException sqlexception1) {
                throw new OAException(sqlexception1.getMessage());
            }

        }

    }


Java function inside the Application Module (pretty short =w=;; )

    public String getFndLookupValue(String lookupType, String lookupCode) {
       
        Date date = new Date(new java.util.Date().getTime());
       
        return XxhlsServerUtil.getFndLookupValue(date, lookupType, lookupCode, this.getOADBTransaction());
       
    }


PLSQL code

FUNCTION get_fnd_meaning_fn (i_effective_date IN DATE,
                             i_lookup_type IN FND_LOOKUP_VALUES.LOOKUP_TYPE%TYPE,
                             i_lookup_code IN FND_LOOKUP_VALUES.LOOKUP_CODE%TYPE)
                            
    RETURN FND_LOOKUP_VALUES.MEANING%TYPE

    IS
   
        l_meaning FND_LOOKUP_VALUES.MEANING%TYPE;
   
    BEGIN
   
        SELECT  MEANING
        INTO    l_meaning
        FROM    FND_LOOKUP_VALUES
        WHERE   LOOKUP_TYPE = i_lookup_type
                AND LOOKUP_CODE = i_lookup_code
                AND i_effective_date BETWEEN START_DATE_ACTIVE AND END_DATE_ACTIVE;
               
        RETURN  l_meaning;
               
        EXCEPTION
       
            WHEN NO_DATA_FOUND THEN
           
            SELECT  MEANING
            INTO    l_meaning
            FROM    FND_LOOKUP_VALUES
            WHERE   LOOKUP_TYPE = i_lookup_type
                    AND LOOKUP_CODE = i_lookup_code
                    AND END_DATE_ACTIVE IS NULL;
           
            RETURN  l_meaning;
   
    END get_fnd_meaning_fn;

Thursday, November 11, 2010

Returning VARCHAR/String from a PLSQL call in Application Module

Well, not all the time you want a CURSOR

    public String getNextReferenceNumber(String loanTypeCode) {

        CallableStatement callableStatement = null;
        String s = "BEGIN ? := xxhls_housing_loan_pkg.get_next_reference_number_fn(?); END;";

        try {

            callableStatement = getOADBTransaction().createCallableStatement(s, -1);
            callableStatement.registerOutParameter(1, OracleTypes.VARCHAR);
            callableStatement.setString(2, loanTypeCode);
            callableStatement.execute();
           
            return ((OracleCallableStatement)callableStatement).getString(1);
          
        } catch (Exception sqlexception) {

            throw new OAException(sqlexception.getMessage());

        } finally {

            try {
                if (callableStatement != null)
                    callableStatement.close();               
            } catch (SQLException sqlexception1) {
                throw new OAException(sqlexception1.getMessage());
            }

        }

    }

Wednesday, November 10, 2010

Implementing LOV (list of values) in OAF

Draft:

1. =w= (wait, I'll do this later)

Retrieving the Active Address of an Employee using PERSON_ID

note : the critical thing to know is PER_ADDRESSES table; since the employee's address is not explicitly defined in PER_ALL_PEOPLE_F

  FUNCTION get_address_fn (i_application_date IN DATE,
                           i_person_id IN XXHLS_TYPES_PKG.t_person_id)
    RETURN VARCHAR2
   
    IS
   
      l_address_line1 VARCHAR2(240) DEFAULT '';
      l_address_line2 VARCHAR2(240) DEFAULT '';
      l_address_line3 VARCHAR2(240) DEFAULT '';   
   
    BEGIN
   
      SELECT  ADDRESS_LINE1, ADDRESS_LINE2, ADDRESS_LINE3
      INTO    l_address_line1, l_address_line2, l_address_line3
      FROM    PER_ADDRESSES
      WHERE   PERSON_ID = 7890
              AND PRIMARY_FLAG = 'Y'
              AND i_application_date BETWEEN DATE_FROM AND DATE_TO;
   
      RETURN l_address_line1 || ' ' || l_address_line2 || ' ' || l_address_line3;
     
      EXCEPTION
        -- case for future dated record, open ended record
     
        WHEN NO_DATA_FOUND THEN
       
          SELECT  ADDRESS_LINE1, ADDRESS_LINE2, ADDRESS_LINE3
          INTO    l_address_line1, l_address_line2, l_address_line3
          FROM    PER_ADDRESSES
          WHERE   PERSON_ID = 7890
                  AND PRIMARY_FLAG = 'Y'
                  AND DATE_TO IS NULL;
           
          RETURN l_address_line1 || ' ' || l_address_line2 || ' ' || l_address_line3;
   
    END get_address_fn;

Tuesday, November 9, 2010

APPLSYS

FND tables under APPLSYS schema


Monday, November 8, 2010

Inserting a Row at the End of an OAF Table / Advanced Table

OAF inserts table rows on zero index by default. However there are times that you want to insert a row at the end of the table and you could accomplish that by:

OARow oaRow = (OARow) VOImpl.createRow();
VOImpl.setRangeSize(VOImpl.getRowCount() + 1);
VOImpl.insertRowAtRangeIndex(VOImpl.getRowCount(), oaRow);

not straightforward but it works :)

OAF Sub Tab Layout Control

setting the active tab

        OASubTabLayoutBean subTabLayout =
             (OASubTabLayoutBean) webBean.findChildRecursive("SubTabLayout");
        subTabLayout.setSelectedIndex(pageContext, 0);

getSelectedIndex method returns the index of the active tab

show or hide the tab by the boolean parameter (false = show it; true = hide it) 
       
        subTabLayout.hideSubTab(0, true);

Task Kill in CMD

issue the command 'tasklist'

C:\Documents and Settings\r21>tasklist

Image Name                   PID Session Name     Session#    Mem Usage
========================= ====== ================ ======== ============
System Idle Process            0 Console                 0         28 K
System                         4 Console                 0        252 K
smss.exe                     620 Console                 0        420 K
csrss.exe                    684 Console                 0      8,180 K
winlogon.exe                 708 Console                 0      1,696 K
services.exe                 752 Console                 0      6,376 K
lsass.exe                    764 Console                 0      1,988 K
svchost.exe                  960 Console                 0      6,860 K
svchost.exe                 1028 Console                 0      5,820 K
svchost.exe                 1068 Console                 0     51,324 K
svchost.exe                 1160 Console                 0      4,836 K
svchost.exe                 1196 Console                 0      8,536 K
spoolsv.exe                 1292 Console                 0      8,172 K
svchost.exe                 1360 Console                 0      5,732 K
FireSvc.exe                 1428 Console                 0      1,596 K
HIPSvc.exe                  1476 Console                 0      3,236 K
jqs.exe                     1492 Console                 0      1,428 K
nsd.exe                     1644 Console                 0      4,124 K
EngineServer.exe            1716 Console                 0        468 K

afterward issue 'taskkill' using this pattern: taskkill /f /pid 516

C:\Documents and Settings\r21>taskkill /f /pid 516
SUCCESS: The process with PID 516 has been terminated.

Sunday, November 7, 2010

Oracle Function Overloading

things to keep in mind

1. you can't overload by merely changing the return type
  - meaning you must change the number, name, order or data type of the parameters (but I'm a bit skeptic over changing the name - I haven't tested it yet)

Parsing DATE to VARCHAR

SELECT TO_CHAR(TO_DATE('01-JAN-2008', 'DD-MM-YYYY'), 'YY')
FROM dual;

in here I would just like to extract the last 2 digits of the year and retrieve it as VARCHAR

Calling PL/SQL from OAF Application Module

Note: probably the most critical part is getOADBTransaction().createCallableStatement(s, -1). take note of the CallableStatment object - this might have a generic implementation on Java or other frameworks.

primary method (inside AMImpl.java)

    public void searchRequiredDocuments (String loanTypeCode) {
       
        if (getXxhlsRequiredDocumentsVO1().getRowCount() == 0) {
           
            OAViewObject vo = getXxhlsRequiredDocumentsVO1();
            CallableStatement cs = null;
            ResultSet rs = null;
            String s = "BEGIN ? := xxhls_test_pkg.get_actv_loan_docs_applied_fn(?); END;";
            try {
                cs = getOADBTransaction().createCallableStatement(s, -1);
                cs.registerOutParameter(1, OracleTypes.CURSOR);
                cs.setString(2, loanTypeCode);
                cs.execute();
                rs = ((OracleCallableStatement)cs).getCursor(1);
                populateViewObject(rs, vo);
            } catch (Exception sqlexception) {
                throw new OAException(sqlexception.getMessage());
            } finally {
                try {
                    if (cs != null)
                        cs.close();
                    if (rs != null)
                        rs.close();
                } catch (SQLException sqlexception1) {
                    throw new OAException(sqlexception1.getMessage());
                }
               
            }
           
        }
       
    }


utility methods

    protected static void populateViewObject (ResultSet rs, OAViewObject vo) throws SQLException {
        Map rsvo = new java.util.HashMap();
        if (vo == null) {
            return;
        }
        rsvo = mapAttrNames(vo);
        int cnt = 0;
        while (rs.next()) {
            Row row = vo.createRow();
            vo.setRangeSize(cnt + 1);
            vo.insertRowAtRangeIndex(cnt, row);
            ResultSetMetaData rsmd = rs.getMetaData();
            int numOfCol = rsmd.getColumnCount();
            for (int i = 0; i < numOfCol; i++) {
                String colName = rsmd.getColumnName(i + 1);
                String attrName = (String)rsvo.get(colName);
                if (attrName != null)
                    setVoAttribute(vo, row, attrName, rs.getObject(colName));
            }
            cnt++;
        }
    }

    protected static Map mapAttrNames (OAViewObject vo) {
        Map attrNames = new java.util.HashMap();
        if (vo == null) {
            return null;
        }
        AttributeDef[] attrDefs = vo.getAttributeDefs();
        int attrCount = (attrDefs == null) ? 0 : attrDefs.length;

        if (attrCount == 0) {
            return null;
        }

        for (int i = 0; i < attrCount; i++) {
            byte attrKind = attrDefs[i].getAttributeKind();

            if (!(attrKind == AttributeDef.ATTR_ASSOCIATED_ROW || attrKind == AttributeDef.ATTR_ASSOCIATED_ROWITERATOR || attrKind == AttributeDef.ATTR_DYNAMIC)) {
                String colName = attrDefs[i].getColumnNameForQuery();
                String attrName = attrDefs[i].getName();
                attrNames.put(colName, attrName);
            }
        }
        return attrNames;
    }

    protected static void setVoAttribute (OAViewObject vo, Row row, String attrName, Object attrVal) {
        if (vo.lookupAttributeDef(attrName) != null) {
            if (attrVal != null) {
                row.setAttribute(attrName, attrVal);
            }
        }
    }

Another way I found on Andries blog . I think I like this because it's much simpler; but you need to manually populate the View Objects

1. calling from CO

// Invoke the method
HashMap returnValues = (HashMap) am.invokeMethod("executePlsql");

// Get the returned values from the method
String status = (String) returnValues.get("Status");
String message = (String) returnValues.get("Message");

if (!status.equals("SUCCESS")) {

  am.invokeMethod("rollback");

  // ERRORS from executePlsql
  MessageToken[] tokens =
    {new MessageToken("STATUS", status),
     new MessageToken("MESSAGE", message)};

  OAException errorMessage = new OAException("XX",
  "XX_PLSQL_ERR", tokens,
  OAException.ERROR, null);

  pageContext.putDialogMessage(errorMessage);

}

2. calling from AM

import com.sun.java.util.collections.HashMap;
import java.sql.CallableStatement;
import java.sql.SQLException;
import java.sql.Types;

public HashMap executePlsql(String objectId, String objectSubType) {

  CallableStatement st = null;
  HashMap returnValues = new HashMap(2);

  try {

    String stmt = "BEGIN xx_pkg.xx_procedure( "
      + "p_object_id => :1, "
      + "p_object_sub_type => :2, "
      + "p_status => :3, "
      + "p_message => :4); END;";

    OADBTransaction tr = getOADBTransaction();

    st = tr.createCallableStatement(stmt, 1);

    // Bind the input parameters
    st.setInt(1, Integer.parseInt(objectId));
    st.setString(2, objectSubType);

    // Register return variables
    st.registerOutParameter(3, Types.VARCHAR);
    st.registerOutParameter(4, Types.VARCHAR);

    st.execute();

    // Assign returned values to variables
    String status = st.getString(3);
    String message = st.getString(4);

    st.close();

    // Populate HashMap with return variables
    returnValues.put("Status", status);
    returnValues.put("Message", message);

    OAExceptionUtils.checkErrors(tr);

  }

  catch (SQLException sqle) {

    throw OAException.wrapperException(sqle);

  }

  return returnValues;

}

Oracle ALL_OBJECTS table

SELECT  *
FROM    ALL_OBJECTS

contains information on objects accessible to the USER (schema)

http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/statviews_2005.htm

SELECT  *
FROM    ALL_OBJECTS
WHERE   OBJECT_TYPE = 'TABLE'

retrieve tables accessible to the user

SELECT  UNIQUE(OBJECT_TYPE)
FROM    ALL_OBJECTS

CONSUMER GROUP
INDEX PARTITION
TABLE SUBPARTITION
SEQUENCE
SCHEDULE
TABLE PARTITION
JAVA DATA
QUEUE
PROCEDURE
OPERATOR
WINDOW
LOB PARTITION
PACKAGE BODY
PACKAGE
LIBRARY
PROGRAM
LOB
INDEX SUBPARTITION
CONTEXT
JAVA RESOURCE
XML SCHEMA
TYPE BODY
TRIGGER
JOB CLASS
DIRECTORY
MATERIALIZED VIEW
TABLE
INDEX
SYNONYM
VIEW
FUNCTION
WINDOW GROUP
JAVA CLASS
INDEXTYPE
JAVA SOURCE
CLUSTER
TYPE
EVALUATION CONTEXT
LOB SUBPARTITION

Thursday, November 4, 2010

Looping Through CURSOR

Note: Cursor is basically a representation of the result set generated from an SQL; this example shows how to loop through that result set and access its values

  PROCEDURE delete_loan_type_history_pr (i_loan_type_code IN XXHLS.XXHLS_LOAN_TYPE_LIST.LOAN_TYPE_CODE%TYPE)
 
    IS
   
    BEGIN
   
        FOR l_cursor IN (SELECT LOAN_TYPE_HISTORY_ID
                         FROM   XXHLS.XXHLS_LOAN_TYPE_HISTORY
                         WHERE  LOAN_TYPE_CODE = i_loan_type_code)
        LOOP
            -- delete documents
            delete_loan_docs_applied_pr(l_cursor.LOAN_TYPE_HISTORY_ID);
            -- delete history record
            DELETE FROM XXHLS.XXHLS_LOAN_TYPE_HISTORY
            WHERE LOAN_TYPE_HISTORY_ID = l_cursor.LOAN_TYPE_HISTORY_ID;
           
        END LOOP;

    END delete_loan_type_history_pr;

PLSQL Error Handling Sample

accomplished by defining an EXCEPTION block right before the END of the procedure. You could specifically handle every type of Oracle predefined exceptions (or your own custom exception) using the WHEN <exception type> THEN clause. <exception type> = OTHERS serves as a catch basin for all excpetions.

TODO: review the list of Oracle predefined exceptions

FUNCTION get_actv_loan_typ_hist_id_fn(i_loan_type_code IN XXHLS.XXHLS_LOAN_TYPE_LIST.LOAN_TYPE_CODE%TYPE)
 
    RETURN XXHLS.XXHLS_LOAN_TYPE_HISTORY.LOAN_TYPE_HISTORY_ID%TYPE
   
    IS
   
        l_loan_type_history_id XXHLS.XXHLS_LOAN_TYPE_HISTORY.LOAN_TYPE_HISTORY_ID%TYPE DEFAULT NULL;
        
    BEGIN
       
      SELECT LOAN_TYPE_HISTORY_ID
      INTO l_loan_type_history_id
      FROM XXHLS.XXHLS_LOAN_TYPE_HISTORY
      WHERE LOAN_TYPE_CODE = i_loan_type_code
        AND SYSDATE BETWEEN
        EFFECTIVE_START_DATE AND EFFECTIVE_END_DATE;
       
      RETURN l_loan_type_history_id;
       
      EXCEPTION
        -- case for future dated record, open ended record
     
        WHEN NO_DATA_FOUND THEN
       
          SELECT LOAN_TYPE_HISTORY_ID
          INTO l_loan_type_history_id
          FROM XXHLS.XXHLS_LOAN_TYPE_HISTORY
          WHERE LOAN_TYPE_CODE = i_loan_type_code
            AND EFFECTIVE_END_DATE IS NULL;
           
          RETURN l_loan_type_history_id;
        
    END get_actv_loan_typ_hist_id_fn;

it is also possible to handle errors within an exception block like:

...
      EXCEPTION
        -- case for future dated record, open ended record


        WHEN NO_DATA_FOUND THEN

          BEGIN
     
            SELECT LOAN_TYPE_HISTORY_ID
            INTO l_loan_type_history_id
            FROM XXHLS.XXHLS_LOAN_TYPE_HISTORY
            WHERE LOAN_TYPE_CODE = i_loan_type_code
              AND EFFECTIVE_END_DATE IS NULL;
           
            RETURN l_loan_type_history_id;


          EXCEPTION


            WHEN OTHERS THEN


              DBMS.OUTPUT(SQLERRM); 
...
    

Take note of the SQLERRM object @A@ this contains the error message from the exception caught.