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();
}

}