miercuri, 22 aprilie 2009

Richfaces panelMenu

Richfaces is a JSF framework extremely powerful. It offers lots of ajax enabled components. In this post I will show how to create a left side navigation bar.

Step 1: We create an eclipse Dynamic Web Project with version 2.5. We activate JSF 1.2. We also have to configure Richfaces as described in: http://www.jboss.org/file-access/default/members/jbossrichfaces/freezone/docs/devguide/en/html_single/index.html.

Step 2: We create a .jsp file in the previously created project with the following code:

<%@page pageEncoding="UTF8" contentType="text/html; charset=ISO-8859-2" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://richfaces.org/a4j" prefix="a4j" %>
<%@ taglib uri="http://richfaces.org/rich" prefix="rich" %>

<f:view>
<h:form>

<rich:panelmenu event="onclick" mode="ajax" width="300">
<rich:panelmenugroup label="Meniu test">
<rich:panelmenuitem label="Optiune 1" onclick="window.location.href='test.jsf';">
<rich:panelmenuitem label="Optiune 2" onclick="window.location.href='test.jsf';">
<rich:panelmenuitem label="Optiune 3" onclick="window.location.href='test.jsf';">
</rich:panelMenuGroup>
</rich:panelMenu>

</h:form>
</f:view>

Comments:

In this moment, we have a navigation bar without any action implemented. In most common cases we'll have to redirect to another page when clicking an item. We can achieve this in many ways, but I think the easiest one is to use javascript code and onclick attribute. We also have to explain what event="onclick" and mode="ajax" means.
Onclick tells richfaces to generate a floating menu which folds/unfolds when an item is clicked. Another value could be onmouseover. The second attribute, mode, defines the submit mode. The default value for this attribute is server, which means that everytime an item is clicked, the page is reloaded. We can also bind panelMenuXXX(XXX stands for: {"" | Item | Group}), to a java object. Data type for attribute is HtmlPanelMenuXXX(XXX stands for: {"" | Item | Group}). The package for this data type is org.richfaces.component.html. Most components that you will use are defined in this package.

joi, 16 aprilie 2009

Configuring subversion + apache2 + ldap

In this post, I describe how I can create subversion repositories authentication using mod_dav_svn and ldap. I suppose we have a virtual path created for out repo: /svn/repos/repo_virtual

We need to have the following structure for ldap nodes:

dc=example,dc=com
ou=Groups,dc=example,dc=com
cn=group_svn_repo,ou=Groups,dc=example,dc=com
ou=Users,dc=example,dc=com
cn=user1,ou=Users,dc=example,dc=com
cn=user2,ou=Users,dc=example,dc=com


Normally the below mentioned structure is enough for configuring apache. In short, we authenticate users on Users node. After that, we check that the user belongs to a specified group. We also need to configure a virtual host for apache(this is the most common scenario used) .

ServerName svn1.example.com
ServerAdmin rcosnita@example.com
ErrorLog /var/log/apache2/error_svn.log
CustomLog /var/log/apache2/access_svn.log combined


DAV svn
SVNPath /svn/repos/repo_virtual/
SVNListParentPath on

AuthBasicProvider ldap

AuthType Basic
AuthName "Example server"
AuthzLDAPAuthoritative off

AuthLDAPURL ldap://svn1.example.com:389/OU=Users,DC=informatix,DC=ro?cn?sub
AuthLDAPBindDN CN=root,DC=example,DC=com
AuthLDAPBindPassword parolamea

AuthLDAPGroupAttribute member
AuthLDAPGroupAttributeIsDN on

Require group cn=group_svn_repo,ou=Groups,dc=informatix,dc=ro


This should do the trick. After you finish configuring the vhost you need to restart apache web server.

It's important to keep in mind that apache webserver cache the connection with ldap server(after first connection). This mean that every entry you add after apache make its first connection won't be "seen" by apache till the next restart(of apache or ldap server).

I don't really know why the solution from this post didn't work with apache + openldap. So if you use openldap you have to cheat a little. You add an attribute to every user from ldap existing schema in which we mention the ldap group. In my case, I have used labeledURI. When I finished adding the above mentioned attribute, I have modified the vhost as:

"Require group cn=group_svn_repo,ou=Groups,dc=informatix,dc=ro"
is replaced by
"Require ldap-attribute labeledURI=cn=group_svn_repo,ou=Groups,dc=informatix,dc=ro".


After this, everything worked just fine.

Oracle and Java Stored Procedure

Starting with Oracle 8i, Oracle RDBMS server has a Java Virtual Machine integrated in it. This means that it can run stored procedures/programs written in java directly in the database. This has huge benefits for PL/SQL language. We can easily add new functionalities in Oracle. In the following paragraphs I'll create a simple class which has a method with one parameter of type java.lang.String. This method will be used as an Oracle stored procedure.

I suppose you use eclipse IDE. Create a Java project. Add a library reference for ojdbc14.jar(this is oracle jdbc driver). Now, we can start writting the class.

Step 1:

package ro.teste.sp;

public class TesteSP
{
public static void WriteMessage(String msg) throws SQLException
{
Connection con = DriverManager.getConnection("jdbc:default:connection");

System.out.println("We received from PL/SQL: " + msg);
}
}

Step 2:

loadjava -user user/passwd@db TesteSP.java

Step 3:

Se creaza un wrapper in baza de date.

We create a wrapper procedure in PL/SQL. We do this so we can invoke the previous java stored procedure natively.

CREATE OR REPLACE PROCEDURE WrapJava1(msg VARCHAR2)
AS
LANGUAGE java
NAME 'ro.teste.sp.TesteSP.WriteMessage(java.lang.String)';

Step 4:

CALL WrapJava1('Hello world');

Comments:

This example is extremely simple. You can create very complicated java stored procedure. For instance, I have managed to write a stored procedure that was generating a jpg image base on received parameters. I have also written a stored procedure to get latest currency from a specified web service. The list of examples can continue indefinitely. I hope you can find this feature of Oracle useful.

joi, 9 aprilie 2009

Oracle forms and Java Bean

In this post I will show how a java component can be plugged in to an Oracle Form. The main problem in achieving this, it's Oracle poor reference for the framework that allows this kind of integration. All you can do it's search the internet and look for as many articles as possible. In the following article I'll create a simple JavaBean component which will send a string to Oracle Forms.

Pasul 1 este sa adaugati o referinta catre frmall.jar care se gaseste in locul in care ati instala Oracle Developer Suite/forms/java.

Step 1: you have to add frmall.jar library reference to your classpath. You can find this library in $ORACLE_HOME/forms/java(in case you installed only Oracle Developer Home) or in $DevSuiteHome_x/forms/java(in case you have installed the Oracle DB and Oracle Developer Suite).

Step 2: You have to compile the following class:

package ro.javabeans;

import oracle.forms.handler.IHandler;
import oracle.forms.properties.ID;
import oracle.forms.ui.CustomEvent;
import oracle.forms.ui.VBean;

public class HelloWorld extends VBean
{
private static IHandler myHandler;
protected static final ID MESAJ = ID.registerProperty("MESAJ");
private String msg;
public void setMsg(String s)
{
this.msg = s;
}
public String getMsg()
{
return this.msg;
}

public void init(IHandler handler)
{
myHandler = handler;
super.init(handler);
}

public boolean setProperty(ID property, Object value)
{
if(property == MESAJ)
{
this.setMsg((String)value);
return true;
}

return super.setProperty(property, value);
}

public Object getProperty(ID property)
{
if(property == MESAJ)
return this.getMsg();

return super.getProperty(property);
}

public void dispatchEvent(ID id)
{
CustomEvent ce = new CustomEvent(myHandler, id);
dispatchCustomEvent(ce);
}
}

Comments:
I think I have to explain the code a little. First of all, every JavaBean which has to run in Oracle Forms has to subclass VBean. We set myHandler, because this object give us methods to access Oracle Forms environment.

