Archive for oc4j

OWSM Faultstring: Http status code: 404

Scenario

An Oracle BPEL application was virtualized in WSM. When the virtualized service was tested, an "Http status code: 404" fault was encounterred .

Error Message

 
<faultcode xmlns="http://schemas.oblix.com/ws/2003/08/Faults">Client.UndeliverableFault</faultcode>
<faultstring>Http status code: 404</faultstring>
 

Diagnosis

* Checked gateway log file (OracleAS_2\j2ee\oc4j_soa\log\gateway.log) and found:
The requested URL /MyService/MySoapHttpPort was not found on this server.
* Viewed Messenger Step for Service: SID0003005 (Policy Management -> Register Services -> Services -> Click "View Details" icon -> Click "View Protocol Parameters" link) and found the HTTP Messenger URL property is set to:
http://localhost/MyService/MySoapHttpPort

Cause

* In BPEL application, "Client" partner link's WSDL imports an existing WSDL document which contains the offending dummy soap:address. During virtualization, WSM incorrectly uses it in HTTP Messenger URL.

Solution 1

* Modify HTTP Messenger URL property and point to the correct physical service endpoint
(Policy Management -> Register Services -> Services -> Click "Edit" icon -> Click "--> Modify Protocol Parameters" link)
* Save -> Save -> OK -> commit -> OK

Solution 2

* Remove the <service> section from the imported WSDL.
* Revirtualize the service.
* Caveat: you'll get a new SID

Oracle BPEL Process Resiliency

* See this post for policy based fault handlings.

Partner Link Failover

* Partner link failover locations can be specified in bpel.xml

 
<partnerLinkBinding name="RatingService">
<property name="wsdlLocation">
    http://localhost:8080/axis/services/RatingService1?wsdl
  </property>
<property name="location">
    http://localhost:1234/axis/services/RatingService1
    http://localhost:8080/axis/services/RatingService2
  </property>
</partnerLinkBinding>
 

Partner Link Retries

* Partner link retries can be specified in bpel.xml

 
<partnerLinkBinding name="FlakyService">
<property name="wsdlLocation">
    http://localhost:8080/axis/services/FlakyService?wsdl
  </property>
<property name="location">
    http://localhost:2222/axis/services/FlakyService
  </property>
<property name="retryMaxCount">2</property>
<property name="retryInterval">60</property>
</partnerLinkBinding>
 

Human Intervention

References

* OracleAS_2\bpel\samples\demos\ResilientDemo\ResilientFlow\ResilientFlow.pdf

Oracle BPEL Fault Policies

Fault Policy Overview

* Since 10.1.3.3
* Catches all faults from an invoke activity (both run time and business faults)
* Overrides all catch activities in BPEL process.
* A fault policy defines conditions and their corresponding fault recovery actions.
* Fault policies are defined in multiple files under directory:
- bpel\domains\default\config\fault-policies
* XSD files are:
- bpel\system\xmllib\fault-policy.xsd
- bpel\system\xmllib\fault-policy-binding.xsd
* A fault policy can be associated at the following levels:
- Partner link
- Port type
- Process level via bpel.xml
- Domain level via fault-bindings.xml
* Fault policy binding order:
-> bpel.xml: partner link -> port type -> process
-> domain: partner link -> port type -> process
-> Catch blocks defined in bpel diagram.

SOA Fault Types

Business Faults

* Programmer defined.
* Defined in WSDL.

Runtime Faults

* Predefined, e.g.
- remoteFault
- bindingFault
* Infrastructure faults, e.g.
- Service down
- Network outage
* Data format errors

Design a Fault Policy

Create a Fault Policy File

* Create policy file (e.g. my-policies.xml) in bpel\domains\domain_name\config\fault-policies directory

Define conditions

* Conditions are based on faultName. e.g.

 
<faultName
  xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
  name="bpelx:remoteFault">
 

* Multiple conditions are allowed for a single faultName
- if so, conditions are evaluated sequentially

 
  <condition>
    <test>$fault.code/code="WSDLReadingError"</test>
    <action ref="ora-terminate"/>
  </condition>
  <condition>
    <action ref="ora-java"/>
  </condition>
 

* Each condition has
- one test section which is an XPath expression against fault variable

 
    <test>$fault.code/code="WSDLReadingError"</test>
 

- one action section which references to the action defined in the same file

 
    <action ref="ora-terminate"/>
 

- No test condition catches all

 
<condition>
  <action ref="ora-rethrow"/>
</condition>
 

- No faultName catches all faults

 
<faultName > . . . </faultName>
 

Define actions

* See examples below.

Fault Policy Examples

* Conditions

 
<Conditions>
  <!-- when bpelx:remoteFault, retry -->
  <faultName
    xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
    name="bpelx:remoteFault">
    <condition>
      <action ref="ora-retry"/>
    </condition>
  </faultName>
 
  <!-- when bpelx:bindingFault, rethrow fault -->
  <faultName
    xmlns:bpelx="http://schemas.oracle.com/bpel/extension"
    name="bpelx:bindingFault">
    <condition>
      <action ref="ora-rethrow-fault"/>
    </condition>
  </faultName>
