vineri, 31 iulie 2009

JSF Localization

Localizations is the process through which an application(web or desktop) can present its' content in multiple languages. This is a hot subject nowadays and a standard is not yet defined for how to properly implement localization. In Java/JSF we can use ResourceBundle class from java.util. A simple example is shown below.

1. We create two resource files(english and romanian).
In each of them we add lbWelcome key with english(romanian) text.

2. We modify faces-config.xml for indicating the supported languages.

<application>
<locale-config>
<default-locale>ro< /default-locale>
<supported-locale>ro< /supported-locale>
<supported-locale>en< /supported-locale>
</ locale-config>
</application>

3. We create a jsp page for presenting the content.

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

<f:view>


<h:form>
<h:commandLink action="#{languageBean.changeLanguage}" value="Romana">
<f:param name="lang" value="ro">
</h:commandLink>
|
<h:commandLink action="#{languageBean.changeLanguage}" value="English">
<f:param name="lang" value="en">
</h:commandLink><>

<h:outputText value="#{msg.lbWelcome}">
</h:form>
</f:view>

4. We create a backbean in which the method for changing the language is implemented


package ro.testlocalization.traduceri;

import java.util.Locale;
import java.util.Map;

import javax.faces.application.Application;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;

public class LanguageBean {
public void changeLanguage() {
Map req = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap();
String lang = req.get("lang").toString();

Locale newLocale = new Locale(lang);
FacesContext context = FacesContext.getCurrentInstance();
context.getViewRoot().setLocale(newLocale);
}
}

5. We map the backbean in faces-config.xml.

miercuri, 29 iulie 2009

JAX-WS Webservices: Part 2

This post continues previous one for offering new information about jax-ws webservices. One issue which is often met is related to return types of the web service. For instance: We implement an EJB component which models a person. How can I return this? I might try to specify for one of the webservice methods the EJB as a return type. This is so wrong. The EJB might have a collection resulting from a OneToMany relation. When the client will try to access an element of this collections an exception will be raised complaining about "session closed". To avoid this, we implement a new class(wrapper) which will be serializable. We make sure we don't use Java Collection types like Set, List, Hash, ..... We'll use arrays instead([]). In the web service method we populate all attributes of the wrapper class. The following example demonstrates this:

@Entity
public class Persoana {
@Id
private long cnp;

@OneToMany(mappedBy="parinte")
private List rude;


//metode getter/setter
}


public class PersoanaWrapper implements Serializable {
private long cnp;

private PersoanaWrapper[] rude;

//metode getter/setter
}


Metoda din webservice care doreste sa returneze o persoana ar putea fi implementat de maniera urmatoare:

public PersoanaWrapper getPersoana(long cnp) {
//cod prin care incarc ejb-ul persoanei dorite. => Persoana persEJB;
PersoanaWrapper pers = new PersoanaWrapper();
int nrRude = persEJB.getRude().size();

pers.setCNP(persEJB.getCNP());
pers.setRude(new PersoanaWrapper[nrRude]);

for(int i = 0; i < nrRude; i++) {
PersoanaWrapper tmp = new PersoanaWrapper();
tmp.setCNP(persEJB.getRude().get(i).getCNP());
pers.getRude()[i] = tmp;
}

return pers;
}

One enhancement of the example is to add a new method/constructor which accepts an argument with the EJB type. Using wrapper classes you cand return whatever custom data type you want.
I mentioned in a previous post that when deploying a java web service in a container it will be exposed as a web service and as a Session bean. I strongly encourage you to invoke it as a web service or as a Session bean(not both). If you intend to make your application interoperable then use just web services.

How can we inject resources in a web service?

It is common to use resources in a web service. For instance, we might need to use a DataSource from the container. We might want to inject an EntityManager in the webservice. Both situation are easily solved in Java EE:

@PersistenContext(unitName="myPersistence")
private EntityManager em;

@Resource(mappedName="java:jdbc/MyDS")
private DataSource ds;

We can use @Resource annotation to inject various resources like:
  • Mail session
  • Custom data sources
  • Other resources

luni, 27 iulie 2009

JAX-WS Webservices

In one of the recent projects I worked on I was supposed to implement a SOA arhitectue. The business logic was exposed through web services. This solution was developed because one of its components was written in C# and the rest of components were written in Java. The chosen container for the business layer was JBoss 5(web services, ejb) and Tomcat 6 for front-end(web application). The first major issue was raised by the JBoss 5 version downloaded from the jboss.org site.

Obs: !!!!!!!!!If you use jre/jdk 6 download the jboss version compiled with jdk 6. Otherwise you will get weird errors when you try to access the webservice.

I assume that you downloaded the correct version of jboss on your computer. Java EE/jax-ws makes webservices creation a formality.

@WebService
@SOAPBinding(style=Style.RPC)
@Stateless
public interface ServiciuTest {
@WebMethod
public String sayHello(@WebParameter(name="message")String msg);
}

@Stateless
@WebService(endpointInterface="ServiciuTest")
public class ServiciuTestBean {
public String sayHello(String msg) {
return msg;
}
}

This is all you have to do for creating a functional web service. In this moment the webservice can be deployed on a container that supports jax-ws. In Java EE, the above mentioned class will be exposed as a web service and as a session bean. The interface described is an endpoint(spec) for the web service. The annotation used in the method declaration alter the way the wsdl file is generated. You must keep in mind that you won't be able to return classes which aren't serializable.

In the following paragraphs I present how a complex web service can be implemented. This web service downloads a file from server.

@WebService
@SOAPBinding(style=Style.RPC)
@Stateless
public interface ServiciuFilesTest {
@WebMethod
public byte[] getFile(@WebParam(name="file_name")String fName);
}

@Stateless
@WebService(endpointInterface="ServiciuFilesTest")
public class ServiciuFilesTestBean {
public byte[] getFile(String fName) {
   byte[] deRet = new byte[(int)(new File(fName)).length()];
try {
FileInputStream file = new FileInputStream(fName);
file.read(deRet);
file.close();
}
catch(IOException ioe) {
ioe.printStackTrace();
return null;
}
return deRet;
}
}

This is all you have to do. In this manner you can send files to a client through the web service. Usually, it is recommended that you encode the content sent using Base64.