Sunday, February 23, 2014

Performance Tip for Webcenter - IDs of Container components

Tip - ADF has a concept of container components by which its child components will have unique ids when rendered as HTML in front end.

Eg :  Lets say Region 1 and Region 2 form a part of a same page.
If Region 1 is with id r1 have an input text component with id i1
and Region 2 is with id r2 have an input text component with id i1
The ids of  input components in the rendered HTML would be r1:i1 and r2:i1

So though the input text component's ids are same, unique value is assigned to them automatically when the UI tree is formed during ADF lifecycle 
cool right??

Lets see a con about this, Since all of the child component's id will be appended by the parent component's id in the front and lets say you have have inputTextComponent in the below location

PageTemplate:Region:PanelCollection:Table:InputText

now the id of InputText in the front end would be (assuming ids given for each container as below)

pgtemplate:region1:pcollection1:table1:input1

This would add up to the HTML size loaded in front end.

Lets see the impact with a real example - I do have a simple page with a af:table and i have given the Table ID with a neat name "TableOne".





Now lets change the  Table ID from "TableOne" to "T"

So just by renaming one container component 0.1 KB is saved, In a large scale application where there are multiple containers and child components are in a single page this would be effective to a good extent.

Always try to name your ids to a much smaller value as possible.

For your reference PFB the list of container components  -

af:calendar

af:carousel

af:declarativeComponent

af:navigationPane

af:panelCollection

af:query

af:quickQuery

af:region

af:pageTemplate

af:subform

af:table

af:train

af:treeTable

af:tree
af:Iterator

Saturday, February 15, 2014

Cache in Iterator binding

This post is about the "CACHE" attribute in Iterator bindings. Though it looks very simple to turn on/off cache in iterator it has lot of implications with respect to performance, so just wan't to highlight it with an example :-)

Employee-Department view link of HR schema is used here.

Step 1 - I have generated java class for EmployeeVO and Departments VO with custom data source methods, placed sysouts in executeQueryForCollection.



Step 2 -  Drag and drop the view link as master detail table, run the application and observe the sysouts-



Here department VO's query is executed once on page load and employee VO query is executed as we select each department. This sounds fair right? Let turn of the Cache in iterator and try again.



Step 3- Re run the app again and now you could able to notice that DepartmentsVO gets executed on page load and as well on every PPR. Look at the number of EmployeeVO queries for each PPR !!



Proves to be an important factor :-)


How to run pubsub server in Integrated weblogic server

Scenario - For one of the usecase I had to do couple of POC on pubsub server, and as always its better to start of with Integrated WLS. I was following this wonderful blog from james bayer -
Real-time Updates on WebPages - Part 2 - Hello World Comet Application

Problem - Integrated server does not come packaged with pubsub.war :-(

Solution - 

Step 1 -  Locate pubsub.war in <MiddlewareHome>\wlserver_10.3\common\deployable-libraries\pubsub-1.0.war of weblogic server

Step 2 - Install it as a shared library in your integrated weblogic server.

Step 3 -  Now though we installed pubsub all it's dependent libraries are still not available in IntegratedWLS so we need to open the pubsub.war using winzip/anything available and see its dependent libraries in MANIFEST.MF,  then copy those libraries from Weblogic server location to Integrated WLS server location. Now that will take quite some time.

Let me give you another short cut- Copy all the folder contents from <MiddlewareHome>\modules\features and jars from  <MiddlewareHome>\modules\ to the same location in Integrated WLS.

This step copies all the required libraries to run pubsub.

So thats pretty much it :-) you can run pubsub locally :-)


Note - I used weblogic 10.3.6 

Saturday, August 17, 2013

Recieved Connections request count in webcenter like in FB/LinkedIn

Scenario - Need to display recieved connection request  count like in Facebook/LinkedIn in webcenter :-)

Implementation - There are two ways to implement -


1) We can use the ConnectionServiceFactory to get the ConnectionManager Instance and get all the information about the user's connection , his/her pending invitation , sent invitations etc.


Below i just explained few methods to get useful info about User's network.


    public void connectionInfo() {

//Gets the ConnectionServicefactory
        ConnectionsServiceFactory connService =
            ConnectionsServiceFactory.getInstance();
        ConnectionsManagerImpl connManager =
            
(ConnectionsManagerImpl)connService.getInstance().getConnectionsManager();
        InvitationsManagerImpl inviteManager =
            (InvitationsManagerImpl)connService.getInstance().getInvitationsManager();
        List<Connection> ConnList;
        List<Invitation> inviteListRecieved;
        List<Invitation> inviteListSent;
        try {
//Connection info of user "Weblogic", replace it with any userID

//Returns List of User's Connection Object , Each connection object returns all //info(user profile) about the connections
//Explore it :-)
            ConnList = connManager.getConnections("weblogic");
  
//Returns List of User's recieved invitation object 
          inviteListRecieved = inviteManager.getReceivedInvitations();

//Returns List of User's sent invitation object
            inviteListSent = inviteManager.getSentInvitations();

//TOTAL Recieved Connections request of the user
//This returns an int value of the recieved invitation
//Use this in the template so that the user's can get notified about their Friends request right away:-)
            System.out.println("User's recieved connections request count" +
                               inviteListRecieved.size());
           
        } catch (ConnectionsException e) {
            System.out.println("Just caught it");

        }
    }