</Conditions>
 

* Actions

 
<!-- retry Action -->
<Action id="ora-retry">
  <retry>
    <retryCount>8</retryCount>
    <retryInterval>2</retryInterval>
    <retryFailureAction ref="ora-terminate"/>
    <exponentialBackoff/>
  </retry>
</Action>
 
<!-- replayScope Action -->
<Action id="ora-replay-scope">
  <replayScope/>
</Action>
 
<!-- rethrowFault Action -->
<Action id="ora-rethrow-fault">
  <rethrowFault/>
</Action>
 
<!-- humanIntervention Action -->
<Action id="ora-human-intervention">
  <humanIntervention/>
</Action>
 
<!-- abort Action -->
<Action id="ora-terminate">
  <abort/>
</Action>
 
<!-- Custom Java Action -->
<Action id="ora-java">
  <javaAction className="mypackage.myClass"
    defaultAction="ora-terminate"
    propertySet="propSet1">
    <returnValue value="R_TRM"
      ref="ora-terminate"/>
    <returnValue value="R_THRW"
      ref="ora-rethrow-fault"/>
  </javaAction>
</Action>

- Java class must implement IFaultRecoveryJavaClass interface

 
public interface IFaultRecoveryJavaClass {
  public void handleRetrySuccess(IFaultRecoveryContext ctx );
  public String handleBPELFault(IFaultRecoveryContext ctx );
}

Associate a Fault Policy

* Process level
- Configured in bpel.xml file.
- Only one fault policy can be bound to a process, port type, or partner link.
- Multiple port types or partner links can be bound to a single fault policy.

 
<faultPolicyBindings>
  <!-- Fault on any plink/port type not specified -->
  <!-- below uses policy BillingFaults -->
<process faultPolicy="BillingFaults"/>
<partnerLink xmlns:credit="http://services.otn.com" faultPolicy="CRM_
    ServiceFaults">
      <!-- Fault on these 2 plink will use policy CRM_ServiceFaults -->
      <name>UnitedLoanService</name>
      <name>StarLoanService</name>
 
    <!----Fault on these 2 port types uses policy CRM_ServiceFaults -->
<portType>credit:CreditRatingService</portType>
<portType xmlns:united="http://services.uninted.com/loan">
    united:UnitedLoanService</portType>
  </partnerLink>
<partnerLink faultPolicy="myOtherFaults">
    <!-- Fault on this plink uses policy myOtherFaults -->
    <name>AnotherPartnerLink</name>
  </partnerLink>
</faultPolicyBindings>
 

* Domain level
- Configured in OracleAS_2\bpel\domains\default\config\fault-bindings.xml file.

 
  <!-- all processes in this domain use DefaultPolicy -->
<process faultPolicy="DefaultPolicy"/>
 
 
<partnerLink faultPolicy="DefaultPolicy">
    <!-- all invoke faults at partner link creditRatingService use DefaultPolicy -->
    <name>creditRatingService</name>
  </partnerLink>
 
 
<partnerLink faultPolicy="DefaultPolicy">
    <!-- all invoke faults at specific port type use DefaultPolicy -->
<portType
      xmlns:db="http://xmlns.oracle.com/pcbpel/adapter/db/insert/">db:insert_plt</portType>
  </partnerLink>
 

Human Intervention in Oracle BPEL Control

* Login BPEL console
* Click Activities tab
* Seach activities based on states
- All States: Displays all activities, regardless of their state.
- Open: Displays only open activities.
- Completed: Displays only completed activities.
- Cancelled: Displays only cancelled activities.
- Stale: Displays only stale activities.
- Pending: Displays only pending activities.
* Click the faulted activity
* Optionally change the variable values
* Select action to take
- Retry: Retries the activity with an option to provide a retry success action.
- Abort: Terminates the process instance of the faulted activity.
- Rethrow: Rethrows the exception and allows the BPEL fault handlers (catch branches) to handle the fault.
- Replay: Replays the scope in which the fault occurred.
- Continue: Skips the activity. The framework assumes the activity completed with no fault.
* Click the Recover button.

References

* Fault Management Framework
* http://www.oracle.com/technology/tech/soa/cab/OracleSOACabWebinar03-25-08SOAExceptions.pdf
* Oracle BPEL 10.1.3.3 Fault Policy Management

Access AQ JMS Destinations From OC4J Web Application

Overview

* Setup Oracle AQ in Oracle database.
* Setup data source in data-sources.xml file.
* Setup resource provider in orion-application.xml.
* Setup logical JNDI names for JMS connection factories and destinations in web.xml file.
- Use <resource-ref> for connection factories.
- Use <resource-env-ref> for destinations.
* Map logical JNDI names to actual JNDI names in orion-web.xml file.
* Package into EAR file and deploy to OC4J.

Setup Oracle AQ

