Author Archive

La vita del web designer è difficile…

Raramente mi è capito di mettere mano a codice web, nonostante mi interessi molto la maggior parte del codice che scrivo è Java nudo e crudo oppure C.
Quando capita però, mi rendo conto che la vita di un designer web è tutt’altro che facile. Lo so, per molti questo post sembrerà il classico “yet another state-the-obvious post” ma la frustrazione di dover adattare le cose perché qualcuno deliberatamente ha sfruttato la sua posizione dominante per fregarsene degli standard è alta…

Chi secondo voi se non Microsoft con il suo Internet Explorer 6?

Per esempio, il fatto che non supporti nativamente il formato PNG trasparente è veramente fastidioso. GIF non è minimamente paragonabile con le sue limitazioni ed allora ho dovuto creare una semplice condizione per cui chi utilizza Explorer 6 vedrà qualcosa di diverso:

<?php $agent = $_SERVER['HTTP_USER_AGENT'];
    if(eregi("msie 6.0",$agent)) { ?>

<a href="<?php bloginfo('url'); ?>">
   <img src="/immagini/logo_ie6.jpg" border="0" alt="" />
</a>

<?php }else{ ?>
<a href="<?php bloginfo('url'); ?>">
   <img src="/immagini/logo.png" border="0" alt="" />
</a>
<?php } ?>

C’è anche una soluzione lato client, utilizzando Javascript, che potete trovare a questo indirizzo, ma per il mio scopo di cambiare solo una immagine di testata è stata sufficiente la soluzione di prima, che non esegue nulla lato client.

Molti sono i browser in circolazione ed utilizzare la variabile ‘HTTP_USER_AGENT’ per distinguere l’uno dall’altro è la scelta più semplice, sebbene non sia affidabile: è possibile mascherare e cambiare tale variabile, alcuni proxy la filtrano… La soluzione? Solo il rispetto degli standard.

Fortunatamente browser come Firefox e Opera prendono piede sempre più, Chrome si arrampica ed Internet Explorer 7 anche sembra aver intrapreso la strada della standardizzazione.

Perdonate il tag

<?php>

ma il plugin che uso sembra avere ancora qualche problema. Vedremo se si potrà risolvere anche questo :)
Il plugin “CodeColorer” lo risolve egregiamente direi :D

Java – Esecuzione comandi su CLI parte II

Se vi ricordate di un pezzo di codice scritto da me e che funzionava particolarmente bene per invocare comandi su UNIX… Beh… Scordatevelo! O meglio, dovrete fare qualche piccola modifica.

Il codice in questione sembra, infatti, causare un piccolo problema chiamato deadlock.

La cosa non si presenta sempre, ma dipende fortemente dalla quantità di output che genera il comando e da come il sistema operativo gestisce il buffering della system call “write”. Lanciando truss da dentro al codice java, infatti, notavo che l’esecuzione delle system call si bloccava in attesa:

ioctl(1, TCGETA, 0xFFBEDF34) Err#22 EINVAL
fstat64(1, 0xFFBEDFA8) = 0
brk(0x00068A70) = 0
brk(0x0006AA70) = 0
write(1, " D A T A ".., 5120) = 5120
write(1, " * - &gt; *".., 5120) = 5120
llseek(0, 0, SEEK_CUR) Err#29 ESPIPE
write(1, " * - &gt; * * * * * ".., 635) (sleeping...)

Non è stato facilissimo arrivare alla causa, il metodo è infatti molto semplice, ma adesso che ho identificato il problema l’errore appare quasi evidente. Il problema risiede infatti nel canale di standard error letto prima dello standard output:

  1. Prima di poter leggere lo standard error è necessario che il processo che esegue il comando termini, e non è detto che vi siano errori;
  2. Prima di poter avere tutto l’output disponibile c’è bisogno di qualcuno che consumi i dati nel buffer, ma quel qualcuno è in attesa sullo standard error;
  3. Deadlock!

Sinceramente, questa spiegazione, seppur sensata non mi convince ancora appieno e appena avrò più tempo analizzerò meglio i trace delle system call, nonostante ciò riporto di seguito la versione del metodo che risolve il problema.

