Wednesday, September 18, 2013

ViewObject: getFilteredRows

there is a function :getFilteredRows(RowQualifier rowQualifier) in the api of the ViewObjectImpl class.
you can create a RowQualifier simply by using:
new RowQualifier("attribute = '"+val+"'");

The allowed conditions can be only simple operators like =, <>, > and <. It does not take other functions like NVL, IS NULL, IS NOT NULL etc. This is not specified in any documentation.

Example:
HR schema, table:Employees.
in the EmployeesViewImpl add the following:
    public Row[] getEmployeesWithJob(String job){
        RowQualifier qualifier=new RowQualifier("JobId ='"+job+"'");
        return getFilteredRows(qualifier);

    }

then call the above method from your client code:
appModule.getEmployeesView1().getEmployeesWithJob("AD_VP");

this will return a Row array with the rows that matches the condition.

but after some experimenting I found that this code may introduce a sql injection threat, for example:
appModule.getEmployeesView1().getEmployeesWithJob("AD_VP' OR ''='");

this will return all rows in the view object.

so if the input of the function is supplied by the user ,this will be a serious security risk.

tested on JDeveloper 11.1.1.5

Edited on:19/9/2013:
concerning the underlined paragraph above,
I jumped to conclusions when I tried it,   I am sorry about that.
here is my explanation after I did some more digging:
using the tracing tools of the oracle database; I think it's safe to conclude the following:
1)the filtering is done in memory, the resulting query is not modified to include the condition.
2)as result of 1, I don't think it's correct to call this threat an SQL injection threat. However, this does not mean the issue of injection is not there.
3)as a result of 1, all rows of the table will be fetched into memory. This may result in performance issues, specially for table with a huge number of rows.

Tuesday, September 10, 2013

Entities Association - not a composition

master detail relations in relational databases can be described either as a composite or not a composite relationships.

a Master - detail composite means that the detail cannot exist on it own without a master.
a Master - detail non-composite means that the detail can exist in the database without a master.

in ADF this can be configured in the Assocaiton between two entities ,relationship tab under the behavior sub-header, by checking the composition association checkbox.

   1)this will have some effects on the behavior of the framework, some of these are: the order of posting changes to the database, the master will be posted first.
   2) if a detail is changed then the master will be validated again.
   3)if the ids are assigned by triggers, the foreign key in the detail will be changed to the new id of the master assigned by the trigger.


but what will happen if the relationship is not a composition?
this might causes some issues, specially since the framework posts the new records to the database in the order of their creation.
so consider the following scenario: you create a detail record , create a master record, assign the detail to be a child record of the master record then commit.
here is a code sample that does the above scenario:
        System.out.println(Test.class+".main>>starting");
        ApplicationModuleImpl module=(ApplicationModuleImpl)Configuration.createRootApplicationModule("model.businessObjects.applicationMod.AppModule","AppModuleLocal");
        System.out.println(Test.class+".main>>after getting application module");

        ViewObject deptVO= module.findViewObject("DepartmentsView1");
        ViewObject empVO= module.findViewObject("EmployeesView3");

        EmployeesViewRowImpl empRow=(EmployeesViewRowImpl)empVO.createRow();
        DepartmentsViewRowImpl deptRow=(DepartmentsViewRowImpl)deptVO.createRow();

        empRow.setLastName("zamer");
        empRow.setEmail("ahmad.alzamer@gmail.com");
        empRow.setHireDate(new Date());
        empRow.setJobId("AD_VP");
        empRow.setDepartmentId(deptRow.getDepartmentId().getSequenceNumber());
        
        deptRow.setDepartmentName("testing");

        module.getTransaction().commit();
        System.out.println(Test.class+".main>>emp:"+empRow.getEmployeeId());
        System.out.println(Test.class+".main>>dept:"+deptRow.getDepartmentId());