* See this post for details.

Setup data source

* Add to EAR data-sources.xml

 
<managed-data-source
  login-timeout='-1'
  connection-pool-name='MyAQUserDSPool'
  jndi-name='jdbc/xa/MyAQUserDS'
  name='MyAQUserDS'
  tx-level='global'
  manage-local-transactions='false'/>
 
<connection-pool name='MyAQUserDSPool'>
  <connection-factory
    factory-class='oracle.jdbc.pool.OracleDataSource'
    user='MyAQUser'
    password='MyAQUserPass'
    url='jdbc:oracle:thin:@localhost:1521:orcl'>
<proxy-interface sql-object='Connection'
      interface='oracle.jdbc.internal.OracleConnection'/>
<proxy-interface sql-object='Statement'
      interface='oracle.jdbc.OracleStatement'/>
<proxy-interface sql-object='CallableStatement'
      interface='oracle.jdbc.OracleCallableStatement'/>
<proxy-interface sql-object='PreparedStatement'
      interface='oracle.jdbc.OraclePreparedStatement'/>
<proxy-interface sql-object='ResultSet'
      interface='oracle.jdbc.OracleResultSet'/>
  </connection-factory>
</connection-pool>
 

Setup Resource Provider

* Add to EAR orion-application.xml

 
<data-sources path="./data-sources.xml"/>
<resource-provider
  class="oracle.jms.OjmsContext"
  name="MyAQJMSResourceProvider">
<property name="datasource"
    value="jdbc/xa/MyAQUserDS"/>
</resource-provider>
 

Setup Logical JNDI Names

* Add to WAR web.xml. Make sure to use resource-ref for connection factories and resource-env-ref for destinations.

 
<resource-ref>
  <res-ref-name>jms/TopicConnectionFactory</res-ref-name>
  <res-type>javax.jms.TopicConnectionFactory</res-type>
  <res-auth>Container</res-auth>
</resource-ref>
<resource-env-ref>
  <resource-env-ref-name>jms/sensorConfigTopic</resource-env-ref-name>
  <resource-env-ref-type>javax.jms.Topic</resource-env-ref-type>
</resource-env-ref>
 

Map Logical JNDI Names

* Add to orion-web.xml. Make sure to use resource-ref-mapping for connection factories and resource-env-ref-mapping for destinations.

 
<resource-ref-mapping
  name="jms/TopicConnectionFactory"
  location="java:comp/resource/MyAQJMSResourceProvider/TopicConnectionFactories/MyTCF"/>
 
<resource-env-ref-mapping
  name="jms/sensorConfigTopic"
  location="java:comp/resource/MyAQJMSResourceProvider/Topics/MyAQUser.TEST_TOPIC"/>

Package into EAR File and Deploy to OC4J Container

Sample Code

* Sample code to receive message from an AQ topic.

 
import javax.jms.JMSException;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jms.TopicConnection;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicSession;
import javax.jms.TopicSubscriber;
 
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
 
import org.apache.log4j.Logger;
 
public class JMSUtil {
  static Logger log = Logger.getLogger(JMSUtil.class.getName());
  private static final String TOPIC_CONN_FACTORY =
      "java:comp/env/jms/TopicConnectionFactory";
  private static final String TEST_TOPIC =
      "java:comp/env/jms/TestTopic";
 
  public static void main(String[] args) {
      JMSUtil util = new JMSUtil();
 
      TextMessage tm;
      try {
          tm = util.receiveTest("testId");
      } catch (JMSException e) {
          log.error(e);
      } catch (NamingException e) {
          log.error(e);
      }
  }
 
  public TextMessage receiveTest(String subscriberID)
      throws NamingException, JMSException {
      log.debug("============================");
      log.debug("Start receiveTest...");
      log.debug("============================");
      Context ctx = null;
      TopicConnectionFactory tcf = null;
      TopicConnection conn = null;
      Topic topic = null;
      TextMessage msg = null;
      TopicSession session = null;
      TopicSubscriber sub = null;
      try {
          ctx = new InitialContext();
          log.debug("got InitialContext.");
 
          tcf =
              (TopicConnectionFactory)ctx.lookup(TOPIC_CONN_FACTORY);
          log.debug("got TopicConnectionFactory.");
          conn = tcf.createTopicConnection();
          log.debug("got conn.");
          topic = (Topic)ctx.lookup(TEST_TOPIC);
          log.debug("got topic.");
          session = conn.createTopicSession(false, TopicSession.AUTO_ACKNOWLEDGE);
          conn.start();
          log.debug("strated conn.");
          sub = session.createDurableSubscriber(topic, subscriberID);
          msg = (TextMessage)sub.receive(5000);
          if (msg != null){
              log.debug(msg.getText());
          } else {
              log.debug("No message");
          }
      } finally {
          if (sub != null)
              sub.close();
          if (session != null)
              session.close();
          if (conn != null)
              conn.close();
      }
      log.debug("done.");
      return msg;
  }
 
}