Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Monday, February 4, 2013

Using PostgreSQL in Java without JDBC

JDBC is the Java starndard API for accessing relational databases. There is any good reason for not using it, directly or through a higher-level API/framework (Hibernate, JPA, etc.)? Usually not, but if you feel you need, probably it's a good reason.

My own reason is related to pgpool-II and its parallel mode. As far as I know (please write to me if I'm wrong), pgpool's parallel mode doesn't support the PostgreSQL extended query sub-protocol. Unfortunately the PostgreSQL JDBC Driver can use only that protocol. Even setting the JDBC Driver for using the V2 protocol doesn't solve the problem because other issues in the communication with pgpool.

The only solution I found is not using JDBC, but accessing PostgreSQL through the libpq C library. Of course I need to do it in Java, so I wrapped the libpq library in Java classes, using the SWIG tool.

You'll find the code of my experiments in this Github repository.

Let's go through the full process.

  1. Install SWIG, downloading from here, or using the correct package of your OS. I use Debian, so I just needed to install the swig package:
    apt-get install swig
    
  2. Prepare a SWIG interface file, describing the C functions you want to wrap. If you want to wrap a whole library, this task could be very simple, as you can simply include the C header files:
    pqswig.i:
    %module pq
    %{
    #include "/usr/include/postgresql/libpq-fe.h"
    %}
    
    %include "/usr/include/postgresql/libpq-fe.h"
    
  3. Use the SWIG command for generating the Java wrapper classes and the C SWIG wrapper functions:
    swig -java \
        -package com.benfante.experiments.libpqwrapper.swig \
        -outdir \
        ../../../generated/java/com/benfante/experiments/libpgwrapper/swig \
        pqswig.i
    In the same directory you'll find the pqswig_wrapper.c file. In the indicated path (../../../generated/java/com/benfante/experiments/libpgwrapper/swig, change it following your needs) you'll find the Java wrapper classes.
  4. Compile the pqswig_wrapper.c file:
    gcc -c pqswig_wrap.c -I /usr/lib/jvm/java-6-sun/include -I /usr/lib/jvm/java-6-sun/include/linux
  5. Build the dynamic library:
    ld -G pqswig_wrap.o -o libpqswig.so -lpq
  6. Copy (or link) the libpqswig.o file into a directory of the java.library.path. For example, copy it into the /usr/lib directory:
    cp libpqswig.so /usr/lib/
    That's all. Of course the previous steps are for a Linux OS. If you are using a different OS, read the SWIG documentation and FAQs (in particular the SharedLibraries section).
Now you can execute code like the following:
package com.benfante.experiments.libpgwrapper;

import com.benfante.experiments.libpqwrapper.swig.ConnStatusType;
import com.benfante.experiments.libpqwrapper.swig.ExecStatusType;
import com.benfante.experiments.libpqwrapper.swig.SWIGTYPE_p_pg_conn;
import com.benfante.experiments.libpqwrapper.swig.SWIGTYPE_p_pg_result;
import com.benfante.experiments.libpqwrapper.swig.pq;

public class App {

    public static void main(String[] args) {
        System.out.println(System.getProperty("java.library.path"));
        System.loadLibrary("pqswig");
        System.out.println("PQ Library Version: " + pq.PQlibVersion());
        SWIGTYPE_p_pg_conn connection = connectToPostgres("localhost", "5432", "test", "test", "test");

        SWIGTYPE_p_pg_result res = selectAllPerson(connection);

        printTuples(res);

        pq.PQclear(res);

        pq.PQfinish(connection);
    }

    private static SWIGTYPE_p_pg_conn connectToPostgres(String host, String port, String db, String username, String password) {
        SWIGTYPE_p_pg_conn connection = pq.PQconnectdb("postgresql://" + username + ":" + password + "@" + host + ":" + port + "/" + db);
        if (pq.PQstatus(connection) != ConnStatusType.CONNECTION_OK) {
            System.out.println("Connection to database failed: " + pq.PQerrorMessage(connection));
            exitNicely(connection);
        }
        return connection;
    }

    private static SWIGTYPE_p_pg_result selectAllPerson(SWIGTYPE_p_pg_conn connection) {
        SWIGTYPE_p_pg_result res = pq.PQexec(connection, "SELECT * FROM person");
        if (pq.PQresultStatus(res) != ExecStatusType.PGRES_TUPLES_OK) {
            System.out.println("SELECT failed: " + pq.PQerrorMessage(connection));
            pq.PQclear(res);
            exitNicely(connection);
        }
        return res;
    }

    private static void exitNicely(SWIGTYPE_p_pg_conn connection) {
        pq.PQfinish(connection);
        System.exit(0);
    }

    private static void printTuples(SWIGTYPE_p_pg_result res) {
        int nTuples = pq.PQntuples(res);
        int nFields = pq.PQnfields(res);
        for (int i = 0; i < nFields; i++) {
            System.out.printf("%-15s|", pq.PQfname(res, i));
        }
        System.out.println("");
        for (int i = 0; i < nTuples; i++) {
            for (int j = 0; j < nFields; j++) {
                System.out.printf("%-15s|", pq.PQgetvalue(res, i, j));
            }
            System.out.println("");
        }
    }
}

Saturday, November 14, 2009

My Devoxx 2009

Devoxx banner
The following is my schedule for the Devoxx conference. In red the presentations I will attend. If you would like to suggest me other presentations you would like to hear about from me, send me a line and I will try to attend them.

Tuesday, May 5, 2009

Mutable authorities with Spring Security and CAS

Recently I worked on an application with the following requisite:

The logged user must select its current role among the roles for which he's authorized.


A simple requisite, and (apparently) it's easy to implement it with Spring Security: write an UserDetails class in which you can select the returned authority(ies). For example:


public class LoggedUserWithSelectableRole extends User {
private GrantedAuthority currentAuthority;

public LoggedUserWithSelectableRole(String username, String password,
boolean enabled, GrantedAuthority[] authorities) throws IllegalArgumentException {
super(username, password, enabled, authorities);
}

public void setCurrentAuthority(GrantedAuthority currentAuthority) {
this.currentAuthority = currentAuthority;
}

@Override
public GrantedAuthority[] getAuthorities() {
if (Arrays.asList(super.getAuthorities()).contains(currentAuthority)) {
return new GrantedAuthority[] {currentAuthority};
} else {
return new GrantedAuthority[0];
}
}

public GrantedAuthority[] getAllAuthorities() {
return super.getAuthorities();
}
}


Now you can select an authority for the logged user (for example, in a controller):


@RequestMapping
public String selectRole(@RequestParam(value = "role") int role) {
LoggedUserWithSelectableRole user =
(LoggedUserWithSelectableRole) SecurityContextHolder.getContext().
getAuthentication().getPrincipal();
user.setCurrentAuthority(user.getAllAuthorities()[role]);
return "redirect:/";
}


Unfortunately this is not sufficient, as the authorities used by Spring Security for checking the user authorization are not (usually) stored in the principal object, but it the Authentication object.

It would be nice to write something like:


/* WARNING: The method setAuthorities doesn't exist */
SecurityContextHolder.getContext().getAuthentication().
setAuthorities(user.getAuthorities());


But the Authentication token is mostly immutable, so the setAuthorities doesn't exist. Worst, in the AbtractAuthenticationToken class, the base class of most of the token implementations, the authorities attribute is private, so you can't easily implement by yourself an alternative token implementation extending the original token class.

In our application we are using CAS. The only solution I found (as far as I know...please send me a line if you see a better solution) was to extend the CasAuthenticationToken, provinding a costructor for coping an existing token (of course of the same type):


public class UpdatableCasAuthenticationToken extends CasAuthenticationToken {

private final int keyHash;

public UpdatableCasAuthenticationToken(CasAuthenticationToken token, GrantedAuthority[] authorities) {
super("BOH", token.getPrincipal(), token.getCredentials(), authorities, token.getUserDetails(), token.getAssertion());
this.keyHash = token.getKeyHash();
}

@Override
public int getKeyHash() {
return this.keyHash;
}

}


As you can see, we also need to hide attributes and override methods not modifiable through the constructor of the base class.

Now I can substitute the original token with the modified one:


@RequestMapping
public String selectRole(@RequestParam(value = "role") int role) {
LoggedUserWithSelectableRole user =
(LoggedUserWithSelectableRole) SecurityContextHolder.getContext().
getAuthentication().getPrincipal();
user.setCurrentAuthority(user.getAllAuthorities()[role]);
SecurityContextHolder.getContext().setAuthentication(
new UpdatableCasAuthenticationToken(
(CasAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(),
user.getAuthorities()));
return "redirect:/";
}


As CAS ha no concerns with the user roles, I think CasAuthenticationToken should provide a way for updating authorities, and maybe the authorites attribute of AbstractAuthenticationToken should be declared as protected.

Thursday, November 13, 2008

Building an AJAX chat with Parancoe and DWR

The AJAX integration through DWR 3 is not the main feature in Parancoe, but it's easy and funny. Let's see how simple is building a Web chat.

Starting from a project generated with Maven using the Parancoe Web Archetype, you need to add the Parancoe DWR Plugin to the dependencies in your pom.xml:


<dependency>
<groupId>org.parancoe</groupId>
<artifactId>parancoe-plugin-dwr</artifactId>
<version>2.0.2</version>
</dependency>


Then add the /dwr/* pattern to the mapping of the parancoe servlet in your web.xml.

Now DWR is ready to be used in your application. You check it building and deploying your application, and pointing your browser to <your_base_address>/dwr/index.html. You should see the DWR Test Page.

Then add a class with methods (a single method in this example) that will be invoked through AJAX:


package com.mycompany.testapp.ajax;

import org.directwebremoting.Browser;
import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.annotations.RemoteProxy;
import org.directwebremoting.ui.dwr.Util;
import org.springframework.stereotype.Component;

@Component
@RemoteProxy(name = "chat")
public class Chat {

@RemoteMethod
public void send(final String nickname, final String message) {
Browser.withCurrentPage(new Runnable() {
public void run() {
Util.addRows("chatLog", new String[][]{{nickname, message}});
}
});
}
}


Simple, isn't it? ...but powerful. When invoked that method will add a row to the table with id chatLog, in all browsers that are visualizing that page.

Let's see the page chat.jsp in which that method is invoked:


<%@ include file="WEB-INF/jsp/common.jspf" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>
<head>
<%@ include file="WEB-INF/jsp/head.jspf" %>
<script src="${cp}/dwr/interface/chat.js" type="text/javascript"/>
<script src="${cp}/dwr/engine.js" type="text/javascript" />
<script src="${cp}/dwr/util.js" type="text/javascript" />
<title>Parancoe DWR chat</title>
</head>
<body>
<h1>DWR Chat</h1>

<table id="chatLog">
<thead>
<tr><th>Nickname</th><th>Message</th></tr>
</thead>
<tbody> </tbody>
</table>

<form id="chatForm" method="post" action="/sendMessage">
Nickname: <input id="nickname" type="text" /><br/>
Say: <input id="say" type="text" /><br/>
<input type="submit">
</form>

<script type="text/javascript">
function bindUI() {
$('chatForm').observe('submit', chatSubmit);
}

function chatSubmit(event) {
event.stop();
chat.send($F('nickname'), $F('say'));
}

dwr.engine.setActiveReverseAjax(true);
document.observe('dom:loaded', bindUI);
</script>
</body>
</html>


In your parancoe-servlet.xml file add the following configuration for enabling the active reverse AJAX in DWR:






Build and deploy your application. Open multiple windows of your browser(s) to <your_base_address>/chat.jsp, and start chatting:



Have fun with Parancoe!

Saturday, November 8, 2008

Parancoe 2.0

Last week the Parancoe Team (me and other smart people :) ) released the version 2.0 of the Parancoe meta-framework. With this release Parancoe achieved a great level of maturity.

In the next weeks, starting with this post, I will demonstrate how easy and pleasant is to develop applications with Parancoe.

First demonstration! :) How difficult is to start a new project with Parancoe? No difficult at all. Install Maven and type the following command:

mvn archetype:create -DarchetypeGroupId=org.parancoe \
-DarchetypeArtifactId=parancoe-webarchetype \
-DarchetypeVersion=2.0.1 \
-DgroupId=com.mycompany \
-DartifactId=testApp \
-DpackageName=com.mycompany.testapp

It will generate a new complete project ready for your next development. I repeat, complete, the new application is already working, you can build and deploy it on your application server and use it. You'll see a simple layout, administrative tasks, debug information in page (when deployed in development mode), user authentication and authorization, user management.

With a good IDE :) the start-up task is even easier. Watch this my previous, still valid, screen-cast.

Don't miss to read the new Parancoe Reference Guide, both in HTML and in PDF.

Have fun!

Monday, July 21, 2008

PDF Unencrypting

Updated 07/29/2008: added the copy of the bookmarks (index) from the original document.


Usually, when you buy a PDF book, it's encrypted and protected by a password. No problem, I agree with authors and publishers that need to protect their work, even if this technique is a very poor protection.

Unfortunately usually some portable readers, like my PRS-505, don't have encryption/password support, so you can't upload those PDFs on them.

So you need to unencrypt the PDF for reading it on the device, a perfectly legal operation if you legally bought the book.

The easiest way to unencrypt a PDF should be to use the pdftk command line tool:

pdftk abook.pdf input_pw your_password_here output abook_unencrypted.pdf

Unfortunately it always emits this error:

Error: Failed to open PDF file:
abook.pdf
OWNER PASSWORD REQUIRED, but not given (or incorrect)

Of course the password was correct and I tried with different combinations of input/owner/user password parameters. I think it's a bug of pdftk (version 1.41).

So I wrote a small Java program for unecrypting my files:

import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.SimpleBookmark;
import java.io.FileOutputStream;
import java.io.IOException;

public class Unencrypt {
public static void main( String[] args )
throws IOException, DocumentException {
String inFile = args[0];
String outFile = args[1];
String password = args[2];
PdfReader pdfReader = new PdfReader(inFile, password.getBytes());
Document document = new Document();
PdfCopy copy = new PdfCopy(document, new FileOutputStream(outFile));
document.open();
for (int i = 1; i <= pdfReader.getNumberOfPages(); i++) {
PdfImportedPage importedPage = copy.getImportedPage(pdfReader, i);
copy.addPage(importedPage);
}
copy.setOutlines(SimpleBookmark.getBookmark(pdfReader));
document.close();
pdfReader.close();
}
}
For executing it, download this file, and type:

java -cp bpdf.jar com.benfante.bpdf.Unencrypt \
abook.pdf abook_unencrypted.pdf \
your_password_here

*WARNING*: I'm not responsible of the use you can do of this code. It's not intended as a tool for infringing copyrights, just for reading PDFs you legally owns on devices that don't support encrypting.

Thursday, March 20, 2008

Start a new Web project with the Parancoe Web meta-framework and NetBeans 6.1

Starting new Web project using the Parancoe meta-framework is very easy and fast. Even more if you are using a good IDE. Watch at this screencast, in which I create a new project with Parancoe and NetBeans 6.1.










Download the screen cast at the maximum resolution.

Monday, October 15, 2007

JavaDay in Turin

Next Saturday I'll speak at the JavaDay in Turin.

My presentation will show that the following code can be a fully functional Data Access Object (DAO):

Note, not any other code or configuration to write, just that interface: NO code...NO bugs...more FUN! :)

See you in Turin...

(If you can't...look at the Parancoe site)

Monday, September 3, 2007

JUG Events

Estate abbastanza produttiva...sole, mare, spiaggia, ombrellone...e sviluppo di JUG Events!

Cos'è JUG Events? E' soprattutto la scusa per sperimentare con Parancoe, quindi principalmente con Hibernate/JPA, Spring, Spring MVC e Maven. Ma anche con JCaptcha, JavaMail, Velocity, Plextile, e chi più ne ha, più ne metta.

A parte la sperimentazione, che comunque ha portato nuove idee e sviluppo per Parancoe, l'applicazione può essere utile, quindi l'ho messa online a disposizione dei JUG che vorranno usarla:

www.jugevents.org

Se invece volete studiarne i sorgenti, li trovate nel repository Subversion di Parancoe.

Aggiornamento: JUG Events ha ora un proprio progetto separato per lo sviluppo su Google Code. jugevents.googlecode.com

Friday, July 27, 2007

Iterare il non iterabile in Java

Vi è mai capitato di avere un contenitore di oggetti, che però non sia implementato come Collection? A me purtroppo sì.

Abbondanti esempi li si trova nella libreria XOM. In tale libreria, ad esempio, il metodo Element.getChildElements() restituisce un oggetto Elements, che non è una Collection, ma ha semplicemente i metodi get(index) e size().

L'unico modo per iterare sugli elementi in esso contenuti è scrivere qualcosa del genere:

for(int i=0; i < elements.size(); i++) {
Element element = elements.get(i);
}

Dato che non implementa l'interfaccia Iterable, ad esempio, non si può usare il comodo "enhanced for" del JDK 5 per scrivere:

for(Element element: elements) {
// etc...
}

Per superare tale problema ho scritto la classe Iterabletor, che aggiunge ad una qualunque classe l'interfaccia e le capacità di un Iterable. Si può quindi scrivere:

Potete scaricare tutto il codice dal mio sito, nella mini-libreria Utilities.

Maggiori dettagli in questo post nel sito del JUG Padova.

Thursday, July 19, 2007

Spring Meeting 2007

Periodo intenso di conferenze. L'ultima a cui ho partecipato è stata a Cagliari, Spring Framework Meeting 2007, organizzata dallo Spring Framework Italian User Group in collaborazione con il JUG Sardegna.

In quest'occasione ho presentato un seminario dal titolo "Parancoe: usare i DAO senza implementarli", in cui ho mostrato come con Parancoe, che usa pesantemente lo Springframework, assieme ad Hibernate, si possa realizzare in pochissimo tempo e con pochissimo sforzo il layer di persistenza di una propria applicazione.

Qui le trasparenze della mia presentazione: http://snipurl.com/sm2007

Al meeting, in veste di speaker, erano presenti altri due membri del JUG Padova: Paolo Donà ed Enrico Giurin. Il primo ha svolto una presentazione su due caratteristiche recenti di Parancoe che ha sviluppato, ispirandosi a Ruby e RoR: fixtures, per il caricamento di dati nel DB durante i test e in installazione, e plugin, per aggiungere semplicemente funzionalità alle applicazioni sviluppate con Parancoe. Enrico invece ha descritto le funzionalità di ACEGI e il modo in cui tale libreria viene usata nel Plugin Security di Parancoe.

Il meeting, forse anche a causa del bel tempo che ha invogliato molti ad andare al mare, a sofferto di alcuni problemi organizzativi. Alcuni suggerimenti per gli organizzatori, per il prossimo anno:
  • pensare ad una giornata meno vacanziera
  • indicare meglio la sede, in modo che riesca a trovarla anche chi non è del posto
  • distribuire ai partecipanti un volantino con il programma (orario) della giornata, e magari le descrizioni dei vari seminari
  • ridurre i tempi di pausa
  • se i partecipanti previsti non sono molti, com'è stato, usare un'unica sala
  • pensare ad un "cane da guardia" per i relatori, in modo che inizino puntuali e non sforino (io, ad esempio, credo di avere abbondantemente sforato...ma in realtà non lo so, dato che non c'era nessuno che controllava il tempo, nemmeno io)
Ad ogni modo, un meeting in Sardegna vale la pena anche solo per la bellezza del luogo.
Purtroppo le mie foto sono pochissime e scattate con un telefonino. Decisamente meglio quelle di Paolo, oppure le foto di Massimiliano Dessì.

Spero che l'anno prossimo venga organizzato ancora, facendo tesoro dell'esperienza di quest'anno...e di riuscire di nuovo a parteciparvi. In bocca al lupo, e W la Sardegna!

PS: devo anche ringraziare Paolo che ci ha ospitato a casa sua, e la sua fantastica nonnina per i buonissimi carciofini sottolio. Un grazie anche a Massimiliano per il suo entusiasmo e per la volontà nell'organizzare questo evento.

Tuesday, July 3, 2007

Jazoon '07

La settimana scorsa ho partecipato a Jazoon '07, prima edizione di una conferenza dedicata alle tecnologie Java che si svolge a Zurigo.

Durante la conferenza, assieme ad altri due membri del JUG Padova, abbiamo presentato una demo su Parancoe, un meta-framework Web opensource con alcune caratteristiche innovative per accelerare lo sviluppo di applicazioni Web.

La conferenza è stata piuttosto interessante. Potete leggerne il mio resoconto nel sito del JUG.

Monday, March 12, 2007

Tomcat "castrato"

...ovvero come perdere una giornata di lavoro credendo che fosse colpa di LifeRay e invece era colpa di Tomcat. (ma anche LifeRay ci ha messo del suo)

Partiamo dalla soluzione, che è un po' più utile. Se usando Tomcat (5.5.20...ma anche 5.5.17, non ho provato gli altri) vi succede di non riuscire a usare le mail session configurate come risorse JNDI dato che facendone il lookup ricevete in risposta una bella ClassNotFoundException: org.apache.naming.factory.MailSessionFactory, la colpa non è vostra, ma di quei burloni che sviluppano Tomcat che si sono dimenticati di distribuirla. Tale classe dovrebbe trovarsi in common/lib/naming-factory.jar, ma viene inclusa solo se durante il build di Tomcat si è avuta l'accortezza di mettere nel classpath le JavaMail e il JavaBeans Activation Framework. Non so se questo sia voluto, visto che ormai si ripete da almeno 2 versioni, certo è che è una bella scocciatura.

Ho quindi dovuto ricompilare Tomcat dai sorgenti (5.5.20) per produrre un JAR contenente le factory mancanti. Dato che non è proprio semplicissimo, se volete evitarvi la fatica potete scaricarlo da qui:

http://snipurl.com/nfjar

Sostituitelo a quello presente in common/lib.

Il punto di partenza del problema è stato ancora più subdolo...da qui la giornata persa. Infatti stavo cercandi di far funzionare le mail session con LifeRay, usando ovviamente Tomcat come Servlet/JSP container. Il problema segnalato da LifeRay non era la tutto sommato chiara ClassNotFoundException, bensì una incomprensibile javax.naming.NameNotFoundException: Name mail is not bound in this Context. Ovviamente, controllando la console di amministrazione, il nome JNDI era definito! Il problema è che LifeRay cerca di "indovinare" il nome JNDI (che ovviamente cambia da server a server), ma facendo questo si perde (ignorandole e nascondendocele completamente) le vere cause dei problemi...quindi un'intera giornata persa cercando di configurare le risorse JNDI, quando invece bisognava "aggiustare" un JAR.

Per fortuna comunque che LifeRay è opensource e ho potuto esaminarne i sorgenti per capire la vera causa di questo errore, altrimenti sarebbe stato impossibile.