the above code is built on the HR schema and the association between the two entities is not a composite one. For the record, I overrode the doDml method in both entities to print to the output console the name of the class
if we run the above code we will get the following:
class model.testing.Test.main>>after getting application module
class model.businessObjects.entity.EmployeesImpl.doDML>>
Exception in thread "main" oracle.jbo.DMLConstraintException: JBO-26048: Constraint "EMP_DEPT_FK" is violated during post operation "Insert" using SQL statement "BEGIN INSERT INTO EMPLOYEES(EMPLOYEE_ID,LAST_NAME,EMAIL,HIRE_DATE,JOB_ID,DEPARTMENT_ID) VALUES (:1,:2,:3,:4,:5,:6) RETURNING EMPLOYEE_ID INTO :7; END;".
at oracle.jbo.server.OracleSQLBuilderImpl.doEntityDML(OracleSQLBuilderImpl.java:568)
at oracle.jbo.server.EntityImpl.doDMLWithLOBs(EntityImpl.java:8535)
at oracle.jbo.server.EntityImpl.doDML(EntityImpl.java:8467)
at model.businessObjects.entity.EmployeesImpl.doDML(EmployeesImpl.java:25)
at oracle.jbo.server.EntityImpl.postChanges(EntityImpl.java:6733)
at model.businessObjects.entity.EmployeesImpl.postChanges(EmployeesImpl.java:33)
at oracle.jbo.server.DBTransactionImpl.doPostTransactionListeners(DBTransactionImpl.java:3286)
at oracle.jbo.server.DBTransactionImpl.postChanges(DBTransactionImpl.java:3089)
at oracle.jbo.server.DBTransactionImpl.commitInternal(DBTransactionImpl.java:2093)
at oracle.jbo.server.DBTransactionImpl.commit(DBTransactionImpl.java:2374)
at model.testing.Test.main(Test.java:35)
Caused by: java.sql.SQLIntegrityConstraintViolationException: ORA-02291: integrity constraint (HR.EMP_DEPT_FK) violated - parent key not found
ORA-06512: at line 1

as you can see framework tried to post the employee record first; since it was created first.
in order to change this behavior, we should override postChanges to ensure that the master record is posted first.
here is the code to override the postChanges in the EmployeesImpl class:
    public void postChanges(TransactionEvent transactionEvent){
        if(getPostState()==STATUS_NEW||getPostState()==STATUS_MODIFIED){
            if(getBelongToDepartment().getPostState()==STATUS_NEW){
                getBelongToDepartment().postChanges(transactionEvent);
            }
        }
        super.postChanges(transactionEvent);
    }
the output after the run is:
class model.testing.Test.main>>after getting application module
class model.businessObjects.entity.DepartmentsImpl.doDML>>
class model.businessObjects.entity.EmployeesImpl.doDML>>
Exception in thread "main" oracle.jbo.DMLConstraintException: JBO-26048: Constraint "EMP_DEPT_FK" is violated during post operation "Insert" using SQL statement "BEGIN INSERT INTO EMPLOYEES(EMPLOYEE_ID,LAST_NAME,EMAIL,HIRE_DATE,JOB_ID,DEPARTMENT_ID) VALUES (:1,:2,:3,:4,:5,:6) RETURNING EMPLOYEE_ID INTO :7; END;".
at oracle.jbo.server.OracleSQLBuilderImpl.doEntityDML(OracleSQLBuilderImpl.java:568)
at oracle.jbo.server.EntityImpl.doDMLWithLOBs(EntityImpl.java:8535)
at oracle.jbo.server.EntityImpl.doDML(EntityImpl.java:8467)
at model.businessObjects.entity.EmployeesImpl.doDML(EmployeesImpl.java:25)
at oracle.jbo.server.EntityImpl.postChanges(EntityImpl.java:6733)
at model.businessObjects.entity.EmployeesImpl.postChanges(EmployeesImpl.java:35)
at oracle.jbo.server.DBTransactionImpl.doPostTransactionListeners(DBTransactionImpl.java:3286)
at oracle.jbo.server.DBTransactionImpl.postChanges(DBTransactionImpl.java:3089)
at oracle.jbo.server.DBTransactionImpl.commitInternal(DBTransactionImpl.java:2093)
at oracle.jbo.server.DBTransactionImpl.commit(DBTransactionImpl.java:2374)
at model.testing.Test.main(Test.java:35)
Caused by: java.sql.SQLIntegrityConstraintViolationException: ORA-02291: integrity constraint (HR.EMP_DEPT_FK) violated - parent key not found
ORA-06512: at line 1