protected static final ID MESAJ = ID.registerProperty("MESAJ"). This line register a bean property which can be used in PL/SQL code using set_custom_property/get_custom_property functions. The name of the property is case sensitive, so I recommend you use just capital letters or lower letters(it's up to you).

setProperty/getProperty method are callback functions invoked by the framework to return a property or set a property from Oracle Forms.

dispatchEvent method is used to implement custom events that can be raised/received from Oracle Forms.

Step 4: exporting the project to a jar archive in $DevsuiteHome/forms/java.

Step 5: You need to modify under DevsuiteHome/forms/server/formsweb.cfg, entry archive=....,exported_project.jar

Step 6: We create a new form and we add a JavaBean item. We change its implementation class property to ro.javabeans.HelloWorld

Step 7: We add a when-new-form-instance trigger with the following code:

declare
msg VARCHAR2(200) := 'Va pup pe toti';
begin
SET_CUSTOM_PROPERTY('BLOCK3.BEAN4', 1, 'MESAJ', 'SALUTARI');
end;

Comments:

I assume that JavaBean item it's located unde BLOCK3 and it's named BEAN4. SET_CUSTOM_ATTRIBUTE is a builtin used to set attributes for a bean.

Step 8: We add a button on the canvas.

Step 9:
We add trigger when-mouse-click, with the following code:

declare
msg VARCHAR2(2000) := GET_CUSTOM_PROPERTY('BLOCK3.BEAN4', 1, 'MESAJ');
begin
MESSAGE(msg);
end;

Step 10: We ran the application as a normal Oracle Forms application.

That's all. It's easier than it looks like. I hope this post helped you in your work.

marți, 7 aprilie 2009

Oracle and functions which return a resultset

I knew it was possible to do this. But what I want in fact is to use that function in a select clause. Almost all examples found on Internet explain how to return a result set from a function using SYS_REFCURSOR. In that manner you won't be able to use select statements on the resultset. In addition, problems appear when you want to create a report base on a certain stored function/procedure. Fo instance, I have tried using Crystal Reports for Java with a stored procedure which returns a resultset. Instead of getting the dataset, Crystal Reports returned an error complaining about the stored procedure.

The alternative would to use a select statement in crystal reports which hides my stored function/procedure. To achieve this, I will use pipelined functions.

Step 1:

create or replace type tp_Person is object(SN NUMBER,
FirstName VARCHAR2(200),
LastName VARCHAR2(200));

Step 2:

create or replace type tp_TblPersons is table of tp_person index by binary_integer;

Step 3:

create or replace function fc_TestPersons return tp_tblpersons pipelined
as
cursor c is select * from persons;
rec tp_Person;
begin
OPEN c;

rec := tp_Person(null, null, null);

LOOP
FETCH c INTO rec.sn, rec.firstname, rec.lastname;
exit when c%notfound;

pipe row(rec);
END LOOP;

CLOSE c;
return;
end fc_TestPersons;

Step 4:

In the end all you have to do is to write a select statement like the following one:

SELECT * FROM table(fc_TestPersons());

Final words:

This feature of Oracle PL/SQL language is extremely useful. You must use it when you are sure there are no others options. It uses oracle buffers and memory, so intense use of it might result in low performance.

Hibernate and Composite Keys

Hibernate is a powerful ORM(object relational mapping) very populat nowadays. In latest version, Hibernate comes with Hibernate Annotations. Using annotations you can avoid writting addition xml files for object mapping. In Java, we use hibernate for moving relational model to objective model.Above diagram descibe the following situation: we have several webhosting packages and several tehnology. Between them, we have a many-to-many relation. It's obvious in the database we have a composite primary key: (pachet,tehnologie). Below I write the code for describing the relation from image in terms of hibernate.

@Entity
@Table(name="tblpachete")
public class PachetGazduire
{
@Id
private int id;

@OneToMany(fetch=FetchType.EAGER, mappedBy="id.pachet")
private ArrayList tehnologii;

/* here we add other properties/methods */
}


@Entity
@Table(name="tbltehnologii")
public class Tehnologie
{
@Id
private int id;

/* here comes getter/setter */
}



/* This class implements the composite key */
@Embeddable
public class TehnologiiPachetPK
{
@ManyToOne
@JoinColumn(name="fk_pachet", referencedColumnName="id")
private PachetGazduire pachet;


@ManyToOne
@JoinColumn(name="fk_tehnologie", referencedColumnName="id")
private Tehnologie tehnologie;

/* here come other methods/properties */
}



@Entity
@Table(name="tbltehnologiipachet")
public class TehnologiiPachet
{
@Id
private TehnologiiPachetPK id;

int laCerere;
int nrConturi;
int pretLaCerere;

/* here comes other methods/properties */
}

You might test this code by generating getter/setter methods for every class. You also have to create the underlying tables. One simple solution it's to let hibernate create them for you: hibernate.hbm2ddl.auto = true(in hibernate.cfg.xml)

After you create the tables you populate them with data and everything should be just fine. Good luck.

Accesing web services from Oracle

This problem represent a tough challenge even in modern programming languages(Java, C#) if you don't have a stub generator based on wsdl. I must say that Oracle 10g2 has a nice feature implemented in utl_dbws. This PL/SQL package has lots of function which allow programmer to use web services without using any java wrapper class. Unfortunately, this package is not very well documented by Oracle(it's not the only package in this situation). When I had to write a PL/SQL package which create a SOAP request for a web service and returns the result I spent many hours on google. Enough talking.

In the first part of this tutorial, I create a web service using J2EE tehnology(it's very easy).

ro.anaf.ws.HelloWorldWS

package ro.anaf.ws;

import javax.ejb.Remote;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style = Style.RPC)
@Remote
public interface HelloWorldWS
{
@WebMethod
public String helloWorld();

@WebMethod
public String receiveBinary(String s);
}



package ro.anaf.ws;

import javax.ejb.Stateless;
import javax.jws.WebService;

@Stateless
@WebService(endpointInterface = "ro.anaf.ws.HelloWorldWS")
public class HelloWorldWSBean implements HelloWorldWS
{
public String helloWorld()
{
return Hello fromWS";
}

public String receiveBinary(String s)
{
return "I have your message: \"" + s + "\"";
}
}


Now, you deploy your webservice on JBoss/Weblogic or whatever J2EE container you like. After this, we describe the Oracle stuff.

You have to download dbws-callout-utility-10131.zip. After this, you have to load the package into Oracle database.

# 10gR2
loadjava -u scott/tiger -r -v -f -genmissing dbwsclientws.jar dbwsclientdb102.jar
# 11g
loadjava -u scott/tiger -r -v -f -genmissing dbwsclientws.jar

If you don't have Oracle Developer Suite, then it's very probable that you won't be
able to run loadjava. We will suppose that you have Oracle Developer Suite and everything worked fine till now.

declare
webservice utl_dbws.service;
webserviceCall utl_dbws.call;

wsdlURL VARCHAR2(1000) := 'http://10.18.14.32:8080/TestareServiciiEAR-ServiciiWeb/HelloWorldWSBean?wsdl';
webserviceNS VARCHAR2(1000) := 'http://ws.anaf.ro/';
webserviceName utl_dbws.qname;
webservicePort utl_dbws.qname;
webserviceOperation utl_dbws.qname;
params utl_dbws.anydata_list;
results anydata;
begin
webserviceName := utl_dbws.to_qname(webserviceNS, 'HelloWorldWSBeanService');
webservicePort := utl_dbws.to_qname(webserviceNS, 'HelloWorldWSBeanPort');
webserviceOperation := utl_dbws.to_qname(webserviceNS, 'helloWorld');

webservice := utl_dbws.create_service(wsdl_document_location => HTTPURITYPE(wsdlURL),
service_name => webservicename);

webserviceCall := utl_dbws.create_call(service_handle => webservice,
port_name => webservicePort,

operation_name => webserviceOperation);

results := utl_dbws.invoke(call_handle => webserviceCall, input_params => params);

utl_dbws.release_service(webservice);
utl_dbws.release_call(webserviceCall);

DBMS_OUTPUT.PUT_LINE(ANYDATA.AccessVarchar2(results));
end;


Above script shows an example of how you can access the webservice you have created in the first part of this tutorial.
Before the end, you have to know that in some cases you'll want to pass certain parameters to the webservice. In these cases
params(0):=ANYDATA.ConvertVarchar2('Cosnita Radu Viorel'); and of course you can add other parameters.