Friday, November 21, 2014

ADF DynamicTable is not picking up iterator changes from model layer after rollback is invoked

DynamicTable isRefreshRequired method caches the ViewDefName, then it compares the cached value with actual viewDefName, if they are the same it skips child creation.

This fix was needed to force the dynamic table to refresh in case of rollback to recreate its children
                    ((DynamicTable)child).getFacesBean().setProperty(PropertyKey.createPropertyKey("ViewDefNameForTable"), null);

Tuesday, October 14, 2014

Changing ViewCriteria Operators on fly - Used to filter TreeTable elements

In this scenario I developed a search form that would filter treeTable elements based on parent child view access link.

I have Parent viewCriteria used in the page as AF:Query along with TreeTable, There is also a child viewCriteria applied to the child view, the parent view has the same query in the exists clause to filter parent items.

Parent View:
Child View:


Then use this code to filter and change view Criteria operators by passing the change of the operators from the parent view criteria to the detail one:





Monday, October 6, 2014

Make DynamicForm survive passivation/Activation - Error javax.el.PropertyNotFoundException: Target Unreachable, 'DynamicForm_dynamic_VO_form1' returned null


This was very wired error when creating viewObjects and ViewDef Objects on the fly and using dynamicForm tag.

I just used the code mentioned in Thirumalaisamy blog and created a method used as a common method when creating Def Objects.

public ViewDefImpl createDynamicViewDef(String packagePath, String viewName) {
PackageDefImpl newPackage;
java.lang.reflect.Method setParentMth;
try {
java.lang.reflect.Method mth =
MetaObjectManager.class.getDeclaredMethod("createContainerDefObject", new Class[] { boolean.class });
setParentMth = oracle.jbo.server.DefObject.class.getDeclaredMethod("setParent", new Class[] { oracle.jbo.common.NamedObjectImpl.class });
mth.setAccessible(true);
setParentMth.setAccessible(true);
newPackage = (PackageDefImpl)mth.invoke(MetaObjectManager.getSingleton(), new Object[] { true });
} catch (Exception ex) {
         throw new JboException(ex);
        }
newPackage.setDefScope(PackageDefImpl.DEF_SCOPE_SESSION);
newPackage.setName(packagePath);
newPackage.setFullName(packagePath);
MetaObjectManager.insertSessionMetaObject(newPackage.getFullName(), newPackage);
ViewDefImpl reportParamsViewDef = new ViewDefImpl(packagePath + "." + viewName);
reportParamsViewDef.setFullName(packagePath + "." + viewName);
reportParamsViewDef.setComponentClass(ViewObjectImpl.class);
try {
    setParentMth.invoke(reportParamsViewDef, new Object[] { newPackage });
   } catch (Exception ex) {
   ex.printStackTrace();
   throw new JboException(ex);
}
  return reportParamsViewDef;
}


Many thanks to  who started the whole topic with oracle support
http://thirumalaisamyt.blogspot.com/2013/04/life-of-dynamic-vo-eo-across.html

Tuesday, September 30, 2014

Dynamic Form Iterator

Great resources to create dynamic form iterator
http://andrejusb.blogspot.com/2013/03/adf-generator-for-dynamic-adf-bc-and.html

Refresh issue need to pay attention to when creating dynamic form specially when rebuilding the form on the same page, execute this before invoking the method that will recreate you dynamic VO.

https://blogs.oracle.com/groundside/entry/refresh_problems_using_adaptive_bindings

Thursday, September 18, 2014

Oracle BI set User Identifier before running report

You can set a pre process property to execute a function at database level before running some set of queries. This is can be accomplished at report DataModel layer or before BI server connects to database in JNDI pre process property and post process property.


set_pre_process_username(:xdo_user_name,'AM START','BI')

set_post_process_username(:xdo_user_name,'AM FINISH','BI')

in the example above I am passing the logged in user in BI to the database to accomplish some kind of database row filtering.

A java usage (BI publicReportService):

You can impersonate the logged\-in user in your Java application by using the impersonate and runReportInSession methods.

String sid =reportService.impersonate(biUserName, biPass, loggedInUser);
repRes = reportService.runReportInSession(repReq, sid);

