Freitag, Dezember 09, 2005
J2EE - Oracle Enterprise Users Security
Oracle Enterprise Users Security make it possible to combine SSO, JAAS, JDBC-Connection Pooling (J2EE-DataSouce) and VPD (Row Level Security) in conjunction with Proxy Authentication and single stored LDAP Users/Roles.
Depending of the securit requirements and used product or feature stack, many different configurations possible. Following I will demonstrate the scenario how to use Oracle Enterprise Users Security with connection pooling in an Java EE environment.
Suppose you have 3 user types:
1. Enterprise User: The LDAP users which connect to the DB without any DB resources (No DB create user command is required!)
2. Global Schema User: The DB-Schema how the enterprise user is automaticly mapped to.
3. JDBC Pool User: The user used to create the connection pool with only connect rights. That user has no resource or other permissons.
Required steps:
1. Create the LDAP V3 User Structure with any LDAP Tool or command
2. Use the Oracle Enterprise Security Manager and Map the LDAP Roles to DB Roles
3. create the oracle pool user: create jdbcpooluser identified by MyPassword123
4. grant connect to jdbcpooluser
5. Permit the Global-Schema user to connect through the jdbc pool user: alter user global_schema grant connect through jdbcpooluser
6. On each connect swich the jdbc connection from the pool to the LDAP user:
properties.put(oraConnection.PROXY_DISTINGUISHED_NAME, username);
oraConnection.openProxySession(OracleConnection.PROXYTYPE_DISTINGUISHED_NAME,´properties);
Within Springframwork you can overwrite the doGetConnection methode of UserCredentialsDataSourceAdapter class to get the connection hook before Sring makes any DB access.
To establish this inside a JSF-Application you must overwrite the SpringPhaseListener to bound the principal to the current Thread:
FacesContext fc = FacesContext.getCurrentInstance().getExternalContext().
Principal j2eePrincipal = fc.getUserPrincipal(); // Bound the context to the current thread with your helper class in usage of the InheritableThreadLocal static variable BmaierContextHolder.createContext(j2eePrincipal);
Afterward you should overwrite the methode doGetConnection of UserCredentialsDataSourceAdapter class as followed:
protected Connection doGetConnection(String username, String password) throws SQLException {
...
Connection connection = getTargetDataSource().getConnection(username, password); ...
if(connection instanceof oracle.jdbc.OracleConnection){ BmaierSecurityContext sc = BmaierSecurityContextHolder.getNgcmSecurityContext();
username = sc.getPrincipal().getName();
// we grant DB-proxy without explicit password delivery - make SSO possible!
password = "";
OracleConnection oc = (OracleConnection)connection;
properties.put(oraConnection.PROXY_DISTINGUISHED_NAME, username);
oraConnection.openProxySession(OracleConnection.PROXYTYPE_DISTINGUISHED_NAME, properties);
return oraConnection;
}
This make it possible to use J2EE/JAAS-Authentication in conjunction with secured and pooled database connections.
Depending of the securit requirements and used product or feature stack, many different configurations possible. Following I will demonstrate the scenario how to use Oracle Enterprise Users Security with connection pooling in an Java EE environment.
Suppose you have 3 user types:
1. Enterprise User: The LDAP users which connect to the DB without any DB resources (No DB create user command is required!)
2. Global Schema User: The DB-Schema how the enterprise user is automaticly mapped to.
3. JDBC Pool User: The user used to create the connection pool with only connect rights. That user has no resource or other permissons.
Required steps:
1. Create the LDAP V3 User Structure with any LDAP Tool or command
2. Use the Oracle Enterprise Security Manager and Map the LDAP Roles to DB Roles
3. create the oracle pool user: create jdbcpooluser identified by MyPassword123
4. grant connect to jdbcpooluser
5. Permit the Global-Schema user to connect through the jdbc pool user: alter user global_schema grant connect through jdbcpooluser
6. On each connect swich the jdbc connection from the pool to the LDAP user:
properties.put(oraConnection.PROXY_DISTINGUISHED_NAME, username);
oraConnection.openProxySession(OracleConnection.PROXYTYPE_DISTINGUISHED_NAME,´properties);
Within Springframwork you can overwrite the doGetConnection methode of UserCredentialsDataSourceAdapter class to get the connection hook before Sring makes any DB access.
To establish this inside a JSF-Application you must overwrite the SpringPhaseListener to bound the principal to the current Thread:
FacesContext fc = FacesContext.getCurrentInstance().getExternalContext().
Principal j2eePrincipal = fc.getUserPrincipal(); // Bound the context to the current thread with your helper class in usage of the InheritableThreadLocal static variable BmaierContextHolder.createContext(j2eePrincipal);
Afterward you should overwrite the methode doGetConnection of UserCredentialsDataSourceAdapter class as followed:
protected Connection doGetConnection(String username, String password) throws SQLException {
...
Connection connection = getTargetDataSource().getConnection(username, password); ...
if(connection instanceof oracle.jdbc.OracleConnection){ BmaierSecurityContext sc = BmaierSecurityContextHolder.getNgcmSecurityContext();
username = sc.getPrincipal().getName();
// we grant DB-proxy without explicit password delivery - make SSO possible!
password = "";
OracleConnection oc = (OracleConnection)connection;
properties.put(oraConnection.PROXY_DISTINGUISHED_NAME, username);
oraConnection.openProxySession(OracleConnection.PROXYTYPE_DISTINGUISHED_NAME, properties);
return oraConnection;
}
This make it possible to use J2EE/JAAS-Authentication in conjunction with secured and pooled database connections.
Mittwoch, September 07, 2005
BPEL Binary FileAdapter
within Oracle BPEL you have the choice to interprete file data as XML stream or as binary data. In the case of binary data the imput type will be a base64 encoded string representation. To decode the Base64 String you can use following java snipped:
CubeDOMElement doc = (CubeDOMElement)getVariableData("myVariable", "opaque","/ns2:opaqueElement");
String str = (String)doc.getData();
byte[] buf = new sun.misc.BASE64Decoder().decodeBuffer(str);
Freitag, August 19, 2005
Print BPEL Variable to Stdout
To trace BPEL Variables you can use the java task:
<bpelx:exec>
CubeDOMElement element = (CubeDOMElement)getVariableData ("MyVariable", "payload","/ns2:myData");
System.out.println(doc.asXML());
</bpelx:exec>
I use following command to make the output visible:
tail -f C:\%ORACLE_HOME%\opmn\logs\OraBPEL~OC4J_BPEL~default_island~1
<bpelx:exec>
CubeDOMElement element = (CubeDOMElement)getVariableData ("MyVariable", "payload","/ns2:myData");
System.out.println(doc.asXML());
</bpelx:exec>
I use following command to make the output visible:
tail -f C:\%ORACLE_HOME%\opmn\logs\OraBPEL~OC4J_BPEL~default_island~1
Mittwoch, August 17, 2005
Deploy additional BPEL Process Archives
It's a normal way to structure and separate java code from BPEL project. To deploy this dependend JAR-Archives automatically with your BPEL-Project, you must create the following Directory structure within your BPEL Project:
However, while developing with JDev, you get an compile error as long as you don't create a deployment-dependency to a the jar deployment profile of the other project. Hint: this dependency will not be evaluated from the BPEL deployment process!
and copy the required jar archives or classes to that directories.
- BPEL-INF - classes
- lib
However, while developing with JDev, you get an compile error as long as you don't create a deployment-dependency to a the jar deployment profile of the other project. Hint: this dependency will not be evaluated from the BPEL deployment process!
Output BPEL-Variable to OutputStream
Here is an example to write any BPEL-Variable to System.out or any other stream:
<bpelx:exec import="org.w3c.dom.*"/>
<bpelx:exec import="javax.xml.parsers.*"/>
<bpelx:exec import="javax.xml.transform.*"/>
<bpelx:exec import="javax.xml.transform.dom.*"/>
<bpelx:exec import="javax.xml.transform.stream.*"/>
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer= transformerFactory.newTransformer();
PrintStream outStream = System.out;
Result output = new StreamResult(outStream);
DOMSource source = new DOMSource((org.w3c.dom.Node) getVariableData("ReceiveFromRMRFileEvent_Read_InputVariable","RMR"));
transformer.transform(source,output);
<bpelx:exec import="org.w3c.dom.*"/>
<bpelx:exec import="javax.xml.parsers.*"/>
<bpelx:exec import="javax.xml.transform.*"/>
<bpelx:exec import="javax.xml.transform.dom.*"/>
<bpelx:exec import="javax.xml.transform.stream.*"/>
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer= transformerFactory.newTransformer();
PrintStream outStream = System.out;
Result output = new StreamResult(outStream);
DOMSource source = new DOMSource((org.w3c.dom.Node) getVariableData("ReceiveFromRMRFileEvent_Read_InputVariable","RMR"));
transformer.transform(source,output);
BPEL: User Defined Preferences
Oracle' BPEL deployment descriptor bpel.xml includes the undocumented section "preferences" to configure user defined properties. The generic BPEL Administration console BPELConsole allow the admistration of all variables at runtime without redeployment.
Sample:
<BPELSuitcase>
<BPELProcess id="MyProzess" src="myProzess.bpel">
<preferences>
<property name="myTempDir">c:\temp</property > </preferences>
</BPELProcess>
</BPELSuitcase>
Attention: the position of the preference section is very important. It must be the first element after the BPELProcess tag to work correctly.
There are two build-in functions to read this properties:
ora:getPreference(String name); in each xml expression andgetPreference in the java inline section
Sample:
<BPELSuitcase>
<BPELProcess id="MyProzess" src="myProzess.bpel">
<preferences>
<property name="myTempDir">c:\temp</property > </preferences>
</BPELProcess>
</BPELSuitcase>
Attention: the position of the preference section is very important. It must be the first element after the BPELProcess tag to work correctly.
There are two build-in functions to read this properties:
ora:getPreference(String name); in each xml expression andgetPreference in the java inline section
Mittwoch, Juli 13, 2005
WISIF - BPEL Java Binding Error
Within WISIF Java Binding you get properly an compile error for methode binding without paramters (eg. public Boolean ping();) like following:
[Error ORABPEL-10902]: compilation failed [Description]: in "bpel.xml", XML parsing failed because "notification operation not supported.In WSDL at MyService.wsdl", operation "ping" of portType "{http://xmlns.xxx.com/ch/rule/service}RLPortType" is a notification operation (The endpoint sends a message), which is not supported in this version. See chapter 2.4 of WSDL spec 1.1.Make sure the operation is "one-way" type or "request-response" type.". [Potential fix]: n/a.
To solve this problem you must define an message for empty parameters within portType section:
<message name="myPingRequest"> </message>
<message name="myPingResponse">
<part name="pingOutput" type="xsd:boolean"/>
</message>
<portType name="myPortType">
<operation name="ping">
<input name="myPingRequest" message="tns:myPingRequest"/>
<output name="myPingResponse" message="tns:myPingResponse"/>
</operation>
</portType>
[Error ORABPEL-10902]: compilation failed [Description]: in "bpel.xml", XML parsing failed because "notification operation not supported.In WSDL at MyService.wsdl", operation "ping" of portType "{http://xmlns.xxx.com/ch/rule/service}RLPortType" is a notification operation (The endpoint sends a message), which is not supported in this version. See chapter 2.4 of WSDL spec 1.1.Make sure the operation is "one-way" type or "request-response" type.". [Potential fix]: n/a.
To solve this problem you must define an message for empty parameters within portType section:
<message name="myPingRequest"> </message>
<message name="myPingResponse">
<part name="pingOutput" type="xsd:boolean"/>
</message>
<portType name="myPortType">
<operation name="ping">
<input name="myPingRequest" message="tns:myPingRequest"/>
<output name="myPingResponse" message="tns:myPingResponse"/>
</operation>
</portType>
Donnerstag, Juli 07, 2005
Oracle Business Rule Engine - JSR 94
Oracle offers a new Java based rule engine based on the JSR-94. Last view days I have the chance to test the rule enigin within an BPEL project to solve dynamic and high performance object manipulation requirements.
Now I'm very inspired about the performance and the ease of use. The main reason of this is the established Rule syntax like Java programming language. and the possiblility to mix Java objects and Java code with Rule RL without restrictions. This make it easy to integrate rules in Java code and manipulate or make dessisions depending of the current program status.
However, the web based rule author is currently in beta status and not realy usfull for complex rules. So I recommend to write your rule in the RL-Syntax and load the rules from file instead repository usage. This means you can omit the rule generation call java methode ruleSession.generateRL( props ) from the XML-Repository. Instead this use simple file loading of your own RL-Syntax file.
Now, have fun with Oracle Business Rules!
Now I'm very inspired about the performance and the ease of use. The main reason of this is the established Rule syntax like Java programming language. and the possiblility to mix Java objects and Java code with Rule RL without restrictions. This make it easy to integrate rules in Java code and manipulate or make dessisions depending of the current program status.
However, the web based rule author is currently in beta status and not realy usfull for complex rules. So I recommend to write your rule in the RL-Syntax and load the rules from file instead repository usage. This means you can omit the rule generation call java methode ruleSession.generateRL( props ) from the XML-Repository. Instead this use simple file loading of your own RL-Syntax file.
Now, have fun with Oracle Business Rules!
Mittwoch, Juni 15, 2005
Change XSLT engine within BPEL
I heard Oracle XDK XSLT engine should be faster than Apache XALAN engine. If you which, you can change the XSLT engine with the xmlns:ora namespace declaration in your BPEL process XML declaration as following:
Change xmlns:ora to xmlns:ora="http://schemas.oracle.com/bpel/extension/xpath/function/xdk" in the bpel....
Change xmlns:ora to xmlns:ora="http://schemas.oracle.com/bpel/extension/xpath/function/xdk" in the bpel
Freitag, April 29, 2005
ContextRoot JSF
How to get the ContextRoot in an JSF environment: #{facesContext.externalContext.requestContextPath} in my configuration">
Donnerstag, März 03, 2005
UIX 2.2.x can't handle Struts Tags
The could not be used in conjunction with uix:struts. This is founded in Struts-TagLib handling. All global-forward tags are bounded at rendering time to the link (Macro funktionality) and not while runtime like elements (/save.do).
A good practice with and without UIX is the usage of the element with a simple forwad attribute instead of .
A good practice with and without UIX is the usage of the
Montag, Januar 17, 2005
OC4J Debuglevel
-verbosity is my favorite OC4J startparameter to get OC4J debug output. The range is defined from 1-10:
$JAVA_HOME/java -jar oc4j.jar -verbosity 10
Today I need a additional parameter to get more information about the used DataSource:
java -Ddatasource.verbose=true -Dhttp.session.debug=true -jar oc4j.jar -verbosity
HTTP Debugging
- http.session.debug = Provides information about HTTP session events
- http.cluster.debug = Provides information about HTTP clustering events
- http.error.debug = Prints all HTTP errors
JDBC Debugging
- datasource.verbose = Provides verbose information on creation of data source and connections using Data Sources and connections released to the pool, etc,
- jdbc.debug = Provides very verbose information when JDBC calls are made
EJB Debugging
- ejb.cluster.debug = Turns on EJB clustering debug messages
- transaction.debug = Provides debug information on transactions, useful for JTA debugging
RMI Debugging
- rmi.debug = Prints RMI debug information
- rmi.verbose = Provides very verbose information on RMI callsJMS Debugging
- jms.debug = Prints JMS debug information
http://www.oracle.com/technology/tech/java/oc4j/htdocs/oc4j-logging-debugging-technote.html
Donnerstag, Januar 13, 2005
Get the serialized ADF-RowKey in uiXML
Within a UIX-Table you can get the serialized ADF-RowKey with the EL-Expression ${uix.current.rowKeyStr}. This undocumented feature allow you to bind the key to a link for table actions instead to use the singleSelection element:
Example to delete a row with a link into each table row:
<link text="${uix.current.EmployeeId.attributeValue}">
<boundAttribute name="destination">
<concat>
<contextProperty select="ui:contextURI"/>
<fixed text="/deleteEmp.do?rowKeyStr="/>
<dataObject source="${uix.current.rowKeyStr}"/>
<fixed text="&event=delete"/>
</concat>
</boundAttribute>
</link>
Example to delete a row with a link into each table row:
<link text="${uix.current.EmployeeId.attributeValue}">
<boundAttribute name="destination">
<concat>
<contextProperty select="ui:contextURI"/>
<fixed text="/deleteEmp.do?rowKeyStr="/>
<dataObject source="${uix.current.rowKeyStr}"/>
<fixed text="&event=delete"/>
</concat>
</boundAttribute>
</link>
Mittwoch, Januar 12, 2005
How to use the JAZN API to manage OC4J users
Here is a sample code to change the password in the jazn.xml file in usage of the JAZN API:
changeJaznUserPassword(String realm, String userName, String password){
RealmManager realmMgr = JAZNContext.getRealmManager();
Realm realm = realmMgr.getRealm(realm);
UserManager userMgr = realm.getUserManager();
RealmUser user = userMgr.getUser(userName);
XMLRealmUser xmlrealmuser = (XMLRealmUser)realm.getUserManager().getUser(userName);
if(xmlrealmuser == null)
throw new Exception("The specified user does not exist in the system.");
xmlrealmuser.setCredentials(userPwd, serRepeatedPwd);
// to refresh automaticlly you must set the property "external.synchronization = true" in jazn.xml - see previous blog
userMgr.refresh();
changeJaznUserPassword(String realm, String userName, String password){
RealmManager realmMgr = JAZNContext.getRealmManager();
Realm realm = realmMgr.getRealm(realm);
UserManager userMgr = realm.getUserManager();
RealmUser user = userMgr.getUser(userName);
XMLRealmUser xmlrealmuser = (XMLRealmUser)realm.getUserManager().getUser(userName);
if(xmlrealmuser == null)
throw new Exception("The specified user does not exist in the system.");
xmlrealmuser.setCredentials(userPwd, serRepeatedPwd);
// to refresh automaticlly you must set the property "external.synchronization = true" in jazn.xml - see previous blog
userMgr.refresh();
How to tell a running OC4J to refresh external updated Users (jazn-data.xml)
To tell a running OC4J instance to refresh the cached users after updating the jazn-data.xml manually, you must set the following parameter in the jazn.xml file
<property name="external.synchronization" value="true">
see also jazn documentation:
<property name="external.synchronization" value="true">
see also jazn documentation:
Mittwoch, Dezember 22, 2004
Write your own JSP EL-Functions to secure your web app
Frank has a very good description to use the J2EE security model to secure your web pages fine granular (ADF UIX: Enabling and disabling page compression in UIX). However I have an extention to this: Within the ADF UIX Framework you can easily extend EL and write your own EL methode like ${isUserInRole('GuestRole')}. As you know UIX was the initial idea to specify JavaServer Faces. So with UIX you can write for each component your own renderer. This means you can write your own Java methodes and call it within the EL renderer like this:
<submitButton disabled="${ctrl:isUserInRole(uix, 'GuestUserRole')}" text="Save" >
To accomplish this you must write the following code:
public final class ELFunctions{
public static Boolean isUserInRole(Object uix, String role) throws Exception{
ControllerImplicitObject uixObj = (ControllerImplicitObject)uix;
boolean isInRole = uixObj.getBajaContext().getServletRequest().isUserInRole(role);
return new Boolean(isInRole);
}
}
After writing your static Java EL Function you must write a framework factory class. This is accomplished by usage of the UIExtention Framework:
public class ELFunctionExtension implements UIExtension {
static Class funcClass = com.bm.ui.common.ELFunctions.class;
static Class getFuncClass(String className){
try {
Class clazz = Class.forName(className);
return clazz;
}
catch(ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
public void registerSelf(ParserManager parserManager) {
XMLUtils.registerFunctions(parserManager, "http://xmlns.oracle.com/uix/controller",
funcClass != null ? funcClass : (funcClass = getFuncClass ("com.bm.ui.common.ELFunctions")));
}
public void registerSelf(LookAndFeel lookandfeel) { }
}
Additional you must register the UIExtention in the WEB-INF/uix-config.xml file:
<ui-extensions>
<extension-class> com.bm.ui.common.ELFunctionExtension </extension-class>
</ui-extensions>
Now you can access the isUserInRole() method directly from the uiXML code:
<submitButton disabled="${!ctrl:isUserInRole(uix,'PowerUserRole')}" text="Save" >
or
<submitButton disabled="${not ctrl:isUserInRole(uix,'PowerUserRole')}" text="Save" >
or
<submitButton disabled="${ctrl:isUserInRole(uix,'GuestUserRole')}" text="Save" >
<submitButton disabled="${ctrl:isUserInRole(uix, 'GuestUserRole')}" text="Save" >
To accomplish this you must write the following code:
public final class ELFunctions{
public static Boolean isUserInRole(Object uix, String role) throws Exception{
ControllerImplicitObject uixObj = (ControllerImplicitObject)uix;
boolean isInRole = uixObj.getBajaContext().getServletRequest().isUserInRole(role);
return new Boolean(isInRole);
}
}
After writing your static Java EL Function you must write a framework factory class. This is accomplished by usage of the UIExtention Framework:
public class ELFunctionExtension implements UIExtension {
static Class funcClass = com.bm.ui.common.ELFunctions.class;
static Class getFuncClass(String className){
try {
Class clazz = Class.forName(className);
return clazz;
}
catch(ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
public void registerSelf(ParserManager parserManager) {
XMLUtils.registerFunctions(parserManager, "http://xmlns.oracle.com/uix/controller",
funcClass != null ? funcClass : (funcClass = getFuncClass ("com.bm.ui.common.ELFunctions")));
}
public void registerSelf(LookAndFeel lookandfeel) { }
}
Additional you must register the UIExtention in the WEB-INF/uix-config.xml file:
<ui-extensions>
<extension-class> com.bm.ui.common.ELFunctionExtension </extension-class>
</ui-extensions>
Now you can access the isUserInRole() method directly from the uiXML code:
<submitButton disabled="${!ctrl:isUserInRole(uix,'PowerUserRole')}" text="Save" >
or
<submitButton disabled="${not ctrl:isUserInRole(uix,'PowerUserRole')}" text="Save" >
or
<submitButton disabled="${ctrl:isUserInRole(uix,'GuestUserRole')}" text="Save" >
Sonntag, Dezember 19, 2004
ADF: How to edit the current selected row
There are may possibilities to edit the current selecte row in usage of ADF-Bindings, ADF- BC4J and uiXML .
- First you can do the task with a table and input fields into the same page . This approach is very simple and also used within Jdev generated sample code. The underling bindingModel associate to the identical page name and so the bounded edit fileds associate always the same model.
- Next to edit the current row into an other page without hidding only the table or edit elements, you must change the associated BindingModel in the new page to the calling page. This is done in five steps: create a new ADF Struts DataAction, change the requested modelName in the getBindingContainerName() methode of your overwritten oracle.cabo.adf.rt.InitModelListener. Additional you should copy all bindingControls from the original UIModel to the underling Model. Into the uiXML page you should call the associated struts action after setting the current row:
<singleSelection model="${bindings.EmployeesViewIterator}" text="Select and "> <primaryClientAction> <fireAction source="EmployeesView0" event="select"> </fireAction>
</primaryClientAction>
....
<event name="select">
<compound>
<set target="${bindings.EmployeesViewIterator}" property="currentRowIndexInRange" value="${ui:tableSelectedIndex(uix, 'EmployeesView0')}"/>
<struts:action path="/selectEmp.do">
</struts:action>
</compound>
</event>
The rest is automatically done by ADF. - A other way is to write our own DataAction for the current user selection. Remove the single selection element from uiXML table and add a column with the following selection link:
<column>
<columnFormat columnDataFormat="numberFormat"/>
<columnHeader>
<sortableHeader model="${ctrl:createSortableHeaderModel(bindings.EmployeesView,'EmployeeId')}"/>
</columnHeader>
<contents>
<link text="${uix.current.EmployeeId.attributeValue}">
<boundAttribute name="destination">
<concat> <contextProperty select="ui:contextURI"/>
<fixed text="/selectEmp.do?id="/>
<dataObject source="${uix.current.EmployeeId.attributeValue}"/>
<fixed text="&event=select"/>
</concat>
</boundAttribute>
</link>
</contents>
</column>
Afterward the associated adf struts action should set the current row and navigate to the edit page with the struts action forward tag:
public void onSelect(DataActionContext ctx){
String id = (String)evalEL("${param.id}",ctx);
JUIteratorBinding iter = (JUIteratorBinding)evalEL("${bindings.EmployeesViewIterator}", ctx);
Key key = new Key(new Object[] {id});
Row[] rows = iter.getViewObject().findByKey(key,1);
iter.setCurrentRowWithKey(key.toStringFormat(true));
}
Samstag, Dezember 18, 2004
How to evaluate any parameter in ADF-Actions
You can easiely evaluate any parameter including servlet, request or ADF binding parameters with the Expression Language Syntax (EL).
/** Evaluate an EL (expression language) Expression and return the result
* @param expression EL Expression to evaluate
* @param ctx The DataAction context.
* @return The object identified by the EL expression
*/
public Object evalEL(String expression, DataActionContext ctx) {
Evaluator eval = Evaluator.getEvaluator(ctx);
return eval.getValue(expression); }
An example to retrive a request parameter into an adf action:
...
String myImputParam = (String)evalEL(ctx, "${param.myInputParam}");
/** Evaluate an EL (expression language) Expression and return the result
* @param expression EL Expression to evaluate
* @param ctx The DataAction context.
* @return The object identified by the EL expression
*/
public Object evalEL(String expression, DataActionContext ctx) {
Evaluator eval = Evaluator.getEvaluator(ctx);
return eval.getValue(expression); }
An example to retrive a request parameter into an adf action:
...
String myImputParam = (String)evalEL(ctx, "${param.myInputParam}");
Donnerstag, Dezember 09, 2004
Spring Toplink Integration
I am very happy to annonce Oracle's Springframwork support. The integration includes the Toplink Persistence Framework like Hibernate. http://www.oracle.com/technology/products/ias/toplink/preview/spring/index.html
... numerous thanks Jim Clark!
... numerous thanks Jim Clark!
Samstag, Oktober 23, 2004
Excellent Architecture
... a good architecture can be more than J2EE: http://www.allianzarena.de/impinc/fotogalerie/20042.php?actpos=11
I'm proud to announce the J2EE community our first success illumination test in Munich (Soccer Station). This is a very good example of extreme building and best architecture practice!
.. be inspired!
I'm proud to announce the J2EE community our first success illumination test in Munich (Soccer Station). This is a very good example of extreme building and best architecture practice!
.. be inspired!
Samstag, September 11, 2004
Struts versus JavaServer Faces (JSF)
Many people compare Struts with JSF. My experience on both give me the opinion to say there is a complete different development approach with JSF.
The only equals between JSF and Struts are the external XML defined states of the controller. The JSF-controller concept is much more comparable with Swing-Component (MVC) and not central managed like struts. Additional, Struts is only a Servlet-Controller based on the MVC-2 Pattern and does not include UI-Components with Rendering Delegation Pattern, Statemanagement, full I18N support, component validators etc.
The only equals between JSF and Struts are the external XML defined states of the controller. The JSF-controller concept is much more comparable with Swing-Component (MVC) and not central managed like struts. Additional, Struts is only a Servlet-Controller based on the MVC-2 Pattern and does not include UI-Components with Rendering Delegation Pattern, Statemanagement, full I18N support, component validators etc.
Freitag, September 10, 2004
Fetch children from any service method in ADF-Treebinding
With ADF-TreeBinding you have the only possibility to get the children nodes from the same BeanClass used to render the current node self. Therefor you must add a getter method that return a collection of childrens in the node bean. There is no possibility to delegate the call to an other service routine e.g. to a delegate class. With the proxy pattern you can solve this problem easily. You must wrap the node bean in a proxy class and delegate each call to wrapped node expect your getChildren() method. This method can use any service class to retrieve the children nodes and store the returned children's as proxies in the instance. Additional you must bind the proxy to the tree and not the node bean. This little trick make it ease to avoid the ADF-Binding restrictions.
Example code:
class MyNode implements Node {
...
int getId() {...}
String getName() {...}
List getChildren(){...}
...
}
class ProxyNode implements Node {
Node node = null;
Service service = null;
ProxyNode(Service service, Node node) {
this.node = node;
this.service = service;
}
String getName(){
// delegate to org node
return node.getName();
}
List getChildren(){
if(node.getChildren() == null){
return service.getChildrenNodes(node.getId());
}
return node.getChildren();
}
...
}
Attention, the tree binding fetch alway the actual selected node and all nodes of his children nodes to know which rendering mode to use (icon, link ...)
Example code:
class MyNode implements Node {
...
int getId() {...}
String getName() {...}
List getChildren(){...}
...
}
class ProxyNode implements Node {
Node node = null;
Service service = null;
ProxyNode(Service service, Node node) {
this.node = node;
this.service = service;
}
String getName(){
// delegate to org node
return node.getName();
}
List getChildren(){
if(node.getChildren() == null){
return service.getChildrenNodes(node.getId());
}
return node.getChildren();
}
...
}
Attention, the tree binding fetch alway the actual selected node and all nodes of his children nodes to know which rendering mode to use (icon, link ...)
Mittwoch, September 08, 2004
J2EE Web Authentication in conjunction with BC4J and JDBC Proxy Authentication
Proxy Authentication is designd to address connection performance problems associated with three-tier. Specifically, it allows to designate an already opend connection from a pool to a specific user with his privileges without logout and login each time.
BC4J-Framwork use the Strategie Pattern to customize the login and connection process. With JDeveloper 10g there is an default Implementation to use the feature. There are only tow single steps to use this feature in conjunction with J2EE login:
String DEFAULT_PWD = "myDefaultPwd123";
HttpContainer c = HttpContainer.getInstanceFromSession(session); c.setSessionCookie("myRootAppModule",null); // More informations about getInstanceFromSession
MyEnvInfoProvider.session.setAttribute(Configuration.DB_USERNAME_PROPERTY, request.getRemoteUser());
This Example works also with an x.509 certificate: see
Example of complete Connection Strategy for BC4J
More infos about proxy authentication
BC4J-Framwork use the Strategie Pattern to customize the login and connection process. With JDeveloper 10g there is an default Implementation to use the feature. There are only tow single steps to use this feature in conjunction with J2EE login:
- Set Connection Factory property jbo.ampool.sessioncookiefactoryclass to oracle.jbo.http.OCISessionCookieFactory in bx4j.xcfg (use the connfiguration dialog for the root Application module)
- or set follow Java option: -Djbo.ampool.sessioncookiefactoryclass=oracle.jbo.http.OCISessionCookieFactory
- Create a J2EE Login Page (Example in usage of OC4J)
- After successfull login you should call any methode to set the new user
String DEFAULT_PWD = "myDefaultPwd123";
HttpContainer c = HttpContainer.getInstanceFromSession(session); c.setSessionCookie("myRootAppModule",null); // More informations about getInstanceFromSession
MyEnvInfoProvider.session.setAttribute(Configuration.DB_USERNAME_PROPERTY, request.getRemoteUser());
This Example works also with an x.509 certificate: see
Example of complete Connection Strategy for BC4J
More infos about proxy authentication
Freitag, September 03, 2004
ADF POJO Binding
I was wondering why the native POJO binding doesn't allow creation of new objects (insert). After a look I found out there is not creation supported in the default DataControl implementation class (DCGenericDataControl) of POJO. To suppot the insert operation you must create and register your own DataControl in the DataBinding.cpx file and overwrite the createRowData(DCRowContext) method. To implement the method you can use the TopLink example found under: ../jdev/BC4J/scrc/adfmsrc.zip/oracle.adf.model/generic/toplink/TopLinkDataControl.java
Afterward you must also overwrite the isOperationSupported(...) in your DataControl to enable the MenuBar buttons (check byte parameter with DCDataControl static DCDataControl.OPER_DATA_ROW... ).
Ist not allowed to use only the new operator and insert the bean into the collection!!!
The same requirement exist for the DeleteOperation. You must also overwrite the removeRowData() Methode as above described.
A BUG in the ADF code prevent JClient to refershe automaticly the iterators and show the new data. You can fix it for your own: Unpack ../jdev/BC4J/scrc/adfmsrc.zip and uncomment the if(!containsRow(row)) in the methode insertRow(Row) and insertRowAtRangeIndex(int, Row) of oracle/adf/model/generic/DCRowSetIteratorImpl.java
Afterward you must also overwrite the isOperationSupported(...) in your DataControl to enable the MenuBar buttons (check byte parameter with DCDataControl static DCDataControl.OPER_DATA_ROW... ).
Ist not allowed to use only the new operator and insert the bean into the collection!!!
The same requirement exist for the DeleteOperation. You must also overwrite the removeRowData() Methode as above described.
A BUG in the ADF code prevent JClient to refershe automaticly the iterators and show the new data. You can fix it for your own: Unpack ../jdev/BC4J/scrc/adfmsrc.zip and uncomment the if(!containsRow(row)) in the methode insertRow(Row) and insertRowAtRangeIndex(int, Row) of oracle/adf/model/generic/DCRowSetIteratorImpl.java
Donnerstag, August 19, 2004
JSF Facet contra UIX Named Children
JSF introduce facet (<f:facet name="header">) tag to address elements inside a parent tag and have control over it. This is a anti pattern for general XML developer and very badly to handle with other specs. as XMLSchema.
Old UIX implementation use for that a more common XML syntax (<f:heander>) and name this named children . Index children are the opposite and used to arrange each elements in a sequence For this UIX (old impl.) use the ((<contents>). Tag. Unfortunately Oracle UIX / JSF implementation must also use the new facet syntay to be spec compliant.
Old UIX implementation use for that a more common XML syntax (<f:heander>) and name this named children . Index children are the opposite and used to arrange each elements in a sequence For this UIX (old impl.) use the ((<contents>). Tag. Unfortunately Oracle UIX / JSF implementation must also use the new facet syntay to be spec compliant.
UIX as JSF Beta Available
Now Oracles UIX technology has been converted to the new JSF API. Here you will find the Early Access Release. I am very happy to found most old features in JSF implementation.
In the past it was very hard to persuade developer to use UIX even though the UIX architetrue is very similar. Now with the magic word JSF it's very easy :-)
In the past it was very hard to persuade developer to use UIX even though the UIX architetrue is very similar. Now with the magic word JSF it's very easy :-)
Freitag, Juli 23, 2004
Configure JVM for OC4J
When you update the JVM of OC4J you must also change following security parameters in the java.security file to prevent a java.lang.SecurityException:
- auth.policy.provider=oracle.security.jazn.spi.PolicyProvider
- login.configuration.provider=oracle.security.jazn.spi.LoginConfigProvider
Dienstag, Juli 06, 2004
Support of Oracle Application Server Load Balancing Strategies
mod_oc4j Load Balancing support follow routing strategies:
Random
route the request to next JVM in a cluster in usage of the randomm algorithm.
Random with local affinity
route the request to next JVM on the local machine in usage of the random algorithm, if none available
it reroute to the next remote JVM also in usage of the ramdom algorithm.
Random with routing weight
route each request randomly to all available JVM in a cluster depending of the
configured routing resource weight. A high value (integer) means more resources available.
Round robin
choose for each request the next JVM in a cluster.
Round robin with local affinity
prefer the for each request the next JVM on the locale mashine
other it will use the next remotely.
Round robin with routing weight
prefer the for each request the next JVM in a cluster depending of the
configured routing resource weight.
Metric based
choose the JVM based on OC4J metrics and his availability.
Metric based with local affinity
first choose the JVM based on locale OC4J metrics and his availability otherwise it will choose the JVM remotely.
See also ...
Random
route the request to next JVM in a cluster in usage of the randomm algorithm.
Random with local affinity
route the request to next JVM on the local machine in usage of the random algorithm, if none available
it reroute to the next remote JVM also in usage of the ramdom algorithm.
Random with routing weight
route each request randomly to all available JVM in a cluster depending of the
configured routing resource weight. A high value (integer) means more resources available.
Round robin
choose for each request the next JVM in a cluster.
Round robin with local affinity
prefer the for each request the next JVM on the locale mashine
other it will use the next remotely.
Round robin with routing weight
prefer the for each request the next JVM in a cluster depending of the
configured routing resource weight.
Metric based
choose the JVM based on OC4J metrics and his availability.
Metric based with local affinity
first choose the JVM based on locale OC4J metrics and his availability otherwise it will choose the JVM remotely.
See also ...
Montag, Juli 05, 2004
HTTP-Connection test with telnet
recently I get the question how to test a HTTP Server connection without any browser (eg. on a server without any X-Server). The simplest way is to connect the HTTP Server with the telnet programm and request the resource with HTTP commands:
Here an example:
Open the connetion with the http listener port:
telnet www.oracle.com 80
Requet the resource /index.htm with GET methode and protocol HTTP/1.1:
GET /index.htm HTTP/1.1
This will get the complete html content of the index.html page
or
HEAD /pages/test.jsp HTTP/1.1
to get informations about the resource
See also ....
Here an example:
Open the connetion with the http listener port:
telnet www.oracle.com 80
Requet the resource /index.htm with GET methode and protocol HTTP/1.1:
GET /index.htm HTTP/1.1
This will get the complete html content of the index.html page
or
HEAD /pages/test.jsp HTTP/1.1
to get informations about the resource
See also ....
Sonntag, Juli 04, 2004
UIX: Build Context Relative Links
to build a resource URL including the context path you can use the ui:contextURI methode directly in your UIX-Page as follow:
<flowLayout>
<contents childData="${fileList.file} >
<link text="${uix.current.text}">
<boundAttribute name="destination">
<concat>
<contextProperty select="ui:contextURI"/>
<fixed text="/"/>
<ui:dataObject source="${uix.current.source}"/>
</concat>
</boundAttribute>
</link>
</contents>
</flowLayout>
<flowLayout>
<contents childData="${fileList.file} >
<link text="${uix.current.text}">
<boundAttribute name="destination">
<concat>
<contextProperty select="ui:contextURI"/>
<fixed text="/"/>
<ui:dataObject source="${uix.current.source}"/>
</concat>
</boundAttribute>
</link>
</contents>
</flowLayout>
Donnerstag, Juli 01, 2004
EJB Lookup within Oracle Appliaction Server in usage of Clustering, Scalability and Fault-Tolerance
There is a main different between OC4J-Standalone EJB addressing schema and OC4J integrated in the Oracle Application Server. Think, Oracle Application Server has additional features regarding Clustering, Scalability and Fault-Tolerance, witch must be carefully attended in the deployment and EJB calling phase.
E.g. for scalability you can instance more then one OC4J components with the same configuration (many OC4J processes). In this case you must configure (default) a RMI port range in the opmn.xml. So OPMN (Oracle Process Monitor) is able to assign a different port to each OC4J instance in the startup phase.
A other feature of Oracle Application Server is to load balance the EJB calls depending of many different implemented algorithm (eg. round robin, metric based, ...). In each of this cases you can not address an OC4J instance directly like this:
env.put(Context.PROVIDER_URL, "ormi://HOST:PORT/EjbAppName")
In this situation you should us the following addressing schema:
env.put(Context.PROVIDER_URL, "opmn:ormi://HOST:OPMNPORT:OC4JInstanceName/EjbAppName");
Notice: for application portability, Oracle recommends to use jndi.properties instead of hardcoding the environment properties in client code.
You will find more information regarding OC4J and EJB in the OC4J Service Guide and in the OC4J-FAQ on OTN
regards
Berthold
E.g. for scalability you can instance more then one OC4J components with the same configuration (many OC4J processes). In this case you must configure (default) a RMI port range in the opmn.xml. So OPMN (Oracle Process Monitor) is able to assign a different port to each OC4J instance in the startup phase.
A other feature of Oracle Application Server is to load balance the EJB calls depending of many different implemented algorithm (eg. round robin, metric based, ...). In each of this cases you can not address an OC4J instance directly like this:
env.put(Context.PROVIDER_URL, "ormi://HOST:PORT/EjbAppName")
In this situation you should us the following addressing schema:
env.put(Context.PROVIDER_URL, "opmn:ormi://HOST:OPMNPORT:OC4JInstanceName/EjbAppName");
Notice: for application portability, Oracle recommends to use jndi.properties instead of hardcoding the environment properties in client code.
You will find more information regarding OC4J and EJB in the OC4J Service Guide and in the OC4J-FAQ on OTN
regards
Berthold
Freitag, Juni 25, 2004
OC4J Remote deployment with dcmctl Commands
I get often the question how to deploy a J2EE App. remotely to IAS. Here are two examples to that:
java.exe -Djava.protocol.handler.pkgs=HTTPClient -jar d:\jdev9052\jdev\lib\oc4j_remote_deploy.jar http://192.33.33.12:1811/Oc4jDcmServletAPI/ ias_admin PASSWORD redeploy F:\ora10g\midtier F:\test\deploy\helloOracle.ear helloOracle home
parameter's:
Protocol: -Djava.protocol.handler.pkgs=HTTPClient
Deploy Utility: eg. d:\jdev9052\jdev\lib\oc4j_remote_deploy.jar
MidtierDeployServlet incl. EM port: http://192.33.33.12:1811/Oc4jDcmServletAPI/
IAS-Username: ias_admin
Password: PASSWORD
Option eg: redeploy, listApplications ... (any dcmctl option is possible"
Midtier ORACLE_HOME Directory: eg.
F:\ora10g\midtier
EAR-File: F:\test\deploy\helloOracle.ear
AppName eg: helloOracle
InstanceName: home
or use the following ANT-Task:
<
<java jar="${jdeveloper.dir}/jdev/lib/oc4j_remote_deploy.jar" fork="yes">
<jvmarg value="-Djava.protocol.handler.pkgs=HTTPClient" />
<arg value="http://remote_server:1810/Oc4jDcmServletAPI/" />
<arg value="ias_admin" />
<arg value="PASSWORD" />
<arg value="redeploy" />
<arg value="${ias_oracle_home.dir}/" />
<arg value="${build.dir}/${name}.ear" />
<arg value="${appname}" />
<arg value="OC4J_XXXXINSTANCEName" />
</java>
Here an other example to query DCM with the listApplications paramter:
F:\jdev9051\jdk\jre\bin\javaw.exe -Djava.protocol.handler.pkgs=HTTPClient -jar F:\jdev9051\jdev\lib\oc4j_remote_deploy.jar http://testhost:1811/Oc4jDcmServletAPI/ ias_admin **** listApplications D:\ora10g\midtier
All commands will interpreted form the Oracle Application Server Servlet deployed in the home OC4J instance.
regards,
Berthold
java.exe -Djava.protocol.handler.pkgs=HTTPClient -jar d:\jdev9052\jdev\lib\oc4j_remote_deploy.jar http://192.33.33.12:1811/Oc4jDcmServletAPI/ ias_admin PASSWORD redeploy F:\ora10g\midtier F:\test\deploy\helloOracle.ear helloOracle home
parameter's:
Protocol: -Djava.protocol.handler.pkgs=HTTPClient
Deploy Utility: eg. d:\jdev9052\jdev\lib\oc4j_remote_deploy.jar
MidtierDeployServlet incl. EM port: http://192.33.33.12:1811/Oc4jDcmServletAPI/
IAS-Username: ias_admin
Password: PASSWORD
Option eg: redeploy, listApplications ... (any dcmctl option is possible"
Midtier ORACLE_HOME Directory: eg.
F:\ora10g\midtier
EAR-File: F:\test\deploy\helloOracle.ear
AppName eg: helloOracle
InstanceName: home
or use the following ANT-Task:
<
<java jar="${jdeveloper.dir}/jdev/lib/oc4j_remote_deploy.jar" fork="yes">
<jvmarg value="-Djava.protocol.handler.pkgs=HTTPClient" />
<arg value="http://remote_server:1810/Oc4jDcmServletAPI/" />
<arg value="ias_admin" />
<arg value="PASSWORD" />
<arg value="redeploy" />
<arg value="${ias_oracle_home.dir}/" />
<arg value="${build.dir}/${name}.ear" />
<arg value="${appname}" />
<arg value="OC4J_XXXXINSTANCEName" />
</java>
Here an other example to query DCM with the listApplications paramter:
F:\jdev9051\jdk\jre\bin\javaw.exe -Djava.protocol.handler.pkgs=HTTPClient -jar F:\jdev9051\jdev\lib\oc4j_remote_deploy.jar http://testhost:1811/Oc4jDcmServletAPI/ ias_admin **** listApplications D:\ora10g\midtier
All commands will interpreted form the Oracle Application Server Servlet deployed in the home OC4J instance.
regards,
Berthold
Donnerstag, Juni 03, 2004
UIX and Struts
UIX in conjunction with the Struts extention (not ADF-DataBinding) can not automaticly populate form fields of a UIX-Table (editable UIX-Table or selectionKey of the table component) to ActionForms with Array-Argumens like setFirstName(String[]). The problem lies in the naming schema of cascaded components. To identify each column with an unique name, UIX concat the name of each column element with the table name and the column sign ':'. So, an editable column get the name like myTable:firstName. With this extention Struts can't find the right setter method in the ActionFormBean. This limitation needs to overwrite the form struts population mechanism to solve the problem.
To do that you must overwrite the processPopulate methode of the org.apache.struts.action.RequestProcessor.java
Additional you must register your new RequestProcessor within the struts-config.xml like this:
When you use table selection moded, UIX add the keyword "Selected" and the row index to the tableName (myTable:Selected:1, myTable:Selected:2 usw.). This behavior must also be handled in your own population methode to get an array of selected rows.
To do that you must overwrite the processPopulate methode of the org.apache.struts.action.RequestProcessor.java
}
protected void processPopulate(HttpServletRequest request,
HttpServletResponse response,
ActionForm form,
ActionMapping mapping)
throws ServletException {
super.processPopulate(request, response, form, mapping);
String contentType = request.getContentType();
if ((contentType != null && contentType.startsWith("multipart")) || (form == null)) {
return;
}
UixStrutsFormPopulateUtil.populate(form, request);
Additional you must register your new RequestProcessor within the struts-config.xml like this:
When you use table selection moded, UIX add the keyword "Selected" and the row index to the tableName (myTable:Selected:1, myTable:Selected:2 usw.). This behavior must also be handled in your own population methode to get an array of selected rows.
Montag, Mai 31, 2004
JMX Console for OC4J
I am pleased to found a very nice Open Sorces JMX Console (MC4J - http://mc4j.sourceforge.net) to administer and introspect each JMX Server like OC4J.