Wednesday, November 30, 2011

JSON-P an example

Say, you have an HTML page in 1 domain and a servlet running in another domain.
For cross domain communication from your HTML and Servlet you can take advantage of the JSONP.

HTML File in Server 1



<html>
  <head>
    <script type="text/javascript">
      function callTheJsonp() {
          // the url of the script where we send the asynchronous call
          //var url = "http://rws65594fwks.us.oracle.com:7001/GoogleAppInsideFireWall/osmservlet?callback=parseRequest";
          var currentPageURL = document.location.href;
          alert(currentPageURL);
          var url = "http://127.0.0.1:7101/GoogleAppInsideFireWall/osmservlet?callback=parseRequest&calledPageUrl="+currentPageURL;//For My JDev testing
          // create a new script element
          var script = document.createElement('script');
          // set the src attribute to that url
          script.setAttribute('src', url);
          // insert the script in out page
          document.getElementsByTagName('head')[0].appendChild(script);
      }

      // this function should parse responses.. you can do anything you need..
      // you can make it general so it would parse all the responses the page receives based on a response field
      function parseRequest(response) {
          try // try to output this to the javascript console
          {
              alert('in callback--Response from OSM ');
              //console.log(response);
              alert('product id ' + response.itemId + ': quantity = ' + response.quantity + ' & price = ' + response.price);
          }
          catch (an_exception)// alert for the users that don't have a javascript console
          {
              alert('product id ' + response.itemId + ': quantity = ' + response.quantity + ' & price = ' + response.price);
          }
      }
    </script>
  </head>
  <body>
    <form>
      <p>
        <b>AMulya Mishra Test-&gt;</b>
         is a simulation of Buzzient UI hosted in 
        <b>Google Apps</b>.Clicking this button will invoke Ravi's WLS ADF App
                          which is inside Oracle Firewall.
      </p>
      <p>Access this page without VPN or without Proxy.. Before clicking this
         button, set proxy or connect to VPN and click to access the ADF App
         running in Ravi's WLS.</p>
      <p>
        1)-See the java script code written in this HTML using view source.<br>
        2)-Clicking 'Create Service Request' button calls a JavaScript method called callTheJsonp().<br>
        3)-Here we add a dynamic script tag with attribute src pointing to a servlet in different WLS.<br>
        4)-The servlet has a method to generate a JSON object and send it back as response to This page.<br>
        5)-Then it invokes function parseRequest(response) which takes this JSON object and prints in javascript console.<br>
      </p>
      <input type="button" name="Create Fusion Apps Service Request"
             value="Create Fusion Apps Service Request"
             onclick="callTheJsonp();"/>
          </form>
  </body>
</html>



Servlet code in Server 2


package view.oracle.apps.atf.osm.hadoopTest;

import com.google.gson.Gson;

import java.io.IOException;
import java.io.PrintWriter;

import java.util.Map;

import java.util.Random;

import javax.servlet.*;
import javax.servlet.http.*;

import oracle.apps.OSMPojo;

public class OSMServlet extends HttpServlet {
    private static final String CONTENT_TYPE = "text/html; charset=UTF-8";

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException,
                                                           IOException {
        System.out.println("--->Here in GET");
        response.setContentType(CONTENT_TYPE);
        PrintWriter out = response.getWriter();
        Map params = request.getParameterMap(); 
        if(params != null && params.containsKey("callback")){
            String jsonData = this.getJSONData();
            String output = request.getParameter("callback") + "(" + jsonData + ");";
            out.println(output);
        }
        out.close();
    }

    private String getJSONData() {
        Gson gson = new Gson();
        OSMPojo pojo = new OSMPojo();
        pojo.setItemId(new Long(new Random().nextLong()).toString());
        pojo.setPrice(new Long(new Random().nextLong()).toString());
        pojo.setQuantity(new Long(new Random().nextLong()).toString());
        String json = gson.toJson(pojo);
        return json;
    }    
}

Thursday, November 24, 2011

Creating your first J2EE Google App and Host in Google Apps Engine.

This is for people who just want to know how to build an app and upload to Google Apps Engine so that you dont have to worry about Server and Hosting mechanism.

If you have an J2EE WebApp and you want to host it in Google Apps Engine, here are the steps.
Assumption, you have a Google/GMAIL account.

Step 1: Go to https://appengine.google.com/ and create a new application.
If you have never used App Engine before, you might be asked to verify your mobile phone number before you can create a new app.

Step 2: Give your application a name – it should be unique and may only include lowercase alphabets and digits.
For this example, our app identifier is “amulsmmtest”. (http://amulsmmtest.appspot.com)
Application Title-> SMM Test For ATK -AMulya

Step3: http://code.google.com/appengine/downloads.html
Download appengine-java-sdk-1.6.0.zip
Unzip to a dir called D:\Downloads\appengine-java-sdk-1.6.0\appengine-java-sdk-1.6.0\

Step4:Create an J2EE WebApp having a servlet/jsp/HTML.
Step5:In the WebApp,under WEB-INF dir(where web.xml resides),create a new XML file called appengine-web.xml
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>amulsmmtest</application>
<version>1</version>
</appengine-web-app>


Step6:From JDeveloper, right click and deploy the War file to a directory, say D:\ATK\SMM\GoogleAppOutSideFireWall\deploy\webapp.war

Step7: Unzip this war to D:\ATK\SMM\GoogleAppOutSideFireWall\deploy\webapp

Step8:You are done now to upload the App to Google Apps Engine, to your own domain, you have created in Step2.

Step9: Go to your Command Prompt and make sure, your %JAVA_HOME%/bin is in classpath
Step10:
Execute the following Java command to upload the WebApp

D:\Downloads\appengine-java-sdk-1.6.0\appengine-java-sdk-1.6.0\bin\appcfg.cmd -p www-proxy.uk.oracle.com:80 update D:\ATK\SMM\GoogleAppOutSideFireWall\deploy\webapp


Thats it, now access the HTML page in your webapp using this URL
http://amulsmmtest.appspot.com/GoogleAppMainPage.html

Where amulsmmtest.appspot.com is your domain and GoogleAppMainPage.html is the HTML page inside your webapp's WEB-INF dir.

Thursday, November 17, 2011

Viewing SOAPMessage in console

Add -Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true

Saturday, November 12, 2011

Invoking Secured Webservice client proxy code

Few setups needed to be done in WLS domain, to enable GPA.
Securing a Webservice producer
Save the below file in name gpa.py under $MW_HOME/oracle_common/common/bin

connect('weblogic','weblogic1','t3://localhost:7101')
beginRepositorySession()
createPolicySet('default-domain-ws-DefaultDomain','ws-service','Domain("*")')
attachPolicySetPolicy('oracle/wss_saml_or_username_token_service_policy')
validatePolicySet()
commitRepositorySession()
beginRepositorySession()
createPolicySet('default-domain-ws-client-DefaultDomain','ws-client','Domain("*")')
attachPolicySetPolicy('oracle/wss10_saml_token_client_policy')
validatePolicySet()
commitRepositorySession()
beginRepositorySession()
createPolicySet('default-domain-ws-connection-DefaultDomain','ws-connection','Domain("*")')
attachPolicySetPolicy('oracle/wss10_saml_token_client_policy')
validatePolicySet()
commitRepositorySession()
beginRepositorySession()
createPolicySet('default-domain-ws-callback-DefaultDomain','ws-callback','Domain("*")')
attachPolicySetPolicy('oracle/wss10_saml_token_client_policy')
validatePolicySet()
commitRepositorySession()
beginRepositorySession()
createPolicySet('soa-domain-sca-reference-fusion_domain','sca-reference','Domain("*")')
attachPolicySetPolicy('oracle/wss10_saml_token_client_policy')
validatePolicySet()
commitRepositorySession()
beginRepositorySession()
createPolicySet('soa-domain-sca-service-fusion_domain','sca-service','Domain("*")')
attachPolicySetPolicy('oracle/wss_saml_or_username_token_service_policy')
validatePolicySet()
commitRepositorySession()


Execute this gpa.py

$MW_HOME/oracle_common/common/bin/wlst.sh gpa.py


$MW_HOME/oracle_common/common/bin/wlst.sh
connect('weblogic','weblogic1','t3://localhost:7101')
createCred(map="oracle.wsm.security", key="keystore-csf-key", user="owsm", password="welcome1", desc="Keystore key")
createCred(map="oracle.wsm.security", key="enc-csf-key", user="orakey", password="welcome1", desc="Encryption key")
createCred(map="oracle.wsm.security", key="sign-csf-key", user="orakey", password="welcome1", desc="Signing key")
createCred(map="oracle.wsm.security", key="basic.credentials", user="weblogic", password="weblogic1", desc="User")


Assumming the Webservice producer App name is "ProducerApp"

$MW_HOME/oracle_common/common/bin/wlst.sh
connect('weblogic','weblogic1','t3://localhost:7101')
grantPermission(codeBaseURL="file:${common.components.home}/modules/oracle.wsm.agent.common_11.1.1/wsm-agent-core.jar",permClass="oracle.wsm.security.WSIdentityPermission",permTarget="resource=ProducerApp",permActions="assert")


Configuration from Client Side
create the Webservice client.(OSMGateWayAMService_Service)
2)-Add the policy "policy:oracle/wss10_saml_token_client_policy" to this client.
3)-Then , they have to create the ProxyClient,i.e oSMGateWayProxy

