Montag, 14. März 2011

Decompiling the Oracle UI Shell Template

The oracle dynamic tabs shell template is one of the best pattern to design your application in a modular way. Additionally the template looks very smooth, so it's a real eye catcher. But not every corporate identity have this blue touch. There might be many people who want to design their own implementation of the template.
This is what we are going to build today. Before we can start, we have to download the template's sources, so we can easily apply our own template.

Unzip the contained fusion web application named SamplePatterns to your workspace and open it with the jdeveloper. 


Before we can start, we have to remove the write protection from the files. Otherwise we wouldn't be able to create our own page definition file. Linux users can just chmod.

~/jdeveloper/mywork/DynamicTabSehll $ sudo chmod 755 -R ./


After we renamed the application and project, we can take a look at the original UI Shell Template. This is located at /oracle/ui/pattern/dynamicShell/dynamicTabSehll.jspx. If you only want to do small changes, it should be easy to do them directly within the template. 
Another solution, is to create a complete new template for your own CI. So we create a new JSF Page Template with the wizard and call it juggernautShell.jspx.




Before we can start to create our own design, we have to create some components and bind them via EL to the tabContext bean. Here is a list of the needed components:



componentbinding
af:panelStretchLayout#{viewScope.tabContext.contentArea}
af:navigationPane#{viewScope.tabContext.tabsNavigationPane}
af:panelGroupLayout#{viewScope.tabContext.innerToolbarArea}
af:panelStretchLayout#{viewScope.tabContext.toolbarArea}
af:popup#{viewScope.tabContext.tooManyTabsPopup}
af:popup#{viewScope.tabContext.tabDirtyPopup}

First we start to create a place for our dynamic tabs. Place a af:decorativeBox at the center of your template and put a af:panelStretchLayout inside the center facet and set its binding attribute this EL value #{viewScope.tabContext.contentArea}.




Even if it looks like a af:panelTabbed, the real ui shell template uses a af:panelStretchLayout with a navigation pane in the top facet and regions in the center facet. To achieve something that looks like a tab panel we put a af:navigationPane the top facet of our just created af:panelStretchLayout and a af:decorativeBox with a welcome facet in the center. Set the navigation panes binding to #{viewScope.tabContext.tabsNavigationPane}. Now it should look like this. 



To Display the proper Tab for our currently active region, we have to do some modifications on our just created af:navigationPane. First surround it with a af:panelBorderLayout und set its rendered attribute to #{viewScope.tabContext.tabsRendered}. Then insert a af:commandNavigationItem inside the node stamp facet. Inside of this Item we need a f:attribute. Take a look at the following code snippet and edit the components attributes.


<af:panelBorderLayout id="pt_psl6"
                      styleClass="AFStretchWidth"
                      rendered="#{viewScope.tabContext.tabsRendered}"
                      inlineStyle="margin-left:5px;">
  <af:navigationPane id="pt_np1"
                     binding="#{viewScope.tabContext.tabsNavigationPane}"
                     rendered="#{viewScope.tabContext.selectedTabIndex != -1}"
                     value="#{viewScope.tabContext.tabMenuModel}"
                     var="tab"
                     inlineStyle="filter: alpha(opacity=100);-moz-opacity: 1.0;opacity: 1.0;">
    <f:facet name="nodeStamp">
      <af:commandNavigationItem id="tabIndex"
                                rendered="#{tab.active}"
                                actionListener="#{viewScope.tabContext.tabActivatedEvent}"
                                inlineStyle="#{tab.dirty ? 'font-style: italic' : ''}"
                                partialSubmit="true"
                                text="#{tab.title}"
                                immediate="true">
        <f:attribute name="tabIndex"
                     value="#{tab.index}"/>
      </af:commandNavigationItem>
    </f:facet>
  </af:navigationPane>
  <f:facet name="end">
    <af:commandImageLink icon="/oracle/ui/pattern/dynamicShell/images/close.png"
                         hoverIcon="/oracle/ui/pattern/dynamicShell/images/closeHover.png"
                         actionListener="#{viewScope.tabContext.tabRemovedEvent}"
                         rendered="#{viewScope.tabContext.selectedTabIndex != -1}"
                         immediate="true"
                         partialSubmit="true"
                         id="pt_cil1"/>
  </f:facet>
</af:panelBorderLayout>


To create the tabbing mechanism, we have to create regions within the center facet. This regions will be rendered dependent on the currently selected tab index. The index will be managed by oracles tab context bean, so we only need to read its value.


To hide the af:decorativeBox containing our welcome facet, we have to set its rendered attribute to #{viewScope.tabContext.selectedTabIndex == -1}.


Surround the af:decorativeBox with a af:group and copy the following XML code inside this group.

<af:region value="#{viewScope.tabContext.tabs[0].binding.regionModel}"
           id="pt_region0"
           rendered="#{viewScope.tabContext.selectedTabIndex == 0}"/>
<af:region value="#{viewScope.tabContext.tabs[1].binding.regionModel}"
           id="pt_region1"
           rendered="#{viewScope.tabContext.selectedTabIndex == 1}"/>