we still get integrity constraint error, since the id of the master is changed -by the trigger- but the foreign key is not.
to fix this error we override two functions in the departmentsImpl class:
    RowSet empsInDept=null;
    @Override
    public void postChanges(TransactionEvent transactionEvent){
        if(getPostState()==STATUS_NEW){
            empsInDept=(RowSet)getEmployeesInDept();
        }
        super.postChanges(transactionEvent);
    }

    @Override
    protected void refreshFKInNewContainees(){
        if(empsInDept!=null){
            while(empsInDept.hasNext()){
                EmployeesImpl employee=(EmployeesImpl)empsInDept.next();
                employee.setDepartmentId(getDepartmentId().getSequenceNumber());
            }
            empsInDept.closeRowSet();
        }
        
        super.refreshFKInNewContainees();
    }
we override the functions:
   1)postChanges : to save a rowSet temporarily ,so that we have a way to access the child record after posting the current row to the database. since after posting the row will have a new id and we will not be able to fetch the child records.
   2)refreshFKInNewContainees: this function is called by the framework to refresh the values of the foreign keys in child records with the new value assigned by the triggers, but this function will only affect composite relations; so we override it to update the values in a non-composite relation.

the output after the run is:
class model.testing.Test.main>>after getting application module
class model.businessObjects.entity.DepartmentsImpl.doDML>>
class model.businessObjects.entity.EmployeesImpl.doDML>>
class model.testing.Test.main>>emp:4
class model.testing.Test.main>>dept:6

Thursday, September 5, 2013

ADF Select One Choice 2

it seems when you build a model driven LOV and disply it on an output page you can use the following EL expression:
#{!empty bindings.DepartmentId.selectedValue? bindings.DepartmentId.selectedValue.attributeValues[1]:'no choice selected'}

to display any of the attributes of the view rows used to create the LOV. 
please pay attention to the use of <<empty bindings.DepartmentId.selectedValue>> , this is used since if no choice is made(empty list item is the currently selected item) then  <<bindings.DepartmentId.selectedValue>> will return an empty string, so if you don't have this test , then you might get an exception complaining that the String class does not have a property named attributeValues.

the above expression gets the second attribute of the view row used to define the model driven LOV on the departmentId attribute.

I cannot think of any use for such functionality right now, but hopefully it can be of use to anyone of the reader of this blog. 

ADF Select Once Choice

building ADF Select One Choice using model driven list is quite easy once you try it. but sometimes you get business requirements that makes you lose some sleep over it.

I recently came across thread discussion on the oracle forum -sorry I don't have the link to it- where the author of the thread was requested to disable some of the items in the Select items.

Some will suggest that instead of showing the items in the list and have them disabled, you can easily remove them from the list, which can be easily done by using a view criteria.
But there are times where the developer is forced to do as the requirements ask. so we still have to show the items and somehow disable them.

here is my solution:
the first steps of the solution is the same as if you are trying to create a normal model driven list.
eventually, you will have something similar to the following in the source of the page:
             <af:selectOneChoice value="#{bindings.DepartmentId.inputValue}"
                                label="#{bindings.DepartmentId.label}"
                                required="#{bindings.DepartmentId.hints.mandatory}"
                                shortDesc="#{bindings.DepartmentId.hints.tooltip}"
                                id="soc2">
              <f:selectItems value="#{bindings.DepartmentId.items}" id="si1"/>
            </af:selectOneChoice>
edit the source to look something like this:
            <af:selectOneChoice value="#{bindings.DepartmentId.inputValue}"
                                label="#{bindings.DepartmentId.label}"
                                required="#{bindings.DepartmentId.hints.mandatory}"
                                shortDesc="#{bindings.DepartmentId.hints.tooltip}"
                                id="soc1" valuePassThru="true"
                                autoSubmit="true"
                                valueChangeListener="#{TestB.testListener}">
                         <!--f:selectItems value="#{bindings.DepartmentId.items}" id="si1"/-->
                       <af:forEach items="#{bindings.DepartmentId.items}" var="item">
                             <af:selectItem label="#{item.label}" id="selectItem1"    value="#{item.value}" disabled="#{item.value%2 eq 0}"/>
                       </af:forEach>
            </af:selectOneChoice>
with this code you will generate the select items yourself using the model driven list.
now all that remains is editing the disabled attribute of the selectItem tag to disable the select item as per your requirements.

ViewObject CreateRow() VS CreateAndInit()

both the methods (CreateRow() and CreateAndInitRow() ) mentioned above create and returns a new record.but the difference lies in the input parameter the createAndInitRow method takes.
the CreateAndInitRow takes a parameter of type NamedValuePair and uses those values to override the default values defined for the view object at design time.
to show the impact of this difference consider the following business case:
using HR schema. we have the following:
1)employees: have manager_id,department_id
2)departments :have department_id, manager_id