ProducerService_Service producer_Service =
new ProducerService_Service(new URL(wsdlUrl),
new QName(producer
producer));
SecurityPolicyFeature[] securityFeature = new SecurityPolicyFeature[] { new SecurityPolicyFeature("policy:oracle/wss10_saml_token_client_policy")};
ProducerService producerServiceProxy = producer_Service.getProducerServiceHttpPort(securityFeature);

5)-If you WONT attach this Client Policy, then while invocation, you get "SAML Indentity Assertion Error".

Thursday, September 29, 2011

WebLogic WorkManager for Multi-threading

WebLogic's WorkManager provides a self-tuned ThreadPool to enable Multi-Threading.

Define a WorkManager either in WLS console or in web.xml as below.

<resource-ref>
<res-ref-name>wm/MyWorkManager</res-ref-name>
<res-type>commonj.work.WorkManager</res-type>
<res-auth>Container</res-auth>
<res-sharing-scope>Shareable</res-sharing-scope>
</resource-ref>


In weblogic-application.xml, you can configure the ThreadPool Size

  <work-manager>
<name>wm/MyWorkManager</name>
<max-threads-constraint>
<name>a</name>
<count>5</count>
</max-threads-constraint>
</work-manager>
<work-manager>


Java Code

        try {
InitialContext ic = new InitialContext();
WorkManager workManager = (WorkManager)ic.lookup("java:comp/env/wm/MyWorkManager");
List workItemList=new ArrayList();

for(int i=0;i<10;i++){
WorkItem workItem1 = startWorkItem(my,i,"OSMM");
workItemList.add(workItem1);
}



//run the work items in parallel; don't wait
//workManager.waitForAll(workItemList, WorkManager.IMMEDIATE);


    public WorkItem startWorkItem(WorkManager workManager, final int count, final String wmName) throws Exception{
WorkItem workItem10 = workManager.schedule(new Work() {
public void run() {
try {
System.out.println("Current Count ["+count+"] : wmName ["+wmName+"]ThreadName Is: "+Thread.currentThread().getName()+"##Priroty="+Thread.currentThread().getPriority());
} catch (Exception e) {
e.printStackTrace();
}
}

public void release() {
}

public boolean isDaemon() {
return false;
}
}); //End of Schedule
return workItem10;

}

PLSQL:Encryption Decryption DBMS_CRYPTO

set serveroutput on

DECLARE
LC$Source VARCHAR2(19) := 'Music is the best!';
LR$Source RAW(128) := utl_raw.cast_to_raw(LC$Source);
LR$Key RAW(128) := utl_raw.cast_to_raw('FrankZappa');
LR$Crypted RAW(2048);
LR$Decrypted RAW(2048);

BEGIN

dbms_output.put_line('Source string : ' || LC$Source);

LR$Crypted := dbms_crypto.encrypt(LR$Source,
dbms_crypto.des_cbc_pkcs5, LR$Key);

dbms_output.put_line('Encrypted raw : ' ||
RAWTOHEX(utl_raw.cast_to_raw(LR$Crypted)));

LR$Decrypted := dbms_crypto.decrypt(src => LR$Crypted,
typ => dbms_crypto.des_cbc_pkcs5, key => LR$Key);

dbms_output.put_line('Decrypted string : ' ||
utl_raw.cast_to_varchar2(LR$Decrypted));
END;
/

Tuesday, August 02, 2011

Raising Business Event from AMImpl

ADFbc EO gives a declarative way of raising Business Event.But in cases, when you need the Business Events to be raised from somewhere else than EO, how will you do.

Libraries needed

  • Add SOA Runtime Lib to the JPR.
  • Make sure, you have "oracle.soa.workflow.wc" lib deployed and targeted to DefaultServer in your WLS.
  • Add below Lib Reference to the weblogic-application.xml file
<library-ref>
<library-name>oracle.soa.workflow.wc</library-name>
</library-ref>




DataSource Configuration

Business Event internally uses Oracle AQ.It needs the "ENDSource" or "EDNDataSource" to be configured in WLS.

Diagnostic messages which comes from Business Event classes are as below(If you dont setup the Above Data Source)

INFO: Looking for BusinessEventConnectionFactory
INFO: Looking for EDN-DB JNDI configuration to create SAQRemoteBusinessEventConnectionFactory.
INFO: Unable to create SAQRemoteBusinessEventConnectionFactory: [jdbc/EDNSource or jdbc/EDNDataSource] undefined.
INFO: Looking for EDN-JMS JNDI configuration to create JMSRemoteBusinessEventConnectionFactory.
INFO: Unable to create JMSRemoteBusinessEventConnectionFactory: [java:comp/UserTransaction] undefined.
INFO: Unable to create JMSRemoteBusinessEventConnectionFactory: [jms/fabric/EDNConnectionFactory] undefined.
INFO: Failed to get ConnectionFactory instance.

Verifying the PayLoad gets Saved to the DB after you publish the event

Once you publish the event, the data goes into the AQ table called "AQ$EDN_EVENT_QUEUE_TABLE" which is inside schema "soa_infra/soa_infra".

  • From ADF App, raise a Business Event
  • connect to your DB as soa_infra/soa_infra
  • select * from AQ$EDN_EVENT_QUEUE_TABLE
  • You can see the row gets populated
  • AQ$EDN_EVENT_QUEUE_TABLE.USER_DATA EDN_EVENT_DATA()
    desc EDN_EVENT_DATA
    user type definition
    -----------------------------------
    type edn_event_data as object (
    event edn_business_event,
    publish_impl char,
    subject_info varchar2(256),
    target varchar2(1024));

Sample Java Code

import java.util.Iterator;
import java.util.List;

import javax.xml.namespace.QName;

import oracle.fabric.blocks.event.BusinessEventConnection;
import oracle.fabric.blocks.event.BusinessEventConnectionFactory;

import oracle.fabric.blocks.event.BusinessEventSubscriptionManager;

import oracle.fabric.common.BusinessEvent;

import oracle.integration.platform.blocks.event.BusinessEventBuilder;
import oracle.integration.platform.blocks.event.BusinessEventConnectionFactorySupport;

import oracle.integration.platform.blocks.event.EDNFacadeImpl;
import oracle.integration.platform.blocks.event.SubscriptionInfo;

import oracle.soa.management.facade.LocatorFactory;
import oracle.soa.management.internal.facade.edn.Event;
import oracle.soa.management.internal.facade.edn.Subscription;

import oracle.xml.parser.v2.XMLDocument;

import org.w3c.dom.Element;

    private static final String eventName = MyNotification;
private static final String eventNamespace = "http://schemas.oracle.com/events/edl/EventDefinition";
private static final String schemaNamespace = "http://xmlns.oracle.com/events/edl/EventDefinition";
public void raiseBusinessEvent() {
try {
// Get event connection, make sure the following entry exists in weblogic-application.xml
/*
*
*
oracle.soa.workflow.wc

*/
BusinessEventConnectionFactory cf =
BusinessEventConnectionFactorySupport.findRelevantBusinessEventConnectionFactory(true);

if (cf != null) {
BusinessEventConnection conn =
cf.createBusinessEventConnection();

// Build event
BusinessEventBuilder builder =
BusinessEventBuilder.newInstance();

// Specify the event name and namespace. In this prototype, they are constants, eventNamespace, eventName
builder.setEventName(new QName(eventNamespace, eventName));

// Specify the event payload. In this prototype, the getXMLPayload custom method constructs the payload

builder.setBody(getXMLPayload().getDocumentElement());
BusinessEvent event = builder.createEvent();

// Publish event
conn.publishEvent(event, 5);
conn.close();

// Event was sent sucessfully;
} else {
// For debug only
//cf is null
}
} catch (Exception exp) {
// For debug only
// Failed sending event: " + exp.getMessage();
exp.printStackTrace();
}
}

private XMLDocument getXMLPayload() {
Element masterElem, childElem1, childElem2, childElem3, childElem4, childElem5;
XMLDocument document = new XMLDocument();

String userName = "row.getUsername()";

masterElem =
document.createElementNS(schemaNamespace, "MyNotification");
document.appendChild(masterElem);

childElem1 = document.createElementNS(schemaNamespace, "userName");
childElem1.appendChild(document.createTextNode(userName));
masterElem.appendChild(childElem1);

childElem2 =
document.createElementNS(schemaNamespace, "distBudgetIssueVal");

childElem2.appendChild(document.createTextNode("getPublishRecallVal"));
masterElem.appendChild(childElem2);

childElem3 = document.createElementNS(schemaNamespace, "comment");

childElem3.appendChild(document.createTextNode("getNotificationComment()"));
masterElem.appendChild(childElem3);

childElem4 =
document.createElementNS(schemaNamespace, "moduleIdentifier");

childElem4.appendChild(document.createTextNode("BudgetNotification"));
masterElem.appendChild(childElem4);

return document;
}

Wednesday, July 27, 2011

Manipulating MDS Customizations In Java

In ADF,we have various Customization layers such as RolesCC,SiteCC,UserCC etc defined in adf-config.xml.This decides in which TIP layer the customization would go.

      <cust-config>
<match path="/">
<customization-class name="oracle.adf.share.config.SiteCC"/>
<customization-class name="oracle.adf.share.config.ADFRolesCC"/>
<customization-class name="oracle.adf.share.config.ADFUserCC"/>
</match>
</cust-config>


But there are scenarios, when we want a particular customization should be in base only, not specific to any TIP layer.

Here is how you can achieve the same.This example is to apply NO_CUSTOMIZATIONS at runtime.

Create a class that implements oracle.adf.share.mds.SessionOptionsFactory interface.
import java.util.List;

import oracle.adf.share.ADFContext;
import oracle.adf.share.mds.SessionOptionsFactory;

import oracle.mds.config.CustClassListMapping;
import oracle.mds.config.CustConfig;
import oracle.mds.config.MDSConfigurationException;
import oracle.mds.core.MDSInstance;
import oracle.mds.core.SessionOptions;
import oracle.mds.cust.CustClassList;
import oracle.mds.cust.CustomizationClass;
import oracle.mds.exception.InvalidNamespaceException;
import oracle.mds.naming.InvalidReferenceException;
import oracle.mds.naming.InvalidReferenceTypeException;
import oracle.mds.naming.Namespace;
import oracle.mds.naming.NamespaceRestriction;
import oracle.mds.naming.PackageName;
import oracle.mds.persistence.PManager;
import oracle.mds.sandbox.IncompatibleSandboxException;
import oracle.mds.sandbox.SandboxHelper;
import oracle.mds.sandbox.SandboxNotFoundException;
import oracle.mds.sandbox.SandboxNotSupportedException;
import oracle.mds.sandbox.SandboxUsage;
import oracle.mds.versioning.LabelNotFoundException;
import oracle.mds.versioning.MultipleLabelsException;
import oracle.mds.versioning.VersionContext;
import oracle.mds.versioning.VersioningNotSupportedException;

/**
* A factory that subtitute the <code>CustConfig</code> object with
* <code>CustConfig.NO_CUSTOMIZATIONS</code> in the default
* <code>SessionOptions</code> object.
*/
public class MyADFSessionOptionsFactory implements SessionOptionsFactory
{

/**
* Gets the instance of the factory for creating base documents.
*
* @return the instance of the factory for creating base documents
*/
public static ModelerSessionOptionsFactory getBaseInstance()
{
return _INSTANCE;
}

private static final ModelerSessionOptionsFactory _INSTANCE =
new ModelerSessionOptionsFactory(CustConfig.NO_CUSTOMIZATIONS, null);
}


Use this class in your AMImpl or somewhere the session starts

    ConfigUtils.setSessionOptionsFactory(_currentContext,
ModelerSessionOptionsFactory.getBaseInstance());

Tuesday, July 26, 2011

Creating a ViewDef Programmatically

Make sure you have an adf-config.xml entry as below, where the ViewDef XML file will be persisted in MDS.

          <mds:namespace metadata-store-usage="globalStore-by-adfconfigfilter"
path="/sessiondef"/>

<mds:metadata-store-usage default-cust-store="true"
deploy-target="true"
id="globalStore-by-adfconfigfilter">
<mds:metadata-store class-name="oracle.mds.persistence.stores.db.DBMetadataStore">
<mds:property value="mds-ApplicationMDSDB"
name="repository-name"/>
<mds:property value="FAGlobal" name="partition-name"/>
<mds:property value="jdbc/mds/mds-ApplicationMDSDBDS"
name="jndi-datasource"/>
</mds:metadata-store>
</mds:metadata-store-usage>



Java Code
    public String writeSessionDefViewDefintion(){
String PACKAGE_NAME = "oracle.apps.atk.ess";
String voName = "MyViewName";
String viewDefFullName = "sessiondef."+PACKAGE_NAME+"."+voName+"MyViewDef";

ViewDefImpl viewDef = new ViewDefImpl(ViewDefImpl.DEF_SCOPE_SESSION,
voName + "MyViewDef");
viewDef.setFullName(viewDef.getBasePackage() + "." + PACKAGE_NAME +
"." + viewDef.getName());*/

AttributeDefImpl attrDef = viewDef.addViewAttribute("id", null, java.sql.Date.class);

Calendar cal = Calendar.getInstance();

// set Date portion to January 1, 1970
cal.set(cal.YEAR, 2011);
cal.set(cal.MONTH, cal.JULY);
cal.set(cal.DATE, 21);

cal.set(cal.HOUR_OF_DAY, 0);
cal.set(cal.MINUTE, 0);
cal.set(cal.SECOND, 0);
cal.set(cal.MILLISECOND, 0);

java.sql.Date defaultDate = new java.sql.Date(cal.getTime().getTime());
attrDef.setDefaultValue(defaultDate);
attrDef.setProperty(AttributeDefImpl.FMT_FORMAT,"MM-dd-yyyy");
attrDef.setProperty(AttributeDefImpl.FMT_FORMATTER,"oracle.jbo.format.DefaultDateFormatter");


// viewDef.setFullSql(true);
viewDef.resolveDefObject();
viewDef.registerDefObject();
viewDef.writeXMLContents();
viewDef.saveXMLContents();
viewDef.setDirty(true);
String viewInstanceName ="MyViewName" + "MyViewDef";
ViewObject dynamicVO =
this.findViewObject(viewInstanceName);

if (dynamicVO != null) {
dynamicVO.remove();
}
dynamicVO = createViewObject(viewInstanceName, viewDefFullName);
String VOName = dynamicVO.getDefFullName();
System.out.println("###VOName="+VOName);
this.setEssParamVOName(VOName);
return VOName;
}

Monday, July 25, 2011

Deriving and Binding WSLD URL at runtime for ADF Application

There are scenario when developers tend to use an exposed WSDL URL and consume it in their ADF Application.
Say, developer is trying to generate Java client proxy classes and use them to build the Application by invoking the Webservice methods.

When you generate the proxies, the WSDL URL gets hardcoded in the Service.java class.
Something like this
        wsdlLocationURL =
SMMPostCrawlerService_Service.class.getResource("http://10.176.87.233:7101/app/CrawlerServicePort?WSDL");



When you deploy the application or the Webservice deployment changes from server to server, then its hard to change in the java class, then redeploy the Ear altogether.

A simple solution IMO is,
  • Define a WSDL URL Connection in connections.xml.("MyWSDLConnection")
  • In your Client Proxy,read this WSDL URL Connection from connections.xml programmatically and use Bindingprovider to bind the URL at runtime to your proxy.
Connections.xml entry
   <Reference name="MyWSDLConnection" className="oracle.adf.model.connection.url.HttpURLConnection" xmlns="">
<Factory className="oracle.adf.model.connection.url.URLConnectionFactory"/>
<RefAddresses>
<XmlRefAddr addrType="MyWSDLConnection">
<Contents>
<urlconnection name="MyWSDLConnection" url="http://myServer:7002/app/CrawlerServicePort?WSDL"/>
</Contents>
</XmlRefAddr>
</RefAddresses>
</Reference>



This eliminates the changes to the java class and avoids redeployment.

    public String readURLFromConnectionsXML() {
String wsdlURL = null;
try {
URLConnectionProxy wsConnection =
(URLConnectionProxy)ADFContext.getCurrent().getConnectionsContext().lookup("MyWSDLConnection");
wsdlURL= wsConnection.getURL().toExternalForm();
} catch (Exception e) {
e.printStackTrace();
}
return wsdlURL;
}



Use this WSDL URL to bind at runtime to your Webservice java client proxy code.
In your ServicePortClient.java class

  @WebServiceRef
private static CrawlerService_Service crawlerService_Service;

public static void main(String [] args)
{

crawlerService_Service = new CrawlerService_Service();
CrawlerService_Service crawlerService_Service = crawlerService_Service.getCrawlerServicePort();


BindingProvider bp = (BindingProvider)sMMPostCrawlerService;
String CrawlerServiceWSDL = readURLFromConnectionsXML();
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, CrawlerServiceWSDL);
}