public static String execCommand(String cmd) throws IOException{
String result = null;
String temp = null;
BufferedReader stdout = null;
BufferedReader stderr = null;

Process proc = Runtime.getRuntime().exec(cmd);

/*consume the output*/
stdout = new BufferedReader(new InputStreamReader(
proc.getInputStream()));
temp = stdout.readLine();

while(temp!=null){
if(result==null)
result = temp+”\n”;
else
result += temp+”\n”;
temp = stdout.readLine();
}

stdout.close();

/*check if errors occurred*/
stderr = new BufferedReader(new InputStreamReader(
proc.getErrorStream()));
temp = stderr.readLine();

if(temp!=null){
result = temp+”\n”;
temp = stderr.readLine();
while(temp!=null){
result += temp+”\n”;
temp = stderr.readLine();
}

stderr.close();
throw new IOException(result);
}

stderr.close();
/*if no exceptions occurred then proceed to return the output*/
return result;
}

Questo è quanto, il metodo main d’esempio del post precedente però è ancora valido :)

Statement vs PreparedStatement

Quando frequentavo l’università mi chiedevo quale fosse effettivamente la differenza tra uno Statement e un PreparedStatement Java. Fondamentalmente mi permettevano di raggiungere lo stesso risultato in maniera lievemente diversa.

In realtà i due costrutti sono molto più diversi di quanto non si creda. Ogni comando SQL ricevuto dal DBMS viene elaborato seguendo 3 fasi:

  1. Compilazione (parsing del comando SQL);
  2. Esecuzione;
  3. Fetching (restituzione del risultato al client).

Supponendo che vengano eseguite molte operazioni, la classe PreparedStatement permette di eseguire il passo di compilazione una sola volta, la prima, e poi di aggiornarne i valori in seguito:

PreparedStatement pstmt = conn.prepareStatement(
         "SELECT * FROM TABELLA WHERE CAMPO = ?");
Iterator ricerca = lista.iterator();
while(ricerca.hasNext()){

   pstmt.setString(1, (String)ricerca.next());
   ResultSet rs = pstmt.executeQuery();

   while(rs.next()){
      //Get results
   }
   //...
}

Questo si concretizza in un miglioramento delle performance, generalmente. Ciò non è sempre vero, ci sono altri fattori che entrano in gioco che possono rendere uno Statement più veloce di un PreparedStatement. A mio avviso anche se fosse, una leggera diminuzione di performance (che dipende moltissimo dal database utilizzato) per il PreparedStatement è sicuramente ben accetta data la sua grande flessibilità. Non solo, dalle FAQ Oracle ho appreso anche che ci sono dei benefici in termini di sicurezza nell’utilizzo di PreparedStatement: il binding dei dati, infatti, eviterebbe un considerevole numero di attacchi di tipo SQL Injection. La FAQ infatti riporta:

“Statements may be slightly faster if you are only going to execute the SQL once. PreparedStatements are much faster when the SQL will be executed more than once. If you are using the statement cache, which you should, getting a statement from the cache is the same as executing the same statement.

In general we strongly recommend that you use PreparedStatements. This is especially true if you are sending user provided data in the SQL. By binding the data to a PreparedStatement parameter you can prevent most SQL injection attacks. Any performance advantage of using Statements is negligible.”

Insomma, per i miei gusti, non c’è motivo di usare Statement e PreparedStatement è la classe vincente.

Java – Esecuzione comandi su CLI

Prima o poi può essere utile astrarre un po’ meno dalla macchina e tornare a interfacciarsi con il Sistema Operativo sottostante. Quello che può tornare utile è quindi un metodo per eseguire comandi di sistema dalla VirtualMachine Java. Il seguente è un metodo che ho scritto in fretta e furia, ma che su sistemi UNIX sembra funzionare molto molto bene:

public static String execCommand(String cmd) throws IOException{
   String result = null;
   BufferedReader stdout = null;
   BufferedReader stderr = null;
   Runtime runtime = null;
   Process proc = null;

   runtime = Runtime.getRuntime();
   proc = runtime.exec(cmd);
   stderr = new BufferedReader(new InputStreamReader(
                                          proc.getErrorStream()));
   String temp = stderr.readLine();

   /*check if errors occurred*/
   if(temp!=null){
      do{
         if(result==null)
            result = temp+"\n";
         else
            result += temp+"\n";

         temp = stderr.readLine();
      }while(temp!=null);

      stderr.close();
      throw new IOException(result);
   }

   /*if no exceptions occurred then proceed to return the output*/
   stdout = new BufferedReader(new InputStreamReader(
                                           proc.getInputStream()));
   temp = stdout.readLine();

   while(temp!=null){
      if(result==null)
         result = temp+"\n";
      else
         result += temp+"\n";
      temp = stdout.readLine();
  }

  stdout.close();
  return result;
}