2) We can use PeopleManagementDataControl , anyhow we shall discuss it in the later :-)



Hope this helps to have a good social networking look and feel to your portal :-)


Sunday, July 21, 2013

Protect Webcenter portal administration from authenticated users


Scenario - Protect Webcenter portal admin page from authenticated users 

Solution - Authenticated users have view access to Admin.jspx in webcenter portal. When any logged in user access http://<host>:<port>/<ContextPath>/admin it would take them to admin screen,  by default authenticated users do not have any permission to perform actions in administration screen but still its not a good practice for everyone to see admin pages. 

A very simple  and easy way to protect it is to disable permissions for Admin page in jazn-data.xml.

Step 1 - Go to Application Descriptors > jazn-data-xml > Resource Grants > Web Page permission > Select check box - Show web page from ADF libraries.










Step 2 - Admin page is shown in the list, choose it to see the permissions given . By default authenticated users have view access , SO delete default permissions and grant all permissions to Administrators.

Step 3 - Run the application, log in as Authenticated user and try to access /admin, You will see HTTP- 401 unauthorized page :-)

So Now /admin is protected :-)

Saturday, July 13, 2013

Export , Import and Migrate Webcenter spaces across environments.

Scenario - Need to migrate Webcenter spaces from One Environment to another.

Situation - Lately we had a situation to deploy changes done to 12 pages of Webcenter spaces into a production environment which had group spaces , tags, subscription etc., data of real users. So export and import of complete Webcenter spaces is out of equation as it would replace the entire spaces application including the data.


Now a work around needed to specifically deploy selected files.

A brief about spaces deployment- Webcenter spaces stores all the customization in Metadata store, So any change that we do in any of the system pages / New business role page that we create would be stored  in metadata files.

So to migrate Webcenter spaces from one environment to next means we have to move the metadata files to the other environment. There is an option provided in Oracle docs to export the Complete Webcenter spaces and import it back to the next environment.


exportWebCenterApplication(appName, fileName, [exportCustomizations, 
exportSecurity, exportData, server, applicationVersion])

importWebCenterApplication(appName, fileName, [server, applicationVersion])
But the con is export and import will replace the complete environment , in the sense any Group space,Subscriptions, lists, tags , notes , saved searches, etc will get replaced too. So for continuous deployment to Prod environments this is not the ideal way.
Solution - 
In spaces we can customize OOTB system pages / create new page etc. So now lets find out how to deploy those pages customization without complete export and import.

For sample i have customized  MyProfile page by adding the rich text editor , lets see how to migrate this to other environment.
















To understand it better, Try the following WLST command to export the metadata store of spaces.
exportMetadata(application='webcenter',server='WC_Spaces',toLocation='/u01/mydata');

specify the server and toLocation attribute according to your environment.

After executing this command, You would see the complete metadata store in /u01/mydata location.


To find out the customization we did to My profile page browse to this path - 


Original Page path -  /oracle/webcenter/page/scopedMD/s8bba98ff_4cbb_40b8_beee_296c916a23ed/businessRolePages/MyProfileMainView.jspx 


Metadata file which has the customization - 

 /oracle/webcenter/page/scopedMD/s8bba98ff_4cbb_40b8_beee_296c916a23ed/businessRolePages/mdssys/cust/site/webcenter/MyProfileMainView.jspx.xml 

Here when you open the file you would see the rich text editor we added to the MyProfile page.


<?xml version='1.0' encoding='UTF-8'?>

<mds:customization version="11.1.1.59.23" xmlns:mds="http://xmlns.oracle.com/mds">
<mds:insert parent="pcTopLeft" position="first">
<cust:showDetailFrame xmlns:cust="http://xmlns.oracle.com/adf/faces/customizable" id="e1014861134" text="#{componentExtensionBundle.TEXT}" background="#{changeModeBean.inEditMode ? 'medium' : 'light'}" contentStyle="background-color:transparent;" displayHeader="#{changeModeBean.inEditMode}" showMinimizeAction="none" selectChild="no" showResizer="never" stretchContent="false">
<af:richTextEditor xmlns:af="http://xmlns.oracle.com/adf/faces/rich" id="e957658699" simple="true" contentStyle="width:100%" clientComponent="true" toolboxLayout="font formatCommon color list mode" readOnly="true" value="&lt;span style=&quot;font-weight: bold; font-size: x-large; color: rgb(46, 139, 87);&quot;>Hi i customized this page right now, this one will get stored in MDS repository, lets find it out&lt;/span>" editMode="wysiwyg"/>
</cust:showDetailFrame>
</mds:insert>
</mds:customization>