Oracle AQ programmatic Solution(Example)

This article demonstrates a Sample Oracle AQJMS program to send & receive Object Messages between two Clients.

Setups Needed in DataBase side

Grant AQ Permission to the DB Schema User.(Say HR)
connect system/manager as sysdba;

grant aq_administrator_role to <schema>;
grant execute on dbms_aqadm to <schema>;
grant execute on dbms_aq to <schema>;
grant execute on dbms_aqin to <schema>;
grant execute on dbms_aqjms to <schema>;


Database Objects Needed to be created(Comments are self Explanatory)

We need to create an AQ Table,AQ Queue and Start the Queue(s)

set serveroutput on

declare
begin
dbms_aqadm.stop_queue(queue_name => 'SMM_AQ_FACEBOOK_Q');
dbms_aqadm.stop_queue(queue_name => 'SMM_AQ_TWITTER_Q');
dbms_aqadm.stop_queue(queue_name => 'SMM_AQ_RSS_Q');
dbms_aqadm.drop_queue(queue_name => 'SMM_AQ_FACEBOOK_Q');
dbms_aqadm.drop_queue(queue_name => 'SMM_AQ_TWITTER_Q');
dbms_aqadm.drop_queue(queue_name => 'SMM_AQ_RSS_Q');
dbms_aqadm.drop_queue_table(queue_table => 'SMM_AQ_QT');
exception
WHEN OTHERS THEN
dbms_output.put_line (SQLCODE||' Drop Queue Objects ' || SUBSTR(SQLERRM, 1, 256));
END;
/