Monday, September 15, 2014

Clear TreeTable or Table selectedRowKeys from MDS

table.getSelectedRowKeys().clear();
RowKeySetAttributeChange rks =
    new RowKeySetAttributeChange(table.getClientId(FacesContext.getCurrentInstance()), "selectedRowKeys",new RowKeySetTreeImpl());
            RequestContext.getCurrentInstance().getChangeManager().addComponentChange(FacesContext.getCurrentInstance(), table, rks);

Thursday, August 7, 2014

ADF PASSIVATION/ACTIVATION - previously selected row gets populated in detail ViewObject, even it doesn't belong to Master ViewObject

JDeveloper 11.1.1.7

Updateable detail view object with viewCriteria applied at application module level, populates previously selected row from another parent, this only happens when running the application while application module pool set off to force Passivation/Activation, and the detailed viewObject have a viewCriteria applied to it.

This is reported to Oracle under (Bug 19203478 - ADF PASSIVATION/ACTIVATION - PREVIOUSLY SELECTED ROW GETS POPULATED).

A sample ADF application is attached here (EmplDeptPassivate.zip)

To reproduce this:
- Create new ADF application with default Model project and view Controller
- Database connection points to HR schema
- Create Business components from tables, only select Employee and Department tables, don't add the view Objects to application module.
- Add DepartmentView as master vo then EmployeesView as detail for departments.
- Create view criteria("EmployeesViewCriteria") in EmployeesView where ManagerId=102
- Return back to application module -> data model and edit EmployeeView1 and apply the view criteria.
- Set Application Module pool off, and disconnect upon release on
- Create a view criteria in DepartmentView to search for department name used in search page only.
- Create two ADF pages in bounded or unbound Taskflow
- First page drag DepartmentViewCriteria and add Query with Table, select single selection, filtering and sorting
- Second page drag EmployeeView1 as table, select single selection, filtering and sorting.
- Add navigation links between the two pages, convert department id outputText to link and set the action to the detail page(Employee page)
- Add back and commit buttons to the Employee page
- back should navigate back to search Departments page
- commit because we will change one record at first time
- run the Department Search page
- Search and select the first department with id=10
- Change the manager ID to 102 and save
- Back
- navigate to Department id=60 IT or any other department it shows the selected record from department id=10
- rerun the application many times as you want with changing the manager id to 102 this time because its one time change only, problem will still persists
- enable application module pool on again, problem disappears.

As a workaround to solve this problem, just change the ViewObject that have the ViewCriteria to expert mode VoilĂ .

Another cause of error (JBO-25014: Another user has changed the row with primary key oracle.jbo.Key[x])

Note this bug happens when using JDeveloper 11.1.1.7, I didn't test it on 11g release 2 versions or 12c, but I assume it might happens as well.

Apparently there is another cause of "JBO-25014 user changed primary key error" other than the ones discussed in Chris Muir post (The_case_of_the_phantom) or Jobinesh post (what-you-may-need-to-know-about-nested). This is related when Passivation/Activation occur while the user is changing a record on Master view object that uses an entity and this entity has a reference usage in the detailed view object.

You can test this by setting Application Module pool off. Assuming the user want to change the hire date of the employee in the master form for specific employee, at the same time the hire date is being referenced in the detail job description table showing readOnly hire date field next to the employee job description (Using Entity reference of-course).

When the user changes the field and the field has autosubmit set on, Passivation/Activation process will happen at the stage, then the user hit the save/commit button, ADF will do another Passivation/Activation process. It will activate the (VOs) including field values (New submitted along with Original) as first step of execution, thus while trying to activate the DoDML method will fail and throw a JBO-25014 error. This because the system will go and check the Entity state if it Synced with the database table to find any mismatch in field values.

It will compare the original field value against the database value, the original field value which is Passivated was overwritten from the detail Entity reference when the first Passivation/Activation happens, thus comparing two different value ( which contains the new data after the first Passivation/Activation process) with the original database value which is not changed or touched at all, and then throwing JBO-25014 exception.

