Some thoughts on Java Platform
Header image

Interceptors (Interceptadores) são de grande utilidade em qualquer projeto JavaEE. Presente desde a versão EJB 3.0, eles permitem ao bean provider interceptar qualquer session bean, tanto antes quanto depois da sua execução. Pensando nisso, é possível usá-los de várias para diversos fins diferentes, podemos citar por exemplo: logging, tratamento de exceção, auditoria, métricas, etc.

É possível definir Interceptors de algumas maneiras diferentes, vamos citá-los:

  1. Default Interceptors – São definidos no ejb-jar xml e podem ser aplicados a todos session beans.
  2. Classe Interceptors – São definidos no topo da classe com a anotação @Interceptors
  3. Method Interceptors – São definidos no nível de métodos com a anotação @Interceptors
  4. Na própria classe – Presentes na própria classe do session bean

Um método do session bean pode ser interceptador por quantos interceptores existirem aplicados para aquele método, e a ordem da execução deles é aplicado seguindo : Default, Class, Method, própria classe. Caso haja mais de um interceptor para alguma categoria, a ordem foi a que foi declarada.

Para se criar um usa-se a anotação @AroundInvoke normalmente um Inteceptor possui a cara abaixo:


@AroundInvoke

public Object aroundInvoke(InvocationContext ic) throws Exception{

System.out.println("start");

Object obj = ic.proceed(); //o método do bean executa aqui

System.out.println("end");

return obj;

}

Um ponto importante a se observar é que o método deve lançar na assinatura Exception. Isso se deve pois session beans podem lançar exceções checadas, então não se sabe qual exceção vai vir de lá, logo declara-se a mais genérica. Um interceptor não pode lançar uma exceção checada que session bean não conheça.

Abaixo o session bean que é interceptado pelo Inteceptor acima:


public class CountryCodeBean implements CountryCodeBeanLocal {
 @Interceptors({InterceptorA.class})

@ExcludeClassInterceptors

@ExcludeDefaultInterceptors

public String getCode(String country){

System.out.println("In getCode");

return country+"_CODE";

}
 @AroundInvoke

public Object selfAround(InvocationContext ic) throws Exception{

System.out.println("In selfAround");

return ic.proceed();

}
}

 

Coisas a se conderar do código acima:

  • O método selfAround é um Inteceptor da própria session bean, e na ordem de execução ele sempre será o último dos interceptors (caso hajam outros).
  • @ExcludeClassInterceptors remove da execução os Inteceptors declarados no topo da classe
  • @ExcludeDefaultInterceptors remove os Interceptos declarados como default no ejb-jar

Abaixo um exemplo de como se declara um default-interceptor no ejb-jar:


<ejb-jarxmlns="http://java.sun.com/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaeehttp://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd"version="3.1">

<assembly-descriptor>

<interceptor-binding>

<ejb-name>*</ejb-name>

<interceptor-class>my.example.MyDefaultInterceptor</interceptor-class>

</interceptor-binding>

</assembly-descriptor>

</ejb-jar>

 

Outro aspecto importante que vale ressaltar, é que o Interceptor é sempre associado com a instância do Session Bean. Ou seja, se um Interceptor é associado com um statefull session bean, sua instância viverá enquanto a instância do statefull viver, inclusive será passivada e ativada da mesma forma. A mesma regra vale para Singleton e Stateless.

 


My use case is very simple. I have two pages, the first one has a couple of fields and the second one shows the result of these fields based on specific calculus.

The result page has a print button, which calls a new browser page that is ready to print.

In addition, I would like in this “new browser page” shows also the customer logo above the result, but only in printable page.

The code below shows how I can achieve this requirement:


<af:panelStretchLayout id="psl1" >

 <f:facet name="top">

 <af:panelGroupLayout id="pgl6" halign="center" layout="scroll"
 styleClass="AFStretchWidth">
 <af:image source="/images/logo.gif" shortDesc="logo" rendered="<strong>#{adfFacesContext.outputMode eq 'printable'}</strong>"
 id="i1" />
 </af:panelGroupLayout>

 </f:facet>

 <f:facet name="center">

<af:panelBox id="pcg7"
 text="Result">

<af:panelGroupLayout layout="horizontal"
 id="pgl5"
 halign="right"
 styleClass="AFStretchWidth">
 <af:commandLink id="cl1">
 <af:image shortDesc="Imprimir" source="/images/bt_imprimir.gif" inlineStyle="border:none" id="image2"/>
 <af:showPrintablePageBehavior />
 </af:commandLink>
 </af:panelGroupLayout>

</af:panelBox>
 </f:facet>
 </af:panelStretchLayout>

 