set serveroutput on
DECLARE
BEGIN
dbms_output.put_line ('Creating Queue Table SMM_AQ_QT.');
dbms_aqadm.CREATE_queue_table( queue_table => 'SMM_AQ_QT', queue_payload_type => 'SYS.AQ$_JMS_OBJECT_MESSAGE', sort_list=> 'ENQ_TIME,PRIORITY', multiple_consumers => FALSE, message_grouping=> DBMS_AQADM.NONE, primary_instance=> '0', secondary_instance=> '0', COMMENT => 'Creating Queue Table SMM_AQ_RSS_QT');
dbms_output.put_line ('Created Queue Table SMM_AQ_QT.');


EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line (SQLCODE||' Create Queue Table ' || SUBSTR(SQLERRM, 1, 256));
END;
/



DECLARE
BEGIN
dbms_output.put_line ('Creating Queue SMM_AQ_RSS_Q...');
dbms_aqadm.CREATE_queue( queue_name => 'SMM_AQ_RSS_Q', queue_table => 'SMM_AQ_QT', queue_type=> DBMS_AQADM.NORMAL_QUEUE, max_retries=> '5', retry_delay=> '0', retention_time=> '0', COMMENT => 'Resource Registration Queue');
dbms_output.put_line ('Created Queue SMM_AQ_RSS_Q.');

dbms_output.put_line ('Creating Queue SMM_AQ_FACEBOOK_Q...');
dbms_aqadm.CREATE_queue( queue_name => 'SMM_AQ_FACEBOOK_Q', queue_table => 'SMM_AQ_QT', queue_type=> DBMS_AQADM.NORMAL_QUEUE, max_retries=> '5', retry_delay=> '0', retention_time=> '0', COMMENT => 'Resource Registration Queue');
dbms_output.put_line ('Created Queue SMM_AQ_FACEBOOK_Q.');

dbms_output.put_line ('Creating Queue SMM_AQ_TWITTER_Q...');
dbms_aqadm.CREATE_queue( queue_name => 'SMM_AQ_TWITTER_Q', queue_table => 'SMM_AQ_QT', queue_type=> DBMS_AQADM.NORMAL_QUEUE, max_retries=> '5', retry_delay=> '0', retention_time=> '0', COMMENT => 'Resource Registration Queue');
dbms_output.put_line ('Created Queue SMM_AQ_TWITTER_Q.');


EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE|| ' Create Queue ' || SUBSTR(SQLERRM, 1, 256));
END;
/


DECLARE
BEGIN
dbms_output.put_line('starting queue SMM_AQ_RSS_Q...');
dbms_aqadm.start_queue( queue_name => 'SMM_AQ_RSS_Q');
dbms_output.put_line ('Started Queue SMM_AQ_RSS_Q.');

dbms_output.put_line('starting queue SMM_AQ_FACEBOOK_Q...');
dbms_aqadm.start_queue( queue_name => 'SMM_AQ_FACEBOOK_Q');
dbms_output.put_line ('Started Queue SMM_AQ_FACEBOOK_Q.');

dbms_output.put_line('starting queue SMM_AQ_TWITTER_Q...');
dbms_aqadm.start_queue( queue_name => 'SMM_AQ_TWITTER_Q');
dbms_output.put_line ('Started Queue SMM_AQ_TWITTER_Q.');

EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line (SQLCODE || ' Start Queue ' || SUBSTR(SQLERRM, 1, 256));
END;
/

grant all on SYSTEM.SMM_AQ_QT to <schema>;
/

Serialized POJO Object to send and receive from Oracle AQ
import java.io.Serializable;

public class SmmPojo implements Serializable{
private String name;
private Long rollnumber;
public SmmPojo() {
super();
}

public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public void setRollnumber(Long rollnumber) {
this.rollnumber = rollnumber;
}

public Long getRollnumber() {
return rollnumber;
}
}


JMS Client programs with Send and Receive code


Below is a Managed bean code.You can create a very simple ADF WebApplication with a DB DataSource called "SmmApp" in the WLS.

In the JSPX page, create 2 buttons and associate them with the 2 ActionEvents shown below[sendMessage() and ReceiveMessage()]


import javax.faces.event.ActionEvent;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;

import javax.naming.Context;
import javax.naming.InitialContext;

import oracle.apps.atk.ess.view.SmmPojo;

import oracle.jms.AQjmsFactory;
import oracle.jms.AQjmsSession;
import oracle.jms.AQjmsTextMessage;
import oracle.jms.AQjmsObject;

public class DemoBean {
public DemoBean() {
}

public void sendMessage(ActionEvent actionEvent) {
// Add event code here...
QSendFunction();
}

public void QSendFunction() {
QueueConnection qc = null;
try {
Context jndiContext = new InitialContext();
javax.sql.DataSource smmAppDS
= (javax.sql.DataSource) jndiContext.lookup ("jdbc/SmmAppDS");

QueueConnectionFactory qcf =
AQjmsFactory.getQueueConnectionFactory(smmAppDS);
qc = qcf.createQueueConnection();

//Message delivery does not begin until you start the connection you created by calling the start method
qc.start();

//session is not transacted
QueueSession m_queueSess =
qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);


// Destination is Queue created in database
Queue m_queue =
((AQjmsSession)m_queueSess).getQueue("", "SMM_AQ_TWITTER_Q");

QueueSender m_sender = m_queueSess.createSender(m_queue);

SmmPojo smmMessagePojo = new SmmPojo();
smmMessagePojo.setName("AMulya Mishra");
smmMessagePojo.setRollnumber(931L);
ObjectMessage objectMessage = m_queueSess.createObjectMessage();
objectMessage.setObject(smmMessagePojo);

//Message mesg = m_queueSess.createTextMessage("Test Message");

m_sender.send(objectMessage);

System.out.println("Message Sent->");

} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
try {
qc.stop();
qc.close();
} catch (JMSException e1) {
}
}
}