PageDef of the page -


pageDefs/oracle/webcenter/page/scopedMD/s8bba98ff_4cbb_40b8_beee_296c916a23ed/businessRolePages/MyProfileMainViewPageDef.xml


Metadata of the pagedef -

pageDefs/oracle/webcenter/page/scopedMD/s8bba98ff_4cbb_40b8_beee_296c916a23ed/businessRolePages/mdssys/cust/site/webcenter/MyProfileMainViewPageDef.xml.xml


Now as we figured out where all our customization data resides , We can deploy only these files ,selectively.


Export the specific files from one (FROM) environment and deploy it to (TO) environment.

Here i export the MyProfile page and its page Def which by itself exports their corresponding metadata files.


exportMetadata(application='webcenter',server='WC_Spaces',toLocation='/u01/mydata',docs='/pageDefs/oracle/webcenter/page/scopedMD/s8bba98ff_4cbb_40b8_beee_296c916a23ed/businessRolePages/MyProfileMainViewPageDef.xml,/oracle/webcenter/page/scopedMD/s8bba98ff_4cbb_40b8_beee_296c916a23ed/businessRolePages/MyProfileMainView.jspx');


At the end of above command it would say 4 documents transferred successfully which includes their 2 metadata files.

Connect to the other environment using WLST connect and import it there.


importMetadata(application='webcenter',server='WC_Spaces',fromLocation='/u01/mydata',docs='/pageDefs/oracle/webcenter/page/scopedMD/s8bba98ff_4cbb_40b8_beee_296c916a23ed/businessRolePages/MyProfileMainViewPageDef.xml,/oracle/webcenter/page/scopedMD/s8bba98ff_4cbb_40b8_beee_296c916a23ed/businessRolePages/MyProfileMainView.jspx');

No need to restart , just login to the environment where you did import and browse to Myprofile page to see the rich text editor, Which means you have successfully migrated a page from one environment to next.


This way we can migrate any number of pages without doing a complete export and import, Just add the page paths and their pageDefs in the export command separated by commas.


There are also options to deploy a specific folders using filters in the docs attribute 

Eg - you can migrate entire pages of spaces using
docs='/pageDefs/oracle/webcenter/page/**,/oracle/webcenter/page/**' 
in the exportMedata/importMetadata wlst command.

Hope it helps :-)


Note - This method is useful in continuous deployments to Production environments where we cannot afford to loose any real data.

But to deploy the application that is developed using spaces to Production  / Any environment for the first time , its always advisable to use complete Export and Import.

Sunday, June 23, 2013

Pretty URL for pages in Webcenter Portal with multiple navigational model

Scenario - There are multiple navigation models in the portal, and the requirement is to refer any page in any Navigation Model using pretty url.

How to do - So lets suppose our sample navigation model looks like this -












Just drag and drop the other navigation models inside the default navigation model,
now it will create a navigation reference inside the default navigation model.















If you run the application, the entire default-navigational-model will be iterated, so the navigation reference that is added will be visible. 
















Suppose if there are 10 navigation reference, all of them will be visible which is not actually needed. If no reference is mentioned here , the pages in other navigation will not be accessible via pretty URL.


So to solve this , we can tweak the forEach loop which iterates the default navigational model , i will check for the node.title in render property of CommandLink so that the
navigation references wont render.



<af:forEach var="node" varStatus="vs"
                        items="#{navigationContext.defaultNavigationModel.listModel['startNode=/, includeStartNode=false']}">
              <af:subform id="pt_sfm1">
                <af:switcher id="pt_sw1"
                             facetName="#{(empty node.attributes['Target']) || (node.attributes['Target'] == '_popup') ? 'command' : 'golink'}">
                  <f:facet name="command">
                    <af:commandLink id="pt_cl1" text="#{node.title}"
                                    inlineStyle="font-size:small;#{node.selected ? 'font-weight:bold;' : ''}"
                                    action="pprnav"
                                    disabled="#{not node.navigable}"
                                    actionListener="#{navigationContext.processAction}"
                                    clientComponent="#{node.attributes['Target'] == '_popup' ? true : false}"
                                    rendered="#{node.title !='Navigation2'}">


The navigation reference will not be rendered as a part of iteration and all the pages will be accessible via pretty url.




Now we can access any page using pretty URL in the portal:-)
NavigationURL.zip





Important - I assume the default-navigation-model.xml is the default Portal's navigation model in the adf-config.xml . If the default Portal's navigation model is different , then use that Navigation Model which is configured as the base .