This is a bug in ADF that only happens when Passivation/Activation happens in the system and there is a circular dependency between Entities used in the same page. The workaround is use a inline sub-query inside the detail ViewObject rather than using Entity reference specially when you know that you will build a screen that will have that field 1- editable, 2- referenced at the same time in the same screen, and 3- there is a possibility that Passivation/Activation will occur at some stage.

I will address anther bugs in Passivation/Activation mechanism in the following posts that I already submitted SRs for, at Oracle Support.

Friday, May 9, 2014

Initially Expand RichTreeTable when first displayed

Don't use initially expanded property or you will end up suffering with wired behavior using this code:

Tree Table Source:


                     selectionListener="#{bindings.ReportMenuTreeVO12.treeModel.makeCurrent}"
                     rowSelection="single" id="tt1" columnSelection="single"
                     displayRow="selected" autoHeightRows="10"
                     binding="#{viewScope.treeTableHelperBean.treeTable}"
                     disclosedRowKeys="#{viewScope.treeTableHelperBean.newDisclosedTreeTableKeys}"
                     rowDisclosureListener="#{viewScope.treeTableHelperBean.disclosureListener}">
..........................


TreeTableHelper class:


public class TreeTableHelper {

    private RowKeySetImpl newDisclosedTreeTableKeys = null;
    private RichTreeTable treeTable;

    public TreeTableHelper() {
        super();
    }

    public void disclosureListener(RowDisclosureEvent rowDisclosureEvent) {
        RichTreeTable treeTable = (RichTreeTable)rowDisclosureEvent.getSource();
        RowKeySet rowKeySet = rowDisclosureEvent.getAddedSet();
        if (rowKeySet != null && rowKeySet.size() > 0) {
            Iterator iterator = rowKeySet.iterator();
            while (iterator.hasNext()) {
                Object rowKey = iterator.next();
                treeTable.setRowKey(rowKey);
                JUCtrlHierNodeBinding rowData = (JUCtrlHierNodeBinding)treeTable.getRowData();
                if (rowData != null && rowData.getChildren() != null) {
                    for (Object child : rowData.getChildren()) {
                        JUCtrlHierNodeBinding childNode = (JUCtrlHierNodeBinding)child;
                        if (childNode.getChildren() == null || childNode.getChildren().size() == 0) {
                            treeTable.getDisclosedRowKeys().add(childNode.getKeyPath());
                        }
                    }
                }
            }
        }
    }

    public void setNewDisclosedTreeTableKeys(RowKeySetImpl newDisclosedTreeTableKeys) {
        this.newDisclosedTreeTableKeys = newDisclosedTreeTableKeys;
    }

    public RowKeySetImpl getNewDisclosedTreeTableKeys() {
        if (newDisclosedTreeTableKeys == null) {
            newDisclosedTreeTableKeys = new RowKeySetImpl();
            RichTreeTable treeTable = this.getTreeTable();
            if (treeTable != null) {
                CollectionModel model = (CollectionModel)treeTable.getValue();
                JUCtrlHierBinding treeBinding = (JUCtrlHierBinding)model.getWrappedData();
                JUCtrlHierNodeBinding nodeBinding = treeBinding.getRootNodeBinding();
                expandAllNodes(nodeBinding, newDisclosedTreeTableKeys, 0, 10);
                AdfFacesContext.getCurrentInstance().addPartialTarget(this.getTreeTable());
            }
        }

        return newDisclosedTreeTableKeys;
    }

    private void expandAllNodes(JUCtrlHierNodeBinding nodeBinding, RowKeySet disclosedKeys, int currentExpandLevel, int maxExpandLevel) {
        if (currentExpandLevel <= maxExpandLevel) {
            List childNodes = (List)nodeBinding.getChildren();
            ArrayList newKeys = new ArrayList();
            if (childNodes != null) {
                for (JUCtrlHierNodeBinding _node : childNodes) {
                    newKeys.add(_node.getKeyPath());
                    expandAllNodes(_node, disclosedKeys, currentExpandLevel + 1, maxExpandLevel);
                }
            }
            disclosedKeys.addAll(newKeys);
        }
    }

    public void setTreeTable(RichTreeTable treeTable) {
        this.treeTable = treeTable;
    }