public void ReceiveMessage(ActionEvent actionEvent) {
// Add event code here...
QRecvFunction();
}

public void QRecvFunction() {
QueueConnection qc = null;
try {

// QueueConnectionFactory is the preconfigured JMS Object set by administrator.
Context jndiContext = new InitialContext();
javax.sql.DataSource smmAppDS
= (javax.sql.DataSource) jndiContext.lookup ("jdbc/SmmAppDS");

QueueConnectionFactory qcf =
AQjmsFactory.getQueueConnectionFactory(smmAppDS);

// Does not created Destination, there is no look to JNDI that holds QF and Destination by JMS Client (this program)
// we are directly using JMS Client to make JMS Provider
// QueueConnection to JMS Provider ( database with JMS Services demon is the service provider )
// User can create one more connections to QF

qc = qcf.createQueueConnection();
// Start the Connection
//Message delivery does not begin until you start the connection you created by calling the start method
qc.start();

//A session is a single-threaded context for producing and consuming messages
//QueueSession m_queueSess = qc.createQueueSession(true, 0);

QueueSession m_queueSess =
qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue m_queue =
((AQjmsSession)m_queueSess).getQueue("", "SMM_AQ_TWITTER_Q");

//Once you have created a message consumer, it becomes active, and you can use it to receive messages
//a session and is used for receiving messages sent to a destination.
//A message consumer allows a JMS client to register interest in a destination with a JMS provider.
//The JMS provider manages the delivery of messages

QueueReceiver m_receiver = m_queueSess.createReceiver(m_queue);

// Synchronous messaging
//A receiver explicitly fetches the message from the destination by calling the receive method.
// The receive method can block until a message arrives or can time out if a message does not arrive within a specified time limit
//if you do not want your program to consume system resources unnecessarily, use a timed synchronous receive ex:- receive(1000) timeout 1000ms
ObjectMessage objectMessage = (ObjectMessage)m_receiver.receive(5000);
//Message mesg = m_receiver.receive(5000);
//System.out.println(((AQjmsTextMessage)mesg).getText());
if (objectMessage != null){
oracle.jms.AQjmsObjectMessage aqjmsObjectMessage = (oracle.jms.AQjmsObjectMessage)objectMessage;
SmmPojo smmMessagePojo = (SmmPojo)objectMessage.getObject();
System.out.println(smmMessagePojo.getName()+"--->"+smmMessagePojo.getRollnumber());
}
} catch (Exception e) {
System.out.println(e.getMessage());
} finally {
try {
qc.stop();
qc.close();
} catch (JMSException e1) {
}
}
}
}

ADFbc:Inserting and retreiving java.util.List object to anf from Database

CREATE TABLE java_objects
(
object_id NUMBER,
object_name VARCHAR(128),
object_value BLOB DEFAULT empty_blob(),
PRIMARY KEY (object_id)
);

CREATE SEQUENCE java_objects_S1 MINVALUE 1 INCREMENT BY 1 START WITH 1000 CACHE 1000
/



Create an EO,VO and AM on this table.

AMImpl code

    public void insertData(){
List<Object> modules = new ArrayList<Object>();
modules.add("This is a short string.");
modules.add(new Integer(1234));
modules.add(new java.util.Date());

ViewObjectImpl vo = getJavaObjectsVO1();
Row row = vo.createRow();
row.setAttribute("ObjectName", "AMulya");
try{
BlobDomain blob = new BlobDomain();
OutputStream os = blob.getBinaryOutputStream();
ObjectOutputStream oop = new ObjectOutputStream(os);
oop.writeObject(modules);
oop.flush();
oop.close();
os.close();
row.setAttribute("ObjectValue", blob);
}catch(Exception e){
e.printStackTrace();
}

vo.insertRow(row);
this.getDBTransaction().commit();
}

public void readData(){
ViewObjectImpl vo = getJavaObjectsVO1();
Row row = vo.first();
BlobDomain blob = (BlobDomain)row.getAttribute("ObjectValue");
try{
InputStream is = blob.getBinaryStream();
ObjectInputStream oip = new ObjectInputStream(is);
Object object = oip.readObject();
String className = object.getClass().getName();
System.out.println(className);
oip.close();
is.close();
// de-serialize list a java object from a given objectID
List listFromDatabase = (List) object;
System.out.println("[After De-Serialization] list=" + listFromDatabase);
}catch(Exception e){
e.printStackTrace();
}

}

Wednesday, June 22, 2011

Handling Single/Multiple selected rows in af:table or af:tree

Accessing the table component and its attributes inside a region from the main page without setting the context,
and When we do a setRowKey() on a RichTable then the following exception is thrown.
java.lang.ClassCastException: java.util.Collections$SingletonList cannot be
cast to java.lang.Integer

Solution



public void dialogListener(DialogEvent dialogEvent) {
final RichTable table = this.getRichTable();

FacesContext facesContext = FacesContext.getCurrentInstance();
VisitContext visitContext = RequestContext.getCurrentInstance().createVisitContext(facesContext,null, EnumSet.of(VisitHint.SKIP_TRANSIENT,VisitHint.SKIP_UNRENDERED), null);
//Annonymous call
UIXComponent.visitTree(visitContext,facesContext.getViewRoot(),new VisitCallback(){
public VisitResult visit(VisitContext context, UIComponent target)
{
if (table != target)
{
return VisitResult.ACCEPT;
}
else if(table == target)
{
//Here goes the Actual Logic
Iterator selection = table.getSelectedRowKeys().iterator();
while (selection.hasNext()) {
Object key = selection.next();
//store the original key
Object origKey = table.getRowKey();
try {
table.setRowKey(key);
Object o = table.getRowData();
JUCtrlHierNodeBinding rowData = (JUCtrlHierNodeBinding)o;
Row row = rowData.getRow();
System.out.println(row.getAttribute(0));
}
catch(Exception ex){
ex.printStackTrace();
}
finally {
//restore original key
table.setRowKey(origKey);
}
}
}
return VisitResult.COMPLETE;
}
});
}

Thursday, June 09, 2011

af:paneltab programmatic disclosure

You may face MDS/Session persistance issue when you are using setDisclosed(boolean) for af:showDetailItem in af:panelTab.

You must do below after you call setDisclosed(true)

            ChangeManager cm = RequestContext.getCurrentInstance().getChangeManager();
ComponentChange truCC = new AttributeComponentChange("disclosed", true);
cm.addComponentChange(FacesContext.getCurrentInstance(), nextDynamicTab, truCC);


You must do below after you call setDisclosed(false)

            ChangeManager cm = RequestContext.getCurrentInstance().getChangeManager();
ComponentChange falseCC = new AttributeComponentChange("disclosed", false);
cm.addComponentChange(FacesContext.getCurrentInstance(), nextDynamicTab, falseCC);

Monday, May 23, 2011

XE DB:ORA-28000: The Account is locked.

sql>connect system/XXXXXX
connected.
sql>connect hr/hr
ORA-28000: The Account is locked.

Solution
sql>alter user hr identified by hr account unlock;

Tuesday, April 05, 2011

JDev:Unable to create an instance of the Java Virtual Machine

I installed JDeveloper11g Studio Edition with no JDK bundle but when i tried to start JDeveloper, it gave me error

Unable to start Java Virtual Machine located at ....

In order to fix this type of error, go to installation_directoy\Middleware\JDeveloper\jdev\bin folder
and edit file jdev.conf.
Locate line "AddVMOption -XX:MaxPermSize=256M".
Now add another line just below this line:

AddVMOption -Xmx256M

Coding Standards

For any ADF/Webcenter/SOA/J2EE Java code, Model and UI layer, here are few points to make code better from writing from performance and standard point of view,that comes from our coding practice and experience.This was the list we were using while developing the Fusion Apps in Oracle.