<af:region value="#{viewScope.tabContext.tabs[2].binding.regionModel}"
           id="pt_region2"
           rendered="#{viewScope.tabContext.selectedTabIndex == 2}"/>
<af:region value="#{viewScope.tabContext.tabs[3].binding.regionModel}"
           id="pt_region3"
           rendered="#{viewScope.tabContext.selectedTabIndex == 3}"/>
<af:region value="#{viewScope.tabContext.tabs[4].binding.regionModel}"
           id="pt_region4"
           rendered="#{viewScope.tabContext.selectedTabIndex == 4}"/>
<af:region value="#{viewScope.tabContext.tabs[5].binding.regionModel}"
           id="pt_region5"
           rendered="#{viewScope.tabContext.selectedTabIndex == 5}"/>
<af:region value="#{viewScope.tabContext.tabs[6].binding.regionModel}"
           id="pt_region6"
           rendered="#{viewScope.tabContext.selectedTabIndex == 6}"/>
<af:region value="#{viewScope.tabContext.tabs[7].binding.regionModel}"
           id="pt_region7"
           rendered="#{viewScope.tabContext.selectedTabIndex == 7}"/>
<af:region value="#{viewScope.tabContext.tabs[8].binding.regionModel}"
           id="pt_region8"
           rendered="#{viewScope.tabContext.selectedTabIndex == 8}"/>
<af:region value="#{viewScope.tabContext.tabs[9].binding.regionModel}"
           id="pt_region9"
           rendered="#{viewScope.tabContext.selectedTabIndex == 9}"/>
<af:region value="#{viewScope.tabContext.tabs[10].binding.regionModel}"
           id="pt_region10"
           rendered="#{viewScope.tabContext.selectedTabIndex == 10}"/>
<af:region value="#{viewScope.tabContext.tabs[11].binding.regionModel}"
           id="pt_region11"
           rendered="#{viewScope.tabContext.selectedTabIndex == 11}"/>
<af:region value="#{viewScope.tabContext.tabs[12].binding.regionModel}"
           id="pt_region12"
           rendered="#{viewScope.tabContext.selectedTabIndex == 12}"/>
<af:region value="#{viewScope.tabContext.tabs[13].binding.regionModel}"
           id="pt_region13"
           rendered="#{viewScope.tabContext.selectedTabIndex == 13}"/>
<af:region value="#{viewScope.tabContext.tabs[14].binding.regionModel}"
           id="pt_region14"
           rendered="#{viewScope.tabContext.selectedTabIndex == 14}"/>

Now you can see where the limitation of 15 open tabs comes from. Now it should look like this:




Because of the rendered attribute, we always see only the region of the currently activated tab index. Now everything is set for loading our dynamic regions to the specified place. What's left, is to define those regions in our binding container. Go to your templates page definition file (If it's not there, let jdeveloper create it). You can create every task flow binding by hand or copy the following code to the xml file.


<executables>
    <variableIterator id="variables"/>
    <taskFlow id="r0" taskFlowId="${viewScope.tabContext.tabs[0].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[0].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r1" taskFlowId="${viewScope.tabContext.tabs[1].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[1].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r2" taskFlowId="${viewScope.tabContext.tabs[2].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[2].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r3" taskFlowId="${viewScope.tabContext.tabs[3].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[3].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r4" taskFlowId="${viewScope.tabContext.tabs[4].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[4].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r5" taskFlowId="${viewScope.tabContext.tabs[5].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[5].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r6" taskFlowId="${viewScope.tabContext.tabs[6].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[6].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r7" taskFlowId="${viewScope.tabContext.tabs[7].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[7].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r8" taskFlowId="${viewScope.tabContext.tabs[8].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[8].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r9" taskFlowId="${viewScope.tabContext.tabs[9].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[9].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r10" taskFlowId="${viewScope.tabContext.tabs[10].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[10].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r11" taskFlowId="${viewScope.tabContext.tabs[11].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[11].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r12" taskFlowId="${viewScope.tabContext.tabs[12].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[12].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r13" taskFlowId="${viewScope.tabContext.tabs[13].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[13].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
    <taskFlow id="r14" taskFlowId="${viewScope.tabContext.tabs[14].taskflowId}"
              parametersMap="${viewScope.tabContext.tabs[14].parameters}"
              activation="deferred"
              xmlns="http://xmlns.oracle.com/adf/controller/binding">
      <parameters>
        <parameter id="tabContext" value="${bindings.tabContext}"
                   xmlns="http://xmlns.oracle.com/adfm/uimodel"/>
      </parameters>
    </taskFlow>
  </executables>


Now, everything that's left, is to create the remaining components with their binding to the tab context bean. Otherwise the initialization of the bean will fail. Where you put those components and if you use them is you choice. You can even put their rendered attribute to false and it'll still work.


It's a good advise to check the used template attributes and facets in the original UI Shell Template and adapt to its way of working. 


How to dynamically start your task flows is pretty detailed described in an article from oracle and can be found here


Official Oracle UI Shell Template Site

Keine Kommentare :

Kommentar veröffentlichen