The secret was the rendered property: #{adfFacesContext.outputMode eq ‘printable’}. That is it!


Novo na spec EJB 3.1, essa é a uma das features mais desejadas e pedidas. É muito comum nós precisarmos fazer um request e esquecer o resultado, pois nós sabemos que esse dado processamento vai demorar por conta do requerimento, etc.

Nesses casos, podemos usar o novo @javax.ejb.Asynchronous annotation para retornar o controle para o cliente antes do EJB ser invocado. Se o cliente precisa do valor de retorno, este pode tê-lo pela api java.util.concurrent.Future.

Basicamente para um método ser assíncrono, é simples assim:


//com retorno

@Asynchronous

public Future<String> myMethod() {

// Wrap and return

return new AsyncResult<String>("qualquer coisa");

}

//sem retorno

@Asynchronous

public void myMethod(){}

Considerações importantes a fazer, antes de continuar:

  1. Métodos Assíncronos podem ser aplicados a qualquer session bean, sejam Stateful, Stateless ou Singleton beans;
  2. Um método assíncrono sempre criará um novo contexto de transação para sua execução, mesmo que esse tenha sido chamado um contexto de transação criado em seu cliente e o transaction attribute seja REQUIRED. Ou seja, o contexto do cliente não é propagado.
  3. Um método assíncrono de retorno void não pode lançar uma application exception. Isso só é permitido para métodos assíncronos com retorno Futute<V>.
  4. O contexto de segurança é propagado normalmente para métodos assíncronos, como já acontece com métodos não assíncronos.

 

Possíveis questões para OCE-EJBD6:

Considerando o bean:


@Asynchronous

public void myAsyncMethod() {

System.out.println("In regularM2void");

if(true) throw new RuntimeException("RTE");

}

//client

beanRef.myAsyncMethod();

System.out.println("done");

O que é correto?

1) Obterá um javax.ejb.EJBException e “done” não será impresso.

2) Obterá um javax.ejb.EJBException e “done” será impresso.

3) Obterá um RuntimeException e “done” não será impresso.

4) Não obterá qualquer exception e “done” será impresso.

Resposta:

Nesse caso dois conceitos se misturam, primeiro deles é que o esse cliente unca receberá uma exception vinda desse método, pois tão logo o método é chamado ele retornará para o cliente a execução, e por isso um assíncrono método com retorno void não pode declarar exceções checadas. Por sempre voltar a execução para o cliente “done” sempre será impresso.

Logo, resposta correta é o item 4.

Questão 2:

Quais desses métodos são válidos em um session bean:

1)  @Asynchronous public void getItDone() throws Exception{  //valid code}

2) public void getItDone() throws Exception{  //valid code}

3) @Asynchronous public Future<void> getItDone() {  //valid code}

4) @Asynchronous public void getItDone() {  //valid code}

5) @Asynchronous void getItDone() throws Exception {  //valid code}

Resposta: opções 2 e 4 são válidas.

Opção 1 não é válida, pois decalara um método assíncrono de retorno void com uma exceção checada, o que não é permitido. É permitido declaras essas exceptions com retorno Future<V>.

Opção 3 não é válida pois Future<void> é inválido.

Opção 5 não é válida pois não é permitido um método de session bean não ser público.

Questão 3:

Qual afirmativa é correta?

1) The security principal of the caller propagates to the target bean’s asynchronous method.

2) The security principal of the caller propagates to the target bean’s asynchronous method only if the target bean specifies so in its deployment information.

3) The security principal of the caller propagates to the target bean’s asynchronous method only if the target bean and the caller bean specify so in their deployment information.

4) The security principal of the caller is never propagated to the target bean’s asynchronous method.

5) The target bean is executed as “system” during the asynchronous call.

Resposta: opção 1. Um método assíncrono mantém as regras de segurança dos sessions beans. Logo, o principal do cliente será propagado para o método assíncrono normalmente como acontece com outros métodos do de qualquer session bean.

Por hoje é isso!


Uma das novidades trazidas pela spec da JEE6 é o novo session bean: Singleton. Para quem conhece o pattern, se não o mais conhecido da Gof, eu não discutirei aqui, mas colocarei na referência. Basicamente, a idéia é que suportada pelo container session beans de única instância.

Exemplo:


@javax.ejb.Singleton

@javax.ejb.Startup

public class MySingletonBean implements MySingletonLocalBusiness{..}

A anotação @Singleton identifica que o session bean é Singleton. Já a anotação @Startup indica que singleton será criado tão logo o container for iniciado. Caso não seja especificado, o container carregará o bean apenas quando ele for referenciado (lazy initialization).

Por padrão, é possível também especificar para esse bean o método de PostConstruct:


@javax.ejb.PostConstruct

public void applicationStartLifecycleMethod() throws Exception{...}

Esse método será chamado, tão logo o bean ser inicializado pelo container (chamando o construtor sem argumento) e injetados as propriedades do bean.

Concorrência

Diferente dos outros beans, o Singleton Session Bean por ter uma instância só, pode ser compartilhado por múltiplos clientes. Logo, existe uma preocupação com a concorrência. Para isso, o container possui três tipos de gerência de concorrência:

  1. @javax.ejb.ConcurrencyManagement(javax.ejb.ConcurrencyManagementType.CONTAINER) – Gerenciado pelo Container
  2. @javax.ejb.ConcurrencyManagement(javax.ejb.ConcurrencyManagementType.BEAN) – A critério do Bean Provider
  3. @javax.ejb.ConcurrencyManagement(javax.ejb.ConcurrencyManagementType.CONCURRENCY_NOT_SUPPORTED)

A concorrência por CONTAINER é a mais importante, e é a padrão caso não seja especificado. Em conjunto com a @javax.ejb.Lock, é possível definir tais características.

Exemplo:

@javax.ejb.ConcurrencyManagement(javax.ejb.ConcurrencyManagementType.CONTAINER)

public class MyBean{

@javax.ejb.Lock(javax.ejb.LockType.READ)

@javax.ejb.AccessTimeout(timeout=15,unit=java.util.concurrent.TimeUnit.SECONDS)

public String concurrentReadOnlyMethod(){...}

}

@javax.ejb.Lock(javax.ejb.LockType.WRITE)

public void allowOnlyOneWriteAtATimeMethod(String stringToSet){...}

O Lock pode ser de dois tipos: READ ou WRITE. O lock do tipo WRITE bloqueia a classe para acesso de apenas uma Thread por vez, o que significa que todos as outras threads deverão esperar até o lock tornar-se disponível para acessar a classe.

É possível especificar timeouts de espera do método com o @AcessTimeout, no exemplo uma thread ficará aguardando o método por 15 segundos. Caso não seja suficiente retornará um javax.ejb.ConcurrentAccessTimeoutException. Isso evita que a thread fique esperando pelo bean por tempo indeterminado.

Pegadinha quanto a Lock. Considere o seguinte bean:

@Singleton
@LocalBean
@Lock(LockType.WRITE)
public class CrazySingletonBean {
 String s1 = "x";
 String s2 = "y";

 public void setStrings(){
 s1 = "x"; s2 = "y";
 }

 public void clearStrings(){
 s1 = ""; s2 = "";
 }

 @Lock(LockType.READ)
 public String getValue(){
 return s1+" "+s2;
 }
}
<pre>

Os métodos setStrings() e clearStrings() são chamados por outro bean em loop, enquanto o getValue() é chamado por alguns outros beans periodicamente.
Quais dos seguintes valores retornados por getValue() são válidos?

a) “x y” or ” “
b) “x y”, ” “, “x “, or ” Y”
c) “x y”
d) alguns clientes podem retornar “x y” enquanto outros podem retornar ” “.

A opção correta é a em negrito. A razão para isso é a questão do Lock. Repare que no topo da classe definimos que os métodos tem Lock do tipo WRITE o que significa que quando um cliente acessa um método desse tipo, nenhuma outra thread de outro cliente poderá acessar esse ou outro método do bean ao mesmo tempo. A segunda coisa a se reparar é que apesar da classe ter declarado Lock do tipo WRITE o método getValue() tem o lock do tipo READ, o que significa que enquanto um cliente chama esse método, outras thread poderiam ocorrer em outros métodos que fossem também do tipo READ, no caso dessa classe, múltiplas threads podem acessar getValue() simultaneamente.

Logo, a opção A é a correta.

 

A principal pegadinha que vi até o momento é relativa ao lançamento de uma runtime exception dentro de um business method de um singleton. Exemplo:

 


@Singleton

public class CountryCodeBean {

private Map<String, String> ccMap;

 @PostConstruct     public void initializeCountryData(){      ...     }

@Lock(LockType.READ)

public String getCode(String country){

if(country == null)

throw new EJBException("Bad Input");

return ccMap.get(country);

}
}

Vamos imaginar que existe um cliente válido que tenta chamar getCode(null). Todas as vezes que ele chamar com null, ele receberá uma EJBException que é uma runtime exception. Agora pergunta, quantas instâncias desse Singleton são criadas. De acordo com os conhecimento sobre tratamento de exceções em Enterprise JavaBeans sabemos que uma runtime exception causa a destruição da instância do bean, mas para o caso particular de Singleton Session Beans, lançar qualquer exception dentro do business method não causará a destruição da instância. Ou seja, nesse caso em especial, quantas vezes forem chamadas o método getCode(null), será criada e mantida apenas 1 instância do Singleton.

 