    public RichTreeTable getTreeTable() {
        return treeTable;
    }
}

Monday, May 5, 2014

Simple and Easy way to display line breaks in outputText without converting it to InputText

Write a java bean that would replace each occurrence of  \n with <br/>

 public String getDescription() {
        String description = (String)JSFUtils.resolveExpression("#{row.Description}");
        if (description != null)
            description = description.replaceAll("\n", "<br/>");
        return description;
    }


In jsf page set escape outputText property to false:
<af:outputText value="#{myBean.description}" id="ot2" escape="false"/>

The result should look like this:

Friday, March 21, 2014

Oracle BI Publisher Desktop Installation Error

Resources

http://docs.oracle.com/cd/E17904_01/bi.1111/e13881/T421739T481157.htm
https://blogs.oracle.com/xmlpublisher/?page=2
http://www.solutionbeacon.com/BIPublisherQuickStartGudepaper.pdf
http://oraclemaniac.com/2014/03/07/limiting-lines-per-page-and-fixed-length-table-in-xmlbi-publisher-reports/

Oracle BI Publisher Desktop Installation Error

---------------------
-- Symptoms
---------------------

When attempting to install BI Publisher Desktop 11g (11.1.1.6.0) for 32-bit Office on Windows 7 64-bit. During the installation process, the following error message displays and the installation fails:

Please make sure JRE version 1.6 or later is installed

Java JRE 6 update 32 is installed on this PC; no other Java versions are installed.

---------------------
-- Cause
---------------------

Bug 14091878: ERROR WITH BIPUBLISHERDESKTOP32.EXE INSTALLATION

BIP Desktop installer might be corrupt

---------------------
-- Solution
---------------------

Complete the following steps:

    Download the offline installer for Java from this page:
    http://www.java.com/en/download/manual.jsp

    Make sure to download both Windows Offline (32-bit) and Windows Offline (64-bit).

    In Windows, go to the Control Panel --> Programs and Features.
    From the list of installed programs, uninstall all Java / JDK programs from your PC (both 32-bit and 64-bit)
    Reboot the PC
    Install the Java Windows Offline (32-bit)
    Install the Java Windows Offline (64-bit)
    Reboot the PC
    Install Oracle BI Publisher Desktop

Thursday, February 13, 2014

Showing first tab always when enabling MDS

I came across this scenario earlier, MDS customization is enabled for project, the project runs under webcenter portal.

User runs a page having three tabs, PanelTab along with showDetailItems used, when user select second tab and navigate away, then returns back to the previous page the last selected tab is displayed.

Using Persist property for the ShowDetailItem doesn't solve the problem, since panelTab component in Webcenter will always remember the last selected tab.

One of the WRONG scenario I tried is using Javascript to force the panelTab to set the tab property disclosed to false when page loads, this worked but it have a jumping effect between the tabs and still its a workaround.

The RIGHT way to do it is by using ChangeManager as shown below:

      public void tabDisclosureListener(DisclosureEvent disclosureEvent) {    
        RichShowDetailItem tab = (RichShowDetailItem)disclosureEvent.getComponent();
        FacesContext fc = FacesContext.getCurrentInstance();
        ChangeManager cm = RequestContext.getCurrentInstance().getChangeManager();
        ComponentChange cc = new AttributeComponentChange("disclosed", Boolean.FALSE);
        cm.addComponentChange(fc, tab, cc);
        ........
    }

This will reset the disclosed property when ever any of the tabs where clicked.

Wednesday, February 12, 2014

Tracking Entity Changes (instead of using Triggers on Database side)

In this example I am tracking all changes on specific set of columns or tables to trigger any events before transaction commit changes.

first you need to get a list of all view objects and compare its entity reference with list of tables you have, either stored in database or as fixed list of tables, note that ADF isAttributeChange method uses Java column naming convention not the column name you have on database, so you must build a list of java attribute names based on database column names.

