jueves, 25 de febrero de 2010

google-guice example

Google-Guice:
Is a java framework to provide dependency injection (DI).

Basic advantages:



My example:

public class AllInOne {

public interface DemoInt {
public String test();
}

public static class DemoImp implements DemoInt {
public String test() {
return "OK";
}
}

public static class Demo {
@Inject
private DemoInt injectedClass;

public String makeTest() {
return injectedClass != null ? injectedClass.test() : "ERROR";
}
}

public class DemoModule extends AbstractModule {
@Override
protected void configure() {
bind(DemoInt.class).to(DemoImp.class);
}
}

public AllInOne() {
Injector injector = Guice.createInjector(new DemoModule());
Demo demo = injector.getInstance(Demo.class);
System.out.println(demo.makeTest());
}

public static void main(String a[]) {
new AllInOne();
}
}

Communications link failure between MySQL and Hibernate after many hours

The Problem:
I was using hibernate and MySql with apache-commons-dhcp. At the beginning everything works ok, but usually the first user who tray to login in the application in the morning get this exception:


2010-02-25 10:58:15,855 ERROR [org.hibernate.transaction.JDBCTransaction] - JDBC begin failed
com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 10.228 milliseconds ago. The last packet sent successfully to the server was 16 milliseconds ago.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2497)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2949)
... 47 more
25-feb-2010 10:58:15 org.apache.catalina.core.StandardWrapperValve invoke
GRAVE: Servlet.service() para servlet default lanzó excepción
org.springframework.transaction.CannotCreateTransactionException: Could not open Hibernate Session for transaction; nested exception is org.hibernate.TransactionException: JDBC begin failed:
at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:599)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:374)
at org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:263)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:101)
Caused by: org.hibernate.TransactionException: JDBC begin failed:
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:68)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1326)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:558)
... 36 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 10.228 milliseconds ago. The last packet sent successfully to the server was 16 milliseconds ago.
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
Caused by: java.io.EOFException: Can not read response from server. Expected to read 4 bytes, read 0 bytes before connection was unexpectedly lost.
at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:2497)
at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:2949)
... 47 more




The Cause:
MySQL server has a default timeout period after which it terminates the idle connections.
This period is 8 hours by default.

Searching on the Internet I found many solutions:
  • Disable SQL_CACHE on mysql (http://forums.mysql.com/read.php?39,203407,217196#msg-217196)
  • Use c3p0 in hibernate (http://hibernatedb.blogspot.com/2009/05/automatic-reconnect-from-hibernate-to.html)
  • Many others..
But always looks a big change in the application for a simple problem, finally

The Solution:
Add the following properties to dbcp configuration:
  • validationQuery=”SELECT 1″
  • testOnBorrow=”true”

How it Works:

  • validationQuery --> Before returning the connection from pool to the application, dbcp runs the “SELECT 1 ” query on the connection to see it it is still live.
  • testOnBorrow --> you tell dbcp to perform the check before returning the connection to application.
Other link with the same solution:

miércoles, 24 de febrero de 2010

IE6 + HTTPS + download files = bug

The problem:
When you try to download a file using href tag in a HTTPS connection with Internet Explorer 6 you get this error: "Internet Explorer Cannot Download".

The Microsoft support link: http://support.microsoft.com/kb/812935/

My initial HTML code:

<a href="../files/test.zip">download</a>

The solution:
Make a specific "servlet" to perform the download. And change there the cache parameters in the request.

The official support says that error hapen with IE6 SP1 but I get the same situation with IE6 SP2.


<html>
<head>
<%@page import="java.util.*,java.io.*, javax.activation.MimetypesFileTypeMap"%>
<%@ page language="java" session="false" contentType="text/html; charset=8859_1"%>
</head>
<body>
<%
String fileName=request.getParameter("fileName");
File f=new java.io.File(request.getRealPath("/ficheros")+"/"+fileName);

if(!f.exists()){
%>
<script>alert("Error: Fichero ['<%=fileName%>'] inexistente!");</script>
<%
}else{
//the content type set as excel
response.setContentType (new MimetypesFileTypeMap().getContentType(f));
//the header and also the Nameis set by which user will be prompted to save
response.setHeader ("Content-Disposition", "attachment;filename="+fileName);
response.setHeader("Content-Disposition", "inline; filename="+fileName);
response.setHeader("Expires", "0");
//response.setHeader("Cache-Control", "must-revalidate, post-check=0,pre-check=0");
response.setHeader("Pragma", "public");
// response.setDateHeader("Expires", 0); //prevents caching at the proxy
response.setHeader("Cache-Control", "max-age=0");

InputStream isStream = null;
ServletOutputStream sosStream = null;
try{
//response.flushBuffer();
isStream = new java.io.FileInputStream(f);
sosStream = response.getOutputStream();
int ibit = 256;
while ((ibit) >= 0){
ibit = isStream.read();
sosStream.write(ibit);
}
}catch (java.lang.Exception ioeException){%>
<script>alert('Se ha producido un error inesperado.!');</script>
<%}
sosStream.flush();
sosStream.close();
isStream.close();
}
%>
</body>
</html>



Now works with all browsers without errors.








martes, 30 de junio de 2009

Oracle, length problem with special characters in VARCHAR2

Oracle maneja de distintas formas la comprobación del tamaño maximo para una columna dependiendo del charset de la BD.
En nuestro caso lo teniamos definido como UTF8 y se nos presentaba el siguiente problema:

Problema:
Si el maximo para una columna es de 10 y dentro de los 10 caracteres habia alguno con acento o ñ a la hora de insertar obteniamos el siguiente error:

ORA-12899: value too large for column

Ejemplo:

CREATE TABLE TEST (
COL_A VARCHAR2(2) NOT NULL
);


INSERT INTO TEST2 VALUES ('aa')
OK
INSERT INTO TEST2 VALUES ('áá')
ERROR


Solució:
Realmente el maximo que indicamos por defecto es en bytes y al tener charset UTF8 esta tomando "á" como 2 bytes.

Opción A: Cambiar el charset de la BD.

Opción B: Modificar todas las columnas de tipo VARCHAR2 para que interpreten su maximo como caracteres y no como bytes.

Ejemplo:

CREATE TABLE TEST (
COL_A VARCHAR2(2 CHAR) NOT NULL
);


INSERT INTO TEST2 VALUES ('aa')
OK
INSERT INTO TEST2 VALUES ('áá')
OK


Para implementar esta alternativa de forma automatica he creado el siguiente scritp:

select 'ALTER TABLE ' || table_name || ' MODIFY ( ' || column_name ||' '|| data_type || ' ( '|| char_length || ' CHAR));'
from cols
where data_type = 'VARCHAR2'
and char_used = 'B'

Esto nos genera una lista con todas las consultas que debemos ejecutar para implementar el cambio.