Here I have tried to consolidate a set of checkpoints we should check before source controlling any changes.This ensures making code better, robust, standards compatible and performant.

Keep this article opened in your web browser and just before checkin, make a habit to just glance through it once to make sure, you havent forgotten unknowingly anything.

Note:
This list is expandable.It would be great to add as much as points you find I have missed in respective sections.

JSFF/JSPX code- Checkpoints

  • Make sure, you have used Resource Bundle whereever its required.
  • For Bounded taskFlows, make sure to use activation as conditional/deferred(Not Immediate) and use active condition EL expression.
  • Id of the component, length should be <= 7.
  • Make sure, you have removed unwanted PageDef Bindings.
  • If af:popup is used, make sure to set the contentDelivery to "LazyUncached".
  • If using af:contextInfo, make sure the af:dialog has modal="false".
  • If using af:contextInfo, make sure the af:showPopupBehavior has triggerType="contextInfo".
  • If using af:popup from af:commandLink, make the partialSubmit to true for af:commandLink.
  • If using af:popup. make childCreation property to "deferred" so that only when the Popup is launched the WebBean hierarchy would get created in server memory.
  • Run JAudit for the file you make changes, from Menu->Run->JAudit file.
  • Right click->Reformat before checkin.
  • If using JavaScript, can you think to avoid that.
  • jsff/jspx files must reside under /page package.
  • Taskflows must reside under /flow package.
  • Menu model xml files must reside under /menu package.
  • In Case of deriving the Url parameters, preferably use the following syntax to derive declaratively #
    Unknown macro: {facesContext.externalContext.requestParameterMap['Empno']}

    (Empno is url parameter)

Any Java Code - Checkpoints

  • Managed Bean class name should end with "Bean".
  • Dont use SOP statements.
  • New methods introduced, make sure they are modular so that they can be JUnitized.
  • New Method should aways return a value so that they can be JUnitized.
  • Add Logger statements to the new methods.
  • Make sure you have thrown sufficiently Exceptions.
  • Run JAudit for the file you make changes, from Menu->Run->JAudit file.
  • Make sure to define the Variables with a name starting with small letter.
  • Do not use underscore (_) in Variable and Method names.
  • Make sure to check for Null condition for all operation that could throw NullPointerException. Ex: CollectionModel, Row, ViewObject, ApplicationModule, String objects etc.
  • Right click->Reformat before checkin.

AM - Check Points

  • Number of occurances of createRootApplicationModule() or *AMImpl.getInstance() should be same as releaseRootApplicationModule().

Entity Object - Check Points

  • Can you convert the code you have just written into Groovy?
  • Run JAudit for the file you make changes, from Menu->Run->JAudit file.

ViewObject - CheckPoints

  • Get SQL explain plan everytime you touches a VO.
  • For new Attributes added, make sure you use proper UI hints.
  • If creating a New VO, make sure its is based on an EO(Exceptions to be considered).
  • if createViewObject calls are present, then make sure, you remove those dynamic ViewObjects.
  • If setting rangeSize() to -1, restore the rangeSize after you work on that.
  • Dont set ListRangeSize == '-1' unless the ViewAttribute using the LOV has CONTROLTYPE 'choice' or 'radio.' or 'default'
  • FetchSize should be <= 25 or same as number of rows to be displayed in UI.
  • Avoid use of vo.getROwCount()
  • View Criteria shouldnt have "null checking" checkbox checked.
  • LOVs shouldn't have "query automatically" checked.
  • SQL based VOs,should have query optimizer hint set to "FIRST_ROWS(10)".
  • Always test the application with ampooling= false when our bc4j txn involves any transient vos.

JDBC - Checkpoints

  • Move to the latest releases of Java as they become available.
  • Use prepared statements (PreparedStatement class) [article provides coded example of using Statement vs. PreparedStatement].
  • Note that two database calls are made for each row in a ResultSet: one to describe the column, the second to tell the db where to put the data. PreparedStatements make the description calls at construction time, Statements make them on every execution.
  • Avoid retrieving unnecessary columns: don't use "SELECT *".
  • If you are not using stored procedures or triggers, turn off autocommit. All transaction levels operate faster with autocommit turned off, and doing this means you must code commits. Coding commits while leaving autocommit on will result in extra commits being done for every db operation.
  • Use the appropriate transaction level. Increasing performance costs for transaction levels are: TRANSACTION_NONE; TRANSACTION_READ_UNCOMMITTED; TRANSACTION_READ_COMMITTED; TRANSACTION_REPEATABLE_READ; TRANSACTION_SERIALIZABLE. Note that TRANSACTION_NONE, with autocommit set to true gives access to triggers, stored procedures, and large object columns.
  • Store string and char data as Unicode (two-byte characters) in the database.
  • Avoid expensive database query functions such as: getBestRowIdentifier; getColumns; getCrossReference; getExportedKeys; getImportedKeys; getPrimaryKeys; getTables; getVersionColumns.
  • Use connection pooling, either explicitly with your own implementation, or implicitly via a product that supports connection pooling.
  • Use blocked fetchs (fetching table data in blocks), and tailor the block size to reduce calls to the database, according to the amount of data required.
  • Use batch updates (sending multiple rows to the database in one call).
  • Use stored procedures where appropriate. These benefit by reducing JDBC complexity, are faster as they use static SQL, and move execution to the server and potentially reduce network trips.
  • Use the type-correct get() method, rather than getObject().

EJB - Performance Checkpoints

  • Use session bean wrapper for returning multiple data rows from an entity bean, rather than returning one row at a time.
  • Use session beans for database batch operations, entity beans typically operate only one row at a time.
  • Use entity beans when only a few rows are required for the entity, and when rows need to be frequently updated.
  • Tune the underlying system, e.g. TCP/IP parameters, file limits, connection pool parameters, EJB pools sizes, thread counts, number of JVMs, JVM heap size, shared pool sizes, buffer sizes, indexes, SQL queries, keep/alive parameters, connection backlogs.
  • Transactions should span the minimum time possible as transactions lock database rows.
  • Use the lowest cost locking available from the database that is consistent with any transaction.
  • Use a dirty flag where supported by the EJB server to avoid writing unchanged EJBs to the database.
  • Commit the data after the transaction completes rather than after each method call (where supported by EJB server).
  • Do bulk updates to reduce database calls.
  • Tune the connection pool size to minimize the creation and destruction of database connections.
  • Use JDBC directly rather than using entity beans when dealing with large amounts of data such as searching a large database.
  • Use container-managed persistence when you can. An efficient container can avoid database writes when no state has changed, and reduce reads by retrieving records at the same time as find() is called.
  • Minimize database access in ejbStores. Use a "dirty" flag to avoid writing tee bean unless it has been changed.
  • Always prepare your SQL statements.
  • Close all database access/update statements properly.
  • Avoid deadlocks. Note that the sequence of ejbStore calls is not defined, so the developer has no control over the access/locking sequence to database records.

Fine Tune ADF Faces UI Layer(Performance Improvement)

Use AJAX to boost up the performance of your web pages

ADF Faces component trigger Partial Page Rendering (PPR) by default. However action components, by default, triggers full page refresh which is quite expensive and may not be required in most of the cases. Make sure that you set partialSubmit attribute to true whenever possible to optimize the page lifecycle. When partialSubmit is set to true, then only the components that have values for their partialTriggers attribute will be processed through the lifecycle.

Avoid mixing of html tags with ADF Faces components

Mixing raw html contents with ADF Faces components may produce undesired output, especially when you have complex layout design for your page. It's highly discouraged to use to embed JavaScript or CSS, instead you can use which adds the resource to the document element and optimizes further processing during tree rendering.

Avoid long Ids for User Interface components

It's always recommended to use short Ids for your User Interface (UI) components. Your JSF page finally boils down to html contents, whose size decides the network bandwidth usage for your web application.

Avoid inline usage of JavaScript/Cascading Style Sheets (CSS) whenever possible

If you need to use custom JavaScript functions or CSS in your application, try using external files to hold the same. Avoid inline usage of JavaScripts/CSS as much as possible. A better idea is to logically group them in external files and embed the required one in the candidate page using tag. If you keep JavaScript and CSS in external files, they are cached by the browser.

Avoid mixing JSF/ADF Faces and JavaServer Pages Standard Tag Library (JSTL) tags