when adding a new employee to a department, the manager_id of the employee is set to the manager_id of the department.
this is achieved by defining a view accessor in the employee named Department. and setting the default value of the manager_id attribute of the employeesView to expression with the value:
    Department.ManagerId
and the default value of the departmentId to 10(otherwise the above expression will throw a nullpointerexception ).

to test the above I wrote:

        Number empId=new Number(546);
        vo= module.findViewObject("EmployeesView1");
        NameValuePairs nvp=new NameValuePairs();
        nvp.setAttribute("EmployeeId",empId);
        nvp.setAttribute("LastName","zamer");
        nvp.setAttribute("Email","zamer@gmmail.com");
        nvp.setAttribute("HireDate",new Date());
        nvp.setAttribute("JobId","AD_VP");
        nvp.setAttribute("DepartmentId",new Number(20));
        ViewRowImpl newRow=(ViewRowImpl)vo.createAndInitRow(nvp);
        vo.insertRow(newRow);
        newRow=(ViewRowImpl)vo.createRow();

        Number empI2=new Number(547);
        newRow.setAttribute(0,empI2);
        newRow.setAttribute(2,"zamer2");
        newRow.setAttribute(3,"zamer@gmmail.com2");
        newRow.setAttribute(5,new Date());
        newRow.setAttribute(6,"AD_VP");
        newRow.setAttribute("DepartmentId",new Number(20));
        vo.insertRow(newRow);
        module.getTransaction().commit();
        String [] attrNames= newRow.getAttributeNames();
        vo.executeQuery();
        while(vo.hasNext()){
            Row row=vo.next();
            if(empId.equals(row.getAttribute(0))||empI2.equals(row.getAttribute(0))){
            System.out.println(test.class+".main>>row:"+attrNames[0]+":"+row.getAttribute(0)+":"+attrNames[1]+":"+row.getAttribute(1)+":"+attrNames[2]+":"+row.getAttribute(2)+":"+attrNames[3]+":"+row.getAttribute(3)+":"+attrNames[4]+":"+row.getAttribute(4)+":"+attrNames[5]+":"+row.getAttribute(5)+":"+attrNames[6]+":"+row.getAttribute(6)+":"+attrNames[7]+":"+row.getAttribute(7)+":"+attrNames[8]+":"+row.getAttribute(8)+":"+attrNames[9]+":"+row.getAttribute(9)+":"+attrNames[10]+":"+row.getAttribute(10)+":"+attrNames[11]+":"+row.getAttribute(11)+":"+attrNames[12]+":"+row.getAttribute(12));
            System.out.println();
            }
        }


the following was printed to the output:
class testing.test.main>>row:DepartmentId:10:DepartmentName:Administration:ManagerId:200:LocationId:1700
class testing.test.main>>row:DepartmentId:20:DepartmentName:Marketing:ManagerId:201:LocationId:1800
class testing.test.main>>creating
class testing.test.main>>row:EmployeeId:546:FirstName:null:LastName:zamer:Email:zamer@gmmail.com:PhoneNumber:null:HireDate:1970-01-01:JobId:AD_VP:Salary:null:CommissionPct:null:ManagerId:201:DepartmentId:20:DeptName:null:EmpVideo:null

class testing.test.main>>row:EmployeeId:547:FirstName:null:LastName:zamer2:Email:zamer@gmmail.com2:PhoneNumber:null:HireDate:1970-01-01:JobId:AD_VP:Salary:null:CommissionPct:null:ManagerId:200:DepartmentId:20:DeptName:null:EmpVideo:null




you can see that that department 10 has manager 200  and  department 20 has manager 201  
when we used createAndInitRow (employee id:546) the employee had the manager id:201
while  when we used createRow (employee id:547) the employee had the manager id:200

this can be explained as follows:
since the expression is on a persistent attribute, the framework computes the default value, and this happens only once (at the creation of the record) using the available values at the time.
so since the department id at the creation of the record is the default value of 10 then the accessor will fetch that department.
as for CreateAndInitRow, the passed parameters will be used to override the default values, then any of the remaining attributes expressions(the attributes not included in the NamedValuePair ) will be evaluated ,so since the department id was changed to 20 , then the accessor will fetch department with the id 20.

so you can think of it this way,
createAndInitRow  set the default values of the new row at runtime using the named value pair passed to it.