so you need to retrieve all entity usages from viewDef, then get actual table name from the entity definition, also I am building a list of column (database_name) attribute (ADF_name) map, which will be used to check AttributeChangeStatus.

 public Map getViewObjectsNeedsToBeTracked(ViewObject[] allViews, ViewObjectImpl) {
        Map viewObjectsMap = new HashMap();
        //RowSetIterator iterator = Source Data Iterator or Array of tables
        for (int i = 0; i < allViews.length; i++) {
            iterator.reset();
            boolean viewPushed = false;
            while (iterator.hasNext() && !viewPushed) {
                Row rowFields = iterator.next();
                String tableName = (String)rowFields.getAttribute(tableFieldName);
                ViewObjectImpl view = (ViewObjectImpl)allViews[i];
                Map sourceMap = getSourceTableFromView(view);
                if (sourceMap != null) {
                    Object keys[] = sourceMap.keySet().toArray();
                    String sourceTable = (String)keys[0];
                    if (StringUtils.equalsIgnoreCase(tableName, sourceTable)) {
                        AttributeDef defs[] = sourceMap.get(keys[0]);
                        viewObjectsMap.put(tableName, createPairList(allViews[i], defs));
                        viewPushed = true;
                    }
                }
            }
        }
        return viewObjectsMap;
    }

private Map getSourceTableFromView(ViewObjectImpl view) {
        String sourceTable = null;
        Map map = null;
        ViewDefImpl viewDef = (ViewDefImpl)view.getDef();
        EntityReference references[] = viewDef.getEntityUsages();
        if (references != null && references.length > 0) {
            try {
                map = new HashMap();
                EntityDefImpl entityDef = references[0].getEntityDef();
                sourceTable = entityDef.getSource();
                sourceTable = StringUtils.substring(sourceTable, sourceTable.indexOf(".") + 1, sourceTable.length());
                map.put(sourceTable, entityDef.getAttributeDefs());
            } catch (Exception exp) {
                sourceTable = StringUtils.substring(sourceTable, 0, sourceTable.length());
            }
        }
        return map;
    }

Then get list of Attribute definition for source EntityDef, make sure to get persistent attributes only, these are the columns will be posted to database when transaction is committed, other attributes such as transient or constraints should be skipped.

                AttributeDef def = entityAttributeDefs[i];
                if (def.getAttributeKind() == AttributeDef.ATTR_PERSISTENT) {
                    String defColumnName = def.getColumnName();
                    String defName = def.getName();
                   

Check attribute changes methods, passing all captured View Rows along with list of parameters need to tracked:

 private static boolean rowAttributeStatusCheck(ViewRowImpl row, Object[] parameters) {
        boolean result = false;
        if (row != null && parameters != null) {
            for (Object param : parameters) {
                result = result || row.isAttributeChanged(param.toString());
            }
        }
        return result;
    }

Great resource for layouts

Great resource for ADF layouts, informative and direct:
http://www.slideshare.net/AMIS_Services/lbors-goodbyenightmarekscope



Sunday, January 5, 2014

Running ADF in High availability

Some of the things you should consider when developing ADF application running in HA environment is changes to pageFlowScope or ViewScope during a request. Making ADF aware of the changes you made to a ViewScope or pageFlowScope params is essential to replicate the changes across cluster.


To accomplish this:
1- Set the adf-scope-ha-support parameter inside adf-config.xml config file to true, this will make sure that changes will automatically replicated within a cluster.
 < adf-controller-config xmlns="http://xmlns.oracle.com/adf/controller/config">
 < adf-scope-ha-support>true</adf-scope-ha-support> </adf-controller-config>

2-  marking the scope is Dirty by adding additional code after scope changes:
    ControllerContext ctx = ControllerContext.getInstance();
    ctx.markScopeDirty(AdfFacesContext.getCurrentInstance().getViewScope());

note if you are making a change by reference without putting (replacing) param value in the Map you must call markScopeDirty.

Example:

Map<String, Object> viewScope = AdfFacesContext.getCurrentInstance().getViewScope();
MyObject obj = (MyObject)viewScope.get("myObjectName");
Obj.setFoo("newValue");

Putting value again in the map will replicate the change across cluster without calling markScopeDirty method.
viewScope.put("myObjectName");

http://docs.oracle.com/cd/E12839_01/core.1111/e10106/adf.htm