Stick on JSF/ADF Faces components for building your UI as much as you can. JSF component may not work properly with some JSTL tags as they are not designed to co-exist. Relying on JSF/ADF Faces components may give you better extensibility and portability for your application as bonus.

Don't generate client component unless it's really needed

Set clientComponent to true only if you need to access the component on the client side using JavaScript. Otherwise this may result in increased Document Object Model (DOM) size at the client side and may affect the performance of your web page.

Prefer not to render the components over hiding components from DOM tree

If you need to hide UI components conditionally on a page, try achieving this with rendered property of the component instead of using visible property. Because the later creates the component instance and then hides the same from client side DOM tree, where as the first approach skips the component creation at the server side itself and client side DOM does not have this element added. Apparently setting rendered to false, reduces the client content size and gives better performance as bonus.

Prefer to use click-To-Edit over edit-All mode for tables

The click-To-Edit mode table lets the end user to edit the selected rows in a lockstep fashion, one row at a time. Advantages of using click-To-Edit mode are listed below.

  • In a click-To-Edit, non editable rows are rendered as output components which tend to generate less HTML than input components.
  • Client components are not created for the read-only rows.
  • Validation phase is also optimized to handle one row at a time.
  • Request and Response data is significantly lower in this mode as data relevant to the current editable row alone is being transferred between client and server. Really a good option if the table has large number of rows.

Fine tune the UI tables(af:table, af:tree, af:treeTable), displayed on your web page

  • Use appropriate content delivery mode
    Pick up the suitable content delivery mechanism for your UI table to accelerate the performance. Data can be delivered to table either upon rendering the page or lazily as separate Partial Page Request (PPR). This behavior is controlled by the contentDelivery attribute. Possible values for this attribute are:
    • immediate
    • lazy
    • whenAvailable

If the page contains only the table context or the number of rows displayed are low (say 50 or below) use immediate delivery. You can opt for lazy delivery when the page contains a number of components other than a table or if the number of rows filled is on the higher side.

  • Use suitable fetch size
    Data fetch size for a table plays critical role in deciding the performance of the containing pages. The attribute fetchSize decides the number of rows needs to be retrieved during each server round trip. You may need to ensure that value specified for this attribute is good enough to fill the displayed table rows to avoid further server round trips.

Pickup right component to display list of values (LOV)

ADF Faces provides multiple components or modes to display the 'list of values'. You may need to choose the right one based on your business requirements.

List Type Component
Input Text with List of Values af:inputListOfValues
Combo Box with List of Values af:inputComboboxListOfValues
Choice List, Combo Box, List Box, Radio Group af:selectOneChoice

Both af:inputListOfValues and af:inputComboboxListOfValues are smart enough to load the list of values on demand(lazy loading) where as af:selectOneChoice reads the entire list and populates the same when the page renders(greedy loading). You need to me be aware of the performance cost associated with each of these components. As a rule of thumb, consider af:selectOneChoice to display the list of values if the number of elements is less (say 15 or less) .In all other cases consider using either af:inputListOfValues or af:inputComboboxListOfValues, which loads list on demand.

we can disable ADF Faces Rich Client animation functionality globally, just by adding one line in trinidad-config.xml file:

  • animation-enabled = false

This will help greatly when rendering LOV popups, drawing data tables and etc. By disabling animation, artificial delay of components rendering is removed and this allows to achieve better UI performance.

Choose the right layouts to design your pages

  • While lay outing components on page, choose the right layout component that meets your requirement. If you don’t want stretch-to-fit layout, then dot use them at all. A stretch-to-fit layout is not as good performant as fixed height-width layouts.
  • Situation becomes worse, if you have nested containers with many child UI components inside.
  • You may need to be measured while opting for columnStretching property for a table to stretch the column to fit the available width. The columnStretching adds extra overhead on the client side at runtime. When the table is a complex one with large number of columns and rows, this becomes very expensive operation.
  • The same point is applicable for table with frozen columns (frozen=true), they are also expensive on the client side.

Avoid repetitive coding by improving the reusability

Use

  • Page templates
  • Declarative components
  • ADF task flows
  • Page Fragments

Use resource bundles intelligently

  • If the size of your resource bundle is huge, logically split that into multiple resource bundles. While splitting, please make sure that a single page doesn't need to look in to multiple bundles to get the localized strings.
  • Don’t over engineer your product by caching the ResourceBundle in your managed bean or through a custom way, it's already cached for you by design.

Always design your Managed Bean for High Availability

You may need to take care of following points in regards to managed bean while developing a high available fusion web application.

  • Keep the managed beans in the lowest possible scope
    While defining managed bean always try to keep them in the lowest possible scope, which reduces the runtime overhead associated with state replication across nodes in a clustered environment.
  • Keep the getters/setters of your managed bean (data model) lightweight
    You may need to understand that getters and setters for a managed bean used in a page may get called multiple times during the life cycle. Always make sure that assessors specified for the data model doesn't have any complex logic. Use managed bean only to store book keeping information, business logic should reside in your business service layer.
  • Bean should be serializable
    If the managed bean scope is higher than request, then its state needs to be serialized and copied to other nodes at the end of each request. Obviously beans need to implement java.io.Serializable interface. Note that, member variable of you class should also be serializable, or marked as transient if their state does not need to be replicated at the end of a request.
  • Mark ADF scopes as dirty to enable state replication
    ADF optimizes state replication of ADF scoped beans to avoid the blind copy of the state at the end of each request. So you may need to ask for state replication by marking them as dirty, based on bean mutation state. Use the below API to ensure the state replication for viewScope or pageFlowScoped bean if its modified for any request.
    ControllerContext.getInstance().markScopeDirty(viewScope/pageFlowScope);

Log your debugging messages smartly with ADFLogger

  • It's a bad practice to use System.out.println() to log your debugging or diagnostic messages. There is no easy way to turn off or control these logs when your application goes for production.
  • it is recommended to use oracle.adf.share.logging. ADFLogger to log all debugging messages which gives more control on the logging part. You can easily change log levels (turn off or customize) of ADFLogger using the configuration parameters present in logging.xml.

Feel free to override the default rules set for JavaScript Partitioning

  • ADF Faces provides a way to group (partitions) the JavaScript source files logically and down load each partition on demand.
  • ADF Faces allows you to tune the JavaScript library footprint to meet the needs of their application.
  • You can override the default partition rules (that come with ADF Faces) by creating your own adf-js-partitions.xml in the WEB-INF directory.

Speed up your web application by caching static contents

  • Caching static contents such as images, JavaScript, css etc. improves performance of the system.
  • ADF Faces is packaged with oracle.adf.view.rich.webapp.AdfFacesCachingFilter (servlet filter) which marks the application resources for caching at external Web Cache and/or user-agents (browsers).
  • ADF Faces comes with set of default rules for caching static contents; however developers can override the default caching behavior with application's adf-config.xml file.
  • This file is located under your web application's WEB-INF folder. Following diagram shows the syntax for defining caching rules in adf-config.xml.

    <adf-config xmlns="http://xmlns.oracle.com/adf/config"
    xmlns:adf="http://xmlns.oracle.com/adf/config/properties"
    xmlns:sec="http://xmlns.oracle.com/adf/security/config">
    <adf-faces-config xmlns="http://xmlns.oracle.com/adf/faces/config">
    <caching-rules>
    <caching-rule id="cache js">
    <cache>true</cache>
    <compress>true</compress>
    <duration>99999</duration>
    <agent-caching>true</agent-caching>
    <cache-key-pattern>*.js</cache-key-pattern>
    </caching-rule>
    <caching-rule id="cache jpeg">
    <cache>true</cache>
    <compress>false</compress>
    <duration>99999</duration>
    <agent-caching>true</agent-caching>
    <cache-key-pattern>*.jpeg</cache-key-pattern>
    </caching-rule>
    </caching-rules>
    </adf-faces-config>
    </adf-config>

Chapter 8 of Fusion Middleware Performance Tuning has more tips and information

http://download.oracle.com/docs/cd/E17904_01/core.1111/e10108/adf.htm#CIHHGADG

Usecase(ADF)-Controlling UI components Behaviour from Model Layer

Requirement

Say,an ADF UI has 50 UI components and you want to control these UI components behaviour dynamically.For example,