L’idea è semplice: se il comando fallisce, restituisco l’esito del comando (lo standard error) come un’eccezione di I/O, altrimenti il metodo torna l’esito del comando (lo standard output).

A questo punto possiamo, per esempio, scrivere il seguente main, un po’ inutile, ma rende l’idea

public static void main(String args[]){
   try{
      String result = execCommand("ls -lrt");
      System.out.println(result);
   }catch(IOException e){
      System.err.println(e.getMessage());
   }
}

Ovviamente il codice non è ottimizzato essendo la prima stesura di getto, alcune cose potevano essere evitate (i due BufferedReader per esempio), ma spero che a qualcuno questo metodo torni utile.

Dopo iWork ’09 anche Photoshop CS4…

Bisognava aspettarselo e molto probabilmente ci saranno anche altri prodotti compromessi. Il trojan è il OSX.Trojan.iServices.B e come spiega anche MacWorld:

“The crack application installs a backdoor in the /var/tmp directory, copies an executable to /usr/bin/DivX and saves the root hash password in the file /var/root/.DivX, according to Intego. It then listens on a random TCP port and attemps to make repeated connections to two IP addresses. Intego concludes that the creator of the malware intends to be alerted through this method and may have the ability to connect to affected Macs and perform various actions remotely”

Non troppo tempo fa era apparsa, sul sito del supporto Apple, una pagina che consigliava l’utilizzo di software di protezione. La pagina risale al 2007, ma fu aggiornata anche nello scorso novembre. Lo scalpore generato, che definirei anche smisurato, fece sì che la pagina fosse rimossa… Forse era meglio tenerla, visto che i virus non sono l’unica minaccia circolante…

Chi non si ricordasse della vicenda può informarsi su questo link .

Trojan in iWork ’09

Ebbene, come spiego spesso a molti miei amici, il solo sistema operativo non garantisce la sicurezza, è soprattutto la consapevolezza di chi lo usa e gli accorgimenti che adotta che rendono il sistema una “roccaforte”.

Secondo Engadget esiste una versione di iWork ’09 pirata, scaricata da diverse migliaia di utenti, che conterrebbe al suo interno un Trojan (OSX.Trojan.iServices) che guadagnerebbe accesso con permessi di root alla macchina OSX su cui è installato. Ciò permette l’accesso remoto alla macchina con la possibilità di installare componenti e manipolare le applicazioni già esistenti.

Da MacWorld (fonte dalla quale la notizia di engadget blog è tratta) ecco come controllare se si è infetti o meno:

“To check if you’ve been infected, look in /System/Library/StartupItems for an item named iWorkServices. If it exists, you’ve been infected with this Trojan horse.”

Ed ecco qual’è la vera differenza tra software “OpenSource/ClosedSource” e tra “gratuito/a pagamento”: dov’è la necessità di scaricare materiale pirata se liberamente disponibile? Quanto tempo si sarebbe impiegato ad identificare il trojan se il codice fosse stato open? Con questo non metto in dubbio l’elevata qualità dei prodotti Apple, è chiaro, manifesto solo i lati che apprezzo del software opensource.

Oracle 10g – Upsert

Recentemente mi è capitato di dover eseguire una insert or update, anche detta upsert, su Oracle 10g. Su MySQL ero solito usare la forma “INSERT … ON DUPLICATE KEY UPDATE …” che funziona piuttosto bene, ma che non era supportata dal database che stavo utilizzando.

La versione 10g di Oracle, però, supporta l’operazione “MERGE”, entrata a far parte dello standard SQL nel 2003, e si è rivelata molto comoda utilizzandola tramite JDBC.

Supponiamo di dover memorizzare in una tabella l’ultima pagina visitata da un utente in un dato giorno, possiamo utilizzare il seguente prepared statement java:

PreparedStatement pstmt = conn.prepareStatement(
"MERGE INTO last_page_table dst "+
   "USING ( "+
"SELECT \'"+username+"\' USER_ID, "+
   "TO_DATE(\'"+
      new java.sql.Date(System.currentTimeMillis())+
   "\'YYYY-MM-DD')  DATE_FIELD, "+
   "\'"+lastPage+"\' LAST_PAGE "+
"FROM DUAL) src "+
   "ON (dst.USER_ID = src.USER_ID AND "+
      "dst.DATE_FIELD = src.DATE_FIELD) "+
"WHEN MATCHED THEN "+
   "UPDATE SET dst.LAST_PAGE = src.LAST_PAGE "+
"WHEN NOT MATCHED THEN "+
   "INSERT (dst.USER_ID, "+
      "dst.DATE_FIELD, "+
      "dst.LAST_PAGE) "+
  "VALUES (src.USER_ID, "+
      "src.DATE_FIELD, "+
      "src.LAST_PAGE)");

In sostanza, l’operazione “MERGE” funziona tra tabelle, prende i valori di una e li inserisce o aggiorna nell’altra in base al matching della condizione nella clausola “ON”.
Tuttavia, la necessità non era di utilizzare valori preesistenti di una tabella ed inserirli o aggiornarli nell’altra, ma l’effettivo popolamento della tabella. Esigenza risolta appoggiandosi alla tabella “DUAL”.
Ovviamente, invece di inserire direttamente nella stringa i valori necessari, si poteva utilizzare anche il ‘?’ e chiamare poi le funzioni della classe PreparedStatement.

PreparedStatement pstmt = conn.prepareStatement(
"MERGE INTO last_page_table dst "+
   "USING ( "+
"SELECT ? USER_ID, ?  DATE_FIELD, ? LAST_PAGE "+
   "FROM DUAL) src "+
   "ON (dst.USER_ID = src.USER_ID AND "+
      "dst.DATE_FIELD = src.DATE_FIELD) "+
   "WHEN MATCHED THEN "+
      "UPDATE SET dst.LAST_PAGE = src.LAST_PAGE "+
   "WHEN NOT MATCHED THEN "+
      "INSERT (dst.USER_ID, "+
         "dst.DATE_FIELD, "+
         "dst.LAST_PAGE) "+
      "VALUES (src.USER_ID, "+
         "src.DATE_FIELD, "+
         "src.LAST_PAGE)");

Se non vi sono particolari necessità in termini di performance, sicurezza, flessibilità, in genere preferisco inserire tutto direttamente nella stringa in modo da poterla scrivere facilmente su un file di log prima di inviarla al driver:

String sqlMerge = "MERGE INTO ...";
PreparedStatement pstmt = conn.prepareStatement(sqlMerge);
logger.debug("Executing "+sqlMerge);
pstmt.executeUpdate();

Antialias dei caratteri su aMsn

Recupero una parte di un vecchio tutorial che sembra interessare molti utenti del pinguino. Su linux esistono diversi client per utilizzare MSN, il protocollo di IM (Instant Messaging) di casa Microsoft.

Nonostante abbia ormai definitivamente scelto Pidgin come client (in quanto multiprotocollo), aMsn è sempre stato un ottimo prodotto opensource. La versione in sviluppo, che si può ottenere da SVN, supporta tra le varie anche l’antialiasing dei caratteri, caratteristica offerta dalle librerie TCL/TK.  Dopo aver installato da SVN su archlinux con

yaourt -S amsn-svn

ed avviato, mi veniva  richiesto TLS e utilizzando il wizard non sono riuscito ad ottenerlo funzionante. La soluzione è semplice:
modificare il file /usr/lib/tls1.50/pkgIndex.tcl sostituendo tls 1.5 con tls 1.50 in modo che la riga risultante sia la seguente:

package ifneeded tls 1.50 "[list load [file join $dir .. libtls1.50.so] ] ; [list source [file j
oin $dir tls.tcl] ]"

indicando ora nelle preferenze di amsn (sulla scheda avanzate) la directory di TLS dovreste avere tutto perfettamente funzionante.

Hello world!

Perché non iniziare col più classico dei messaggi anche qui? Mi ricordo il mio primo programma, come quello di quasi tutti penso, il classico “hello world!” in ogni parte del mondo si inizia così:

int main(void)
{
printf("Hello world!\n");
return 0;
}

a seconda del linguaggio con cui si inizia ovviamente… Per me fu il Pascal, ma il C fu il linguaggio che mi appassionò di più.