Por hora isso resume o tema Singleton Session Bean. Próximo post algumas pegadinhas de prova relacionadas. Até breve!

Referências:

Singleton pattern wikipedia - http://pt.wikipedia.org/wiki/Singleton


One more easily requirement, where everybody needs! I have a simple use case. Imagine a authentication form, where I have to know If the user exists in my database first before tried to login him. I just want to throw a exception and I would like to my exception message have been showed to my user in friendly way. My demo shows how to do this!

First of all, I will show my session bean, with 4 methods and different exceptions throw:

 


@Stateless(name = "SessionEJB", mappedName = "SessionEJB")

public class SessionEJBBean implements SessionEJB, SessionEJBLocal {

@Resource    SessionContext sessionContext;
 public SessionEJBBean() {    }

@Override    public void authenticateJbo(String email) throws JboException{        throw new JboException("Authenticate failed jbo");    }

@Override    public void authenticateRuntime(String email) throws RuntimeException{        throw new JboException("Authenticate failed runtime");    }

@Override    public void authenticateChecked(String email) throws Exception{        throw new JboException("Authenticate failed checked");    }

@Override    public void authenticateCustomJbo(String email) {        throw new CustomJboException("Authenticate failed custom jbo exception");    }

}

 

I did the method binding with my JSF view, just to show the exceptions:



In every exception, there is no exception by adf controller framework. So, look what It’s happening:

Of course, It’s so ugly, It’s not what I want. Therefore, I will show the correct way to do this. You have to implement a custom DCErrorHandler, it’s easy, you have to just extend the DCErrorHandlerImpl class from ADF Controller Framework and handle the exception. The example class is below:


package com.oracle.demo.view.exception;
import oracle.adf.model.BindingContext;import oracle.adf.model.binding.DCBindingContainer;import oracle.adf.model.binding.DCErrorHandlerImpl;
import oracle.jbo.JboException;

public class CustomErrorHandlerImpl extends DCErrorHandlerImpl {

&nbsp;

public CustomErrorHandlerImpl(boolean b) {        super(b);    }

&nbsp;

public CustomErrorHandlerImpl() {        super(true);    }

&nbsp;

@Override    public void reportException(DCBindingContainer bc, Exception ex) {

BindingContext ctx = bc.getBindingContext();

ex = (Exception)getRootException(ex);

disableAppendCodes(ex);

super.reportException(bc, ex);    }

private void disableAppendCodes(Exception ex) {

if (ex instanceof JboException) {

JboException jboEx = (JboException)ex;

jboEx.setAppendCodes(false);

Object[] detailExceptions = jboEx.getDetails();

if ((detailExceptions != null) && (detailExceptions.length > 0)) {

for (int z = 0, numEx = detailExceptions.length; z < numEx;                     z++) {

disableAppendCodes((Exception)detailExceptions[z]);

}

}

}

}

public Throwable getRootException(Throwable ex) {

Throwable rtEx = null;

if ((rtEx = ex.getCause()) == null) {            return ex;        }

else {

return getRootException(rtEx);

}

}

@Override

public String getDisplayMessage(BindingContext ctx, Exception th) {        return super.getDisplayMessage(ctx, th);    }

}

&nbsp;

 

Right now, we have to register this error handler in databindings.cpx :

 

 

We are ready to show the messages to the final User:

That’s it!


This is my first post about Oracle ADF technology. First of all, I have to explain why after this post will be many others. A few months ago, I changed for work to Oracle Corp. For that reason, It’s normal that I’ll see products and technologies from this company.

Today’s post I will talk about how to adding a parameter to ValueChangeListener event from JSF. In fact, I didn’t find a nice way to do this. So, the reason for I’m writing this post is also share my knowledge and find other way to do the same thing.

My issue was: I have a beauty datatable built using af:table. This table has a column with a af:selectOneChoice, because the user can choose in a dropdown which value is better for him. Simple and clean. When the User change this value, I have to show a friendly message, based on the value from another column in the same row. Therefore, I would like to have in my backing bean this row selected or this specific other column value to my purpose.

The unique option that I found is using ValueChangeListener and navigate to the components in runtime. I will explain with the code.

That’s my af:column:


<af:column width="10%" align="center" sortable="false" headerText="Regular (%)" id="c9">
<af:inputText id="limiteMaximo" <strong>visible="false"</strong> value="#{row.limitesContribuicaoPP2.limiteMaximo}">
<f:convertNumber />
</af:inputText>
<af:selectOneChoice autoSubmit="true"
value="#{row.limitesContribuicaoPP2.percentualRegularToString}"
id="comboRegular"  valuePassThru="true"
valueChangeListener="#{Petros2MB.onChangePercentualRegular}">
<f:selectItems value="#{row.percentuaisRegular}" id="si4"/>
</af:selectOneChoice>
</af:column>

There are two components inside the column: af:inputText and af:selectOneChoice. The trick is, the component inputText is not visible (the old h:inputHidden), I prefer put in this way, just to simplify my managed bean. In the valueChangeListener method I can get this value in inputText and make my decision. Let’s go to the MB code:


public void onChangePercentualRegular(ValueChangeEvent evt){
if (evt.getNewValue() != null){

String strNewValue = (String)evt.getNewValue();
Integer newValue = Integer.parseInt(strNewValue);
RichColumn column = (RichColumn)evt.getComponent().getParent();
RichInputText inputLimiteMaximo = (RichInputText)column.getChildren().get(0);
Integer limiteMaximo = (Integer)inputLimiteMaximo.getValue();

if (newValue < limiteMaximo){//process what i want to do}
}
}

In fact, I woudn’t need to put the component inputText visible=false inside my column, but I prefer in that way for simplify my MB code. I can navigate for all components in this page, just using getParent and getChildren. However, It’s not a good tip, because If you need to change something in the page, probably this could affect in your MB. So, be careful!


Nowadays, several applications use Google Maps API. In my case, I had to implement in a Jboss Seam + Jboss RichFaces webapp. In the beginning, it was not difficult, because RichFaces has a component to Gmaps API and Seam provides a useful integration with javascript, it is known as Remote API, but when I had to return lots of differents types of objects to plotting on the map strangely there is no error, but simply the map does not work.

So, I decided to implement in a different way without Remote. Basically, I will use Ajax to request my entities to plot, after that I will apply reRender in a div layer where calls my javascript function to fill my map. Let’s see!

First of all, my xhtml:


				<a4j:commandButton id="find"
					value="#{messages['btn.buscar']}"
					onclick="this.disabled=true; onClickSearch();"
					action="#{myAction.searchMap}"
					oncomplete="onCompleteSearch(); this.disabled=false;"
					reRender="divMapaResult"/>

	<s:div id="divMapaResult" style="visibility: hidden;">
               <ui:repeat var="row" value="#{myAction.resultList}">
                    <script type="text/javascript">
                       addEquipe('<h:outputText value="#{row.latitude}"/>',
                           '<h:outputText value="#{row.longitude}"/>',
                           '<h:outputText value="#{row.caption}"/>');
                   </script>
               </ui:repeat>
           </s:div>

			<f:view contentType="text/html">

				<rich:panel id="panelMapa" header="#{messages['Mapa']}">
		        	<rich:gmap
						id="gmap" gmapVar="map" zoom="3"
						style="width:100%;height:500px" mapType="G_NORMAL_MAP"
						gmapKey="#{parametros['mapkey']['valor']}"
						lat="-46.000" lng="-20.000"
			        	locale="#{messages['localeGoogleMaps']}"
			        	oninit="init(map)"
			        	/>
				</rich:panel>

			</f:view>

There are two javascript functions: onClickSearch and onCompleteSearch. onClickSearch just clean my map and initialize my global array of points.  onCompleteSearch read my global array, calculate and plot. That’s my js file:


var maxx = -200;
var maxy = -100;
var minx = 200;
var miny = 100;

var l_map;
var equipes = new Array();

function init(map) {
    for (i = 0; i < equipes.length; i++) {
        try{
        	map.addOverlay(equipes[i]);
        }catch(err){ alert(err);}
    }
}

function onClickSearch() {
	map.clearOverlays();
	equipes = new Array();
}

function onCompleteSearch(){
	init(map);
        //centralize my map
	var sw = new GLatLng(miny, minx);
	var ne = new GLatLng(maxy, maxx);
	var bounds = new GLatLngBounds(sw, ne);
	var fitLevel = map.getBoundsZoomLevel(bounds);
	if (fitLevel > 1) {
		fitLevel = fitLevel -1;
	}
	var center = new GLatLng(miny + (maxy-miny)/2, minx + (maxx-minx)/2);
	map.setCenter(center, fitLevel);

}

function addEquipe(lat, lng, caption) {
	if (lat != null && lat != '' && lng != null && lng != ''){
		lat = parseFloat(lat);
		lng = parseFloat(lng);
		marker = createMarker(lat,lng,caption);
		equipes[equipes.length] = marker;
		if (lat > maxy){
			maxy = lat;
		}
		if (lng > maxx){
			maxx = lng;
		}
		if (lat < miny){
			miny = lat;
		}
		if (lng < minx){
			minx = lng;
		}
	}
}

function createMarker(geoy, geox, caption) {
	var latlng = new GLatLng(geoy, geox);
	var marker = new GMarker(latlng);
	GEvent.addListener(marker, "click", function() {
	  marker.openInfoWindowHtml(caption);
	});
	return marker;
}

This solution is quite simple and very powerfull. Works for me and all browsers. That’s it!


Today, I have a opportunity to post a fast, but important topic. Nowadays is very common people when develop to the web to intend malicious attacks. In this idea, is normally implement a captcha thinking about protect your operation system against people who could implement malicious automatic softwares.

With Captcha is obligation that the User put in his user interface something especific. Jboss Seam has a sample of captcha, where you can use just puting this peace of code in your page:


<rich:panel  id="captchaPanel">

<h:panelGrid rowClasses="prop" columns="1">

<s:decorate id="verifyCaptchaDecoration" template="../layout/edit.xhtml">

<ui:define name="label">#{messages['ordemservicocriacao.captcha']}</ui:define>

<h:graphicImage value="/seam/resource/captcha"/>

<h:inputText id="verifyCaptcha" value="#{captcha.response}" required="true"/>

</s:decorate>

</h:panelGrid>

</rich:panel>

My little trouble was that Seam implements a sample of captcha with a algorithm where gives two numbers and this case the user should input the add result. I had to implement my owner algorithm, doing similar the megaupload website. Here is my code:


@Name("org.jboss.seam.captcha.captcha")
@Scope(ScopeType.SESSION)

@Install(precedence = Install.APPLICATION)

@BypassInterceptors

public class CustomCaptcha extends Captcha {
 private static final long serialVersionUID = 1L;

@Override
@Create

public void init() {

	String challenge = getAlgorithmChallenge();

	setCorrectResponse(challenge);

	setChallenge(challenge);
}
private String getAlgorithmChallenge() {

String challenge = "";
int i = 0;
while (i < 5) {
// gera um número aleatório entre de 50 a 90
int x = 50 + (int) (Math.random() * 40);
if (x >= 58 && x <= 64) {
continue;
}
i++;
challenge += (char) x;
}
return challenge;
}

@Override
public BufferedImage renderChallenge() {
BufferedImage challenge = new BufferedImage(100, 20, BufferedImage.TYPE_BYTE_GRAY);
Graphics graphics = challenge.getGraphics();
graphics.setColor(getChallengeBackgroundColor());
graphics.fillRect(0, 0, getChallengeImageWidth(), 20);
graphics.setColor(getChallengeTextColor());
graphics.drawString(getChallenge(), 5, 15);
return challenge;
}

@Override
@CaptchaResponse(message = "{validator.captcha.message}")
public String getResponse() {		return super.getResponse();	}

protected int getChallengeImageWidth() {		return 100;	}

protected Color getChallengeBackgroundColor() {		return Color.BLACK;	}

protected Color getChallengeTextColor() {		return Color.WHITE;	}
}

In summary, what I need It was override the seam component “org.jboss.seam.captcha.captcha” with precedence higher than the Captcha component and override methods.

There’s another problem I found in my tests. After the User input a wrong value in captcha, the webpage was not refreshing the captcha image. To solve this problem, I had to force this refresh, because some browsers save images on their cashes.


<s:decorate id="verifyCaptchaDecoration" template="../layout/edit.xhtml" >

<ui:define name="label">#{messages['ordemservicocriacao.captcha']}</ui:define>

<h:graphicImage value="/seam/resource/captcha?f=#{currentDate.time}"/>

<h:inputText id="verifyCaptcha" value="#{captcha.response}" required="true"/>

</s:decorate>

When I have to choose a strategy of generation ID, I always prefer sequence. This is my favourite, and works very well. Unfortunatelly, some databases do not support it. In my case, I’ve been using PostgreSQL or Oracle, then I can use sequence.

In the hibernate documentation, they show us how we could use this sequence strategy. Take a look in a sample source code:

<pre>@Entity
@javax.persistence.SequenceGenerator(
    name="SEQ_STORE",
    sequenceName="my_sequence"
)
public class Store implements Serializable {
    private Long id;

    @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
    public Long getId() { return id; }
}</pre>

However, I have a little problem in my use case. Sometimes, I don’t want to use the sequence strategy, I only want to set my id by setXXXId() method, and persist this data. If I had tried to do this, in a entity above, it won’t work.


Store store = new Store();

store.setId(109238L); //i'm trying to force an ID

entityManager.persist(store); //hibernate here will use the sequence generator overwrite my id in the last line

So, in order to work my example,  I have to write my own sequence strategy generator:


import java.io.Serializable;
import org.hibernate.HibernateException;

import org.hibernate.engine.SessionImplementor;

import org.hibernate.id.SequenceGenerator;
import br.com.activia.commons.model.BaseBean;
public class CustomSequenceGenerator extends SequenceGenerator {

@Override
public Serializable generate(SessionImplementor session, Object obj) 	throws HibernateException {

System.out.println("CustomSequenceGenerator");

BaseBean<?> myEntity = (BaseBean<?>)obj;	    //If my id was set, use it!

if (myEntity.getId()!=null && myEntity.getId() > 0) {

return myEntity.getId();	    }

else {

return super.generate(session, obj);

}

}
}

My custom sequence generator extends default sequence generator from hibernate. And the unique job here is to override generate method, and check if the id field was set. In my entity I have to change a little:

<pre>@Entity
public class Store implements Serializable {
    private Long id;

    @Id @GeneratedValue(generator="SEQ_STORE")
    @GenericGenerator(name="SEQ_STORE" , 
       strategy="mypackage.id.CustomSequenceGenerator", 
       parameters = {@Parameter(name="sequence", value="seq_store")})
    public Long getId() { return id; }
}</pre>

That’s it!


A few months ago, I had a unfortunately surprise with Hibernate Logging. People usually logs hibernate with log4j using this:


<category name="org.hibernate.SQL" additivity="false">

<level value="debug"/>

<appender-ref ref="FileAppender"/>

<appender-ref ref="ConsoleAppender"/>

</category>

The peace above, only logs the sql without your parameters. So, when you need to see your parameters, you did this:


<category name="org.hibernate.type" additivity="false">

<level value="debug"/>

<appender-ref ref="FileAppender"/>

<appender-ref ref="ConsoleAppender"/>

</category>

If you tried to test this peaces above, you’ll see it is very inutile. Firstly, because I didn’t know how much time a sql query causes. And the second one, the log was very dirty.

After that, I find out few solutions in the web. The most common is c3p0, which it is also integrate with hibernate.  However, I chose log4jdbc, which has exactly what I need. I’ll describe here, all steps you’ll have in order to configure your hibernate project to use log4jdbc.

Step 1: Download dependencies

  • log4jdbc
    log4jdbc is a Java JDBC driver that can log SQL and/or JDBC calls (and optionally SQL timing information) for different JDBC drivers using the SLF4J logging system, which provides APIs for interworking of logging service with log4jdbc. This is the main JAR library we need to analyse the CUBRID JDBC Driver.Download the latest version of log4jdbc compatible with JDK 1.5 or higher fromhttp://code.google.com/p/log4jdbc/downloads/list. CUBRID JDBC supports JDK 1.5 and higher.
  • SLF4J
    log4jdbc uses the SLF4J (Simple Logging Facade for Java), a very simple and flexible small library which enables logging at runtime without modifying the application binary. Moreover users are free to pick any java logging systems such as Log4jjava.util logging in JDK 1.4, logbackJakarta Commons Logging. In this tutorial we will be using Log4j as our logging system. SLF4J is distributed in zip archive which has many jar files in it. You will need only two of them: 

    1. slf4j-api-1.5.0.jar or any other latest available version. This library will provide APIs for interworking of logging service with log4jdbc.
    2. slf4j-log4j12-1.5.2.jar or any latest version. This library will provide the implementation libraries for interworking of Log4j-based logging service with log4jdbc.

    Download the latest version of slf4j fromhttp://www.slf4j.org/download.html.

  • log4j
    log4j is a Java logging system which we will use throughout our project.
    Download log4j from http://logging.apache.org/log4j/1.2/download.html.
    You will also need to download the sample log4j.xml configuration file so that you do not have to type all properties manually.
    Download the sample log4j.xml file fromhttp://code.google.com/p/log4jdbc/source/browse/trunk/doc/log4j.xml.

Step 2: Hibernate settings

We’ll create a class which extends the provider default from hibernate.  Basically, we need to override the getConnection method and return the object ConnectionSpy from log4jdbc library.


import java.sql.Connection;

import java.sql.SQLException;
import org.hibernate.connection.DatasourceConnectionProvider;

public class CustomDatasourceConnectionProvider extends		DatasourceConnectionProvider {
public Connection getConnection() throws SQLException {

return new net.sf.log4jdbc.ConnectionSpy(super.getConnection());

}

}

After that, we have to register this custom provider in hibernate settings xml. In my case, I’m working with JPA, then my settings file is persistence.xml:


<property name="hibernate.connection.provider_class" value="mypackage.CustomDatasourceConnectionProvider"/>

Step 3: Log4j settings

My log4j file was:

<pre><?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<!-- An example log4j configuration xml file for log4jdbc -->
<!-- Logging levels are:                                  -->
<!-- DEBUG < INFO < WARN < ERROR < FATAL                  -->

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

  <appender name="stdout-appender">
    <layout>
      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %c{1}: %m%n"/>
    </layout>
  </appender>

  <appender name="sql-appender">
    <param name="File" value="./logs/sql.log"/>
    <param name="Append" value="false"/>
    <layout>
      <param name="ConversionPattern" value="-----&gt; %d{yyyy-MM-dd HH:mm:ss.SSS} &lt;%t&gt; %m%n%n"/>
    </layout>
  </appender>

  <appender name="sql-timing-appender">
    <param name="File" value="./logs/sqltiming.log"/>
    <param name="Append" value="false"/>
    <layout>
      <param name="ConversionPattern" value="-----&gt; %d{yyyy-MM-dd HH:mm:ss.SSS} %m%n%n"/>
    </layout>
  </appender>

  <appender name="jdbc-appender">
    <param name="File" value="./logs/jdbc.log"/>
    <param name="Append" value="false"/>
    <layout>
      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n"/>
    </layout>
  </appender>

  <appender name="jdbc-connection">
    <param name="File" value="./logs/connection.log"/>
    <param name="Append" value="false"/>
    <layout>
      <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %m%n"/>
    </layout>
  </appender>

  <!--
       The Following 5 logs can be turned on and off while the server is running
       LIVE in order to trace the SQL and/or all JDBC coming out of the application.

       To turn a log on, set the level value to INFO or DEBUG (to see class name and
       line number information in the log)  The DEBUG setting is much more inefficient
       but the output is much more useful.

       To turn off JDBC logging completely, you must set all 5 logs to a level higher
       than ERROR (FATAL is suggested.)
  -->

  <!-- log SQL (pre-execution) plus exceptions caused by SQL -->
  <logger name="jdbc.sqlonly" additivity="false">
    <level value="debug"/>
    <appender-ref ref="sql-appender"/>
  </logger>

  <!-- log SQL with timing information, post execution -->
  <logger name="jdbc.sqltiming" additivity="false">
    <level value="fatal"/>
    <appender-ref ref="sql-timing-appender"/>
  </logger>

  <!-- only use the two logs below to trace ALL JDBC information,
       NOTE:  This can be very voluminous!  -->

  <!-- log all jdbc calls except ResultSet calls -->
  <logger name="jdbc.audit" additivity="false">
    <level value="fatal"/>
    <appender-ref ref="jdbc-appender"/>
  </logger>

  <!-- log the jdbc ResultSet calls -->
  <logger name="jdbc.resultset" additivity="false">
    <level value="fatal"/>
    <appender-ref ref="jdbc-appender"/>
  </logger>

  <!-- log connection open/close events and dump of all open connection numbers -->
  <logger name="jdbc.connection" additivity="false">
    <level value="fatal"/>
    <appender-ref ref="connection-appender"/>
  </logger>

  <!-- this log is for internal debugging of log4jdbc, itself -->
  <!-- debug logging for log4jdbc itself -->
  <logger name="log4jdbc.debug" additivity="false">
    <level value="debug"/>
    <appender-ref ref="stdout-appender"/>
  </logger>

  <!-- by default, log everything to the console with a level of WARN or higher -->
  <root>
    <level value="warn"/>
    <appender-ref ref="stdout-appender"/>
  </root>
</log4j:configuration></pre>

When you run your Application Server, you’ll have something like this in your output:

[2011-03-16 15:56:07,434] jdbc.sqltiming DEBUG –  org.hibernate.jdbc.AbstractBatcher.getResultSet(AbstractBatcher.java:186)11. select ordemservi0_.actstatusos as col_0_0_, sum(case when ordemservi0_.actstatussla=1 then 1 else 0 end) as col_1_0_, sum(case when ordemservi0_.actstatussla=2 then 1 else 0 end) as col_2_0_, sum(case when ordemservi0_.actstatussla=3 then 1 else 0 end) as col_3_0_, sum(case when ordemservi0_.actstatussla=4 then 1 else 0 end) as col_4_0_ from act_ordem_servico ordemservi0_ where (ordemservi0_.actstatusos in (1 , 2 , 3 , 5 , 7 , 10 , 12 , 17 , 18 , 19 , 24 , 26 , 33)) and (ordemservi0_.actstatussla in (1 , 2 , 3 , 4)) group by ordemservi0_.actstatusos order by ordemservi0_.actstatusos  {executed in 18 msec}

Isn’t it awsome, is it?

References