* 15 UI components shouldnt be rendered in a specific condition.
* 10 UI components should be ReadOnly in a specific condition.
* 20 UI components should have a MaxLength 120 in a specific condition.
* 30 UI components should have a different Label in a specific condition.
* and so on.

Simple Solution

Simplest solution is to manipulate the "rendered", "disabled" ,"label", "shortDesc", "maximumLength" etc properties in the JSFF/JSPX using EL expressions which can be calculated using a managed bean method.
Smart Solution

The simple solution makes the JSFF/JSPX messy with complex conditional EL expressions which is hard to maintain and improvise.

A smart solution is to handle this entirely in the Model Layer if your UI is driven by a View Object. View Object attributes have Control Hints which derive their values and represent themselves in the UI layer.

These are the things you need to do to achieve this.

Create a Service/Util class that will handle the logic to derive the values of the properties based on some business requirement.

import java.util.HashMap;
import java.util.Map;

import oracle.jbo.AttributeHints;

public class UIHintsService {

private static UIHintsService uiHintsService;

private UIHintsService() {
super();
}

public static synchronized UIHintsService getInstance() {
if (uiHintsService == null) {
uiHintsService = new UIHintsService();
}
return uiHintsService;
}
//Your Business Logic goes here, which says, for DepartmentName Attribute following UI properties need to be changed at the runtime.
public Map getAttributeHints(String attributeName) {
Map map = new HashMap();
if("DepartmentName".equalsIgnoreCase(attributeName))
{
map.put(AttributeHints.ATTRIBUTE_CTL_DISPLAYWIDTH, 100);
map.put(AttributeHints.ATTRIBUTE_LABEL,
attributeName + "[Overridden1111]");
map.put(AttributeHints.ATTRIBUTE_TOOLTIP,
attributeName + "[Overridden1111]");
map.put(AttributeHints.ATTRIBUTE_DISPLAY_HINT,
AttributeHints.ATTRIBUTE_DISPLAY_HINT_HIDE);
map.put(AttributeHints.HINT_NAME_UPDATEABLE,
"NEVER");
}
return map;
}
}



Create a Custom Class in your Model Layer called LazyViewRowAttrHintsImpl.java that extends oracle.jbo.server.ViewRowAttrHintsImpl.

public class DepartmentsViewRowImpl extends ViewRowImpl {


/**
* This is the default constructor (do not remove).
*/
public DepartmentsViewRowImpl() {
}

/**
* Gets Departments entity object.
* @return the Departments
*/
public EntityImpl getDepartments() {
return (EntityImpl)getEntity(0);
}

@Override
protected ViewRowAttrHintsImpl createViewRowAttrHints(AttributeDefImpl attrDef) {
//See here, we are returning the custom RowAttrHintsImpl class which has our own logic
return new LazyViewRowAttrHintsImpl(attrDef, this);
}

}
import java.util.HashMap;

import java.util.Map;

import oracle.jbo.AttributeHints;
import oracle.jbo.LocaleContext;
import oracle.jbo.server.AttributeDefImpl;
import oracle.jbo.server.ViewAttributeDefImpl;
import oracle.jbo.server.ViewRowAttrHintsImpl;
import oracle.jbo.server.ViewRowImpl;

import model.UIHintsService;

public class LazyViewRowAttrHintsImpl extends ViewRowAttrHintsImpl {

public LazyViewRowAttrHintsImpl(AttributeDefImpl attributeDefImpl,
ViewRowImpl viewRowImpl) {
super(attributeDefImpl, viewRowImpl);
decorateWithLazyHints(attributeDefImpl);

}

public LazyViewRowAttrHintsImpl() {
super();
}

private void decorateWithLazyHints(AttributeDefImpl attributeDefImpl) {
String flag = (String)attributeDefImpl.getProperty("Populated");
if ("true".equals(flag)) {
return;
}
System.out.println("##### Inside decorateWithLazyHints for : " +
attributeDefImpl.getName());
Map propMap =
UIHintsService.getInstance().getAttributeHints(attributeDefImpl.getName());
if (propMap != null && propMap.size() > 0) {
attributeDefImpl.setPropertyMap(propMap);
AttributeDefImpl entAttr =
((ViewAttributeDefImpl)attributeDefImpl).getEntityAttributeDef();
if (entAttr != null) {
entAttr.setPropertyMap(propMap);
}
}
attributeDefImpl.setProperty("Populated", "true");
}
}



In your VORowImpl.java, override the method createViewRowAttrHints(AttributeDefImpl attrDef) to return the custom LazyViewRowAttrHintsImpl like this.

Your UI JSFF/JSPX would look like this as you have already used the VO bound UI and the control hints would automatically be bound to these components.

<af:inputText value="#{bindings.DepartmentId.inputValue}"
label="#{bindings.DepartmentId.hints.label}"
rendered="#{bindings.DepartmentId.hints.displayHint == 'DISPLAY'}"
required="#{bindings.DepartmentId.hints.mandatory}"
columns="#{bindings.DepartmentId.hints.displayWidth}"
maximumLength="#{bindings.DepartmentId.hints.precision}"
shortDesc="#{bindings.DepartmentId.hints.tooltip}"
id="it3">
<f:validator binding="#{bindings.DepartmentId.validator}"/>
<af:convertNumber groupingUsed="false"
pattern="#{bindings.DepartmentId.format}"/>
</af:inputText>
<af:inputText value="#{bindings.DepartmentName.inputValue}"
label="#{bindings.DepartmentName.hints.label}"
rendered="#{bindings.DepartmentName.hints.displayHint == 'DISPLAY'}"
required="#{bindings.DepartmentName.hints.mandatory}"
columns="#{bindings.DepartmentName.hints.displayWidth}"
maximumLength="#{bindings.DepartmentName.hints.precision}"
shortDesc="#{bindings.DepartmentName.hints.tooltip}"
id="it1">
<f:validator binding="#{bindings.DepartmentName.validator}"/>
</af:inputText>
<af:inputText value="#{bindings.ManagerId.inputValue}"
label="#{bindings.ManagerId.hints.label}"
rendered="#{bindings.ManagerId.hints.displayHint == 'DISPLAY'}"
required="#{bindings.ManagerId.hints.mandatory}"
columns="#{bindings.ManagerId.hints.displayWidth}"
maximumLength="#{bindings.ManagerId.hints.precision}"
shortDesc="#{bindings.ManagerId.hints.tooltip}"
id="it4">
<f:validator binding="#{bindings.ManagerId.validator}"/>
<af:convertNumber groupingUsed="false"
pattern="#{bindings.ManagerId.format}"/>
</af:inputText>
<af:inputText value="#{bindings.LocationId.inputValue}"
label="#{bindings.LocationId.hints.label}"
rendered="#{bindings.LocationId.hints.displayHint == 'DISPLAY'}"
required="#{bindings.LocationId.hints.mandatory}"
columns="#{bindings.LocationId.hints.displayWidth}"
maximumLength="#{bindings.LocationId.hints.precision}"
shortDesc="#{bindings.LocationId.hints.tooltip}"
id="it2">
<f:validator binding="#{bindings.LocationId.validator}"/>
<af:convertNumber groupingUsed="false"
pattern="#{bindings.LocationId.format}"/>
</af:inputText>

Monday, March 28, 2011

Estimating Database Table Size

Table->PRODUCT

Sql>analyze table PRODUCTcompute statistics;

Sql> select extent_id, bytes, blocks
from user_extents
where segment_name = 'PRODUCT'
and segment_type = 'TABLE'

"EXTENT_ID" "BYTES" "BLOCKS"
0 1048576 128
1 1048576 128
2 1048576 128


Sql> select blocks, empty_blocks,
avg_space, num_freelist_blocks
from user_tables
where table_name = 'PRODUCT'

"BLOCKS" "EMPTY_BLOCKS" "AVG_SPACE" "NUM_FREELIST_BLOCKS"
376 8 1021 0

Anaylsis
the above shows us:
• we have 128*3(384) blocks allocated to the table
• 8 blocks are totally empty
• 376 block contains data (the other block is used by the system)
• we have an average of about 1k(1021, AVG_SPACE) free on each block used.

Therefore, our table ('FMT027T')

• consumes 376 block
• of which 376block * 8k blocksize - 8 block * 1k free = 3000k is used for our data.


Another Simple SQL is

select sum(bytes) from user_segments where segment_name = 'PRODUCT';