mercoledì 17 giugno 2015

Errore schemaLocation: ... must have even number of URI's

Nei file xml di spring la voce xsi:schemaLocation specifica dove trovare gli xsd per i namespace definiti prima nel file.
Esempio:


<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:jdbc="http://www.springframework.org/schema/jdbc"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:batch="http://www.springframework.org/schema/batch"
 xmlns:context="http://www.springframework.org/schema/context"
 
 xsi:schemaLocation="http://www.springframework.org/schema/jdbc 
     http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
  http://www.springframework.org/schema/beans 
  http://www.springframework.org/schema/beans/spring-beans.xsd
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-4.0.xsd">


In questo caso su alcuni namespace è definita la locazione dell'xsd (non è obbligatorio che ci siano tutti).
E' però importante che le dichiarazioni seguano questo schema [NAMESPACE] [XSD_NAMESPACE], quindi il numero totale di dichiarazioni dovrà essere pari.

Se proviamo a cancellare una di queste voci allora apparirà l'eccezione

Error schemaLocation:....... must have even number of URI's

venerdì 5 giugno 2015

WebSphere (su windows) controllare versione

Per controllare esattamente la versione di WAS che si sta utilizzando posizionarsi via cmd sotto

C:\Program Files\IBM\WebSphere\AppServer\bin

e lanciare la bat versionInfo.bat.

Compariranno in console tutte le info relative all'installazione di WAS

domenica 3 maggio 2015

Spring esternalizzare configurazioni datasource e cifrare password

Scenario: abbiamo una applicazione Java che si connettead un db utilizzando Spring, vogliamo fare in modo che i dati della connettività siano spostati dal file di contesto di Spring ad un normale file di properties esterno al jar, in modo che l'utente possa personalizzarlo a seconda dell'ambiente di esecuzione senza dover toccare il file specifico del context di Spring.
Nel file di configurazione di Spring è possibile definire la seguente proprietà:

<context:property-override location="file:conf/db.properties"/>

Il file è letto in un percorso esterno rispetto al jar di esecuzione, come specificato appunto dalla direttiva file.

Il file esterno avrà una struttura di questo tipo (quella tipica di un file di properties):


dataSource.url=jdbc:sqlserver://localhost:1433;dataBaseName=hibernatetest
dataSource.username=pippo
dataSource.password=m4dr+75TW7u0nWFUU52IaQ==


Quindi nell'applicationContext.xml avremo la seguente definizione del dataSource:


 <bean id="dataSource"
  class="it.dao.BasicDataSourceCifrato">
  <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
  <property name="url" value="${dataSource.url}" />
  <property name="username" value="${dataSource.username}" />
  <property name="password" value="${dataSource.password}" />
  <property name="initialSize" value="5"></property>
  <property name="maxActive" value="10"></property>
 </bean>


Il datasource è stato ridefinito estendendo  org.apache.commons.dbcp.BasicDataSource .
In questo modo possiamo effettuare la ridefinizione del metodo setPassword inserendo la decifratura della password:


package it.dao;
import it.oasi.cipher.Cifratura;
import org.apache.commons.dbcp.BasicDataSource;
public class BasicDataSourceCifrato extends BasicDataSource {
 public BasicDataSourceCifrato() {
 }
 public synchronized void setPassword(String password) {     
        super.setPassword(decryptPassword(password));
    }
 private String decryptPassword(String password) { 
          // qui si inserisce la logica di decifratura pwd
          ...... 
 }

}


Spring Jdbc Template

In alcuni casi particolari risulta molto utile utilizzare per l'accesso al DBMS JDBC invece degli ORM (Hibernate,EBatis etc.), soprattutto in ambienti legacy dove il database è già esitente e non ottimizzato per l'utilizzo degli ORM.
Il problema di JDBC è comunque l'eccessiva verbosità del codice che ci costringe a gestire l'apertura delle connessioni, la chiusura, i PreparedStatement etc.
Una soluzione ideale in questo ambito è Spring Jdbc, che con il modello dei template ci esenta dal dover gestire manualmente il "plumbing code" JDBC.

Vediamo i passi da seguire per realizzare una applicazione client che si connette ad un db.

LIBRERIE

Ho utilizzato in questo caso spring 3.0
Le dipendenze maven sono le seguenti:


<properties>
 <org.springframework.version>3.0.0.RELEASE</org.springframework.version>
</properties>
 <dependencies>

  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-core</artifactId>
   <version>${org.springframework.version}</version>
  </dependency>
  <dependency>

   <groupId>org.springframework</groupId>

   <artifactId>spring-jdbc</artifactId>

   <version>${org.springframework.version}</version>

  </dependency>
  <dependency>
   <groupId>commons-dbcp</groupId>
   <artifactId>commons-dbcp</artifactId>
   <version>1.2.2</version>
  </dependency>
  <dependency>
   <groupId>commons-pool</groupId>
   <artifactId>commons-pool</artifactId>
   <version>1.4</version>
  </dependency>

 </dependencies>








FILE DI CONFIGURAZIONE

Il file di configurazione del context di Spring:

<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
 xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:task="http://www.springframework.org/schema/task"
 xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">


 <bean id="adUserDao" class="it.dao.AdUserDaoImpl">
  <property name="dataSource" ref="dataSource" />
 </bean>

 <bean id="dataSource"
  class="org.apache.commons.dbcp.BasicDataSource">

  <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
  <property name="url" value="jdbc:sqlserver://localhost:1433;dataBaseName=hibernatetest" />
  <property name="username" value="pippo" />
  <property name="password" value="pippo" />
  <property name="initialSize" value="5"></property>
  <property name="maxActive" value="10"></property>
 </bean>
 
</beans>


TABELLA

La tabella su cui si scrive e si legge ha il seguente script di creazione (DBMS Sql server versione 2008):


CREATE TABLE [dbo].[aduser](
 [id] [bigint] IDENTITY(1,1) NOT NULL,
 [name] [varchar](255) NOT NULL,
 [password] [varchar](255) NOT NULL,
 CONSTRAINT [PK_aduser] PRIMARY KEY CLUSTERED 
(
 [id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]



INTERFACCIA ADUSERDAO


package it.dao;
import java.util.List;
import it.objects.AdUser;
public interface AdUserDao {
 
 public boolean insert(AdUser obj) throws DaoException ;
 
 public AdUser getUserById(int id) throws DaoException;
 
 public List<AdUser> getListaUtenti() throws DaoException;

}


CLASSE ADUSER 

package it.objects;
public class AdUser {
 private static final String A_CAPO = "\r\n";
 private int id;
 private String nome;
 private String password;
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getNome() {
  return nome;
 }
 public void setNome(String nome) {
  this.nome = nome;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 public AdUser(){
  
 }
 public AdUser(String nome,String password){
  this.nome=nome;
  this.password=password;
  
 }
 public String toString(){
  StringBuffer sb=new StringBuffer();
  sb.append("ID: ");
  sb.append(this.id);
  sb.append(A_CAPO);
  sb.append("NOME: ");
  sb.append(this.nome);
  sb.append(A_CAPO);
  sb.append("PWD: ");
  sb.append(this.password);
  sb.append(A_CAPO);
  return sb.toString();
 }
}



IMPLEMENTAZIONE DAO 
package it.dao;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;
import it.objects.AdUser;
public class AdUserDaoImpl implements AdUserDao {
 private DataSource dataSource;
 private JdbcTemplate jdbcTemplate;
 public DataSource getDataSource() {
  return dataSource;
 }

 public void setDataSource(DataSource dataSource) {
  this.dataSource = dataSource;
 }

 public AdUserDaoImpl() {
  // TODO Auto-generated constructor stub
 }

 @Override
 public boolean insert(AdUser obj) throws DaoException {
  try
  {
   boolean retVal=false;
   jdbcTemplate=new JdbcTemplate(dataSource);
   String insert="insert into aduser(name,password) values (?,?)";
   int esito=jdbcTemplate.update(insert,new Object[]{obj.getNome(),obj.getPassword()});
   if(esito>0) retVal= true;
   return retVal;
  }
  catch(Exception ex){
   throw new DaoException("Errore nell'insert dettaglio "+ex.getMessage());
  }
 }

 @Override
 public AdUser getUserById(int id) throws DaoException {
  try
  {
   jdbcTemplate=new JdbcTemplate(getDataSource());
   String get="select id,name,password from aduser where id=?";
   AdUser retVal=jdbcTemplate.queryForObject(get,new Object[]{id}, new AdUserRowMapper());
   return retVal;
  }
  catch(Exception ex){
   throw new DaoException("Errore nel recupero dettaglio "+ex.getMessage());
  }
 }

 @Override
 public List<AdUser> getListaUtenti() throws DaoException {
  try
  {
   jdbcTemplate=new JdbcTemplate(getDataSource());
   String get="select id,name,password from aduser";
   List<AdUser> listaUtenti=new ArrayList<AdUser>();
   List<Map<String, Object>> rows =jdbcTemplate.queryForList(get);
    for (Map row : rows) {
     AdUser u=new AdUser();
     u.setId(Integer.parseInt(String.valueOf(row.get("ID"))));
     u.setNome((String)row.get("name"));
     u.setPassword((String)row.get("password"));
     listaUtenti.add(u);
    }
   return listaUtenti;
  }
  catch(Exception ex){
   throw new DaoException("Errore nel recupero dettaglio "+ex.getMessage());
  }
 }

}



ROWMAPPER 

Il RowMapper è una classe che implementa l'interfaccia di Spring org.springframework.jdbc.core.RowMapper e che serve a mappare il ResultSet con l'oggetto.

package it.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import it.objects.AdUser;
import org.springframework.jdbc.core.RowMapper;
public class AdUserRowMapper implements RowMapper<AdUser> {
 public AdUserRowMapper() {
  // TODO Auto-generated constructor stub
 }
 @Override
 public AdUser mapRow(ResultSet rs, int arg1) throws SQLException {
  // TODO Auto-generated method stub
  AdUser a=new AdUser();
  a.setId(rs.getInt("ID"));
  a.setNome(rs.getString("name"));
  a.setPassword(rs.getString("password"));
  return a;
 }

}



ESECUZIONE PROGRAMMA

 ConfigurableApplicationContext context=new ClassPathXmlApplicationContext("conf/applicationContext.xml");
   AdUserDao ad=(AdUserDao)context.getBean("adUserDao");
        AdUser user= ad.getUserById(1);
        System.out.println(user);
        List<AdUser> utenti=ad.getListaUtenti();
        for(AdUser a : utenti){
         System.out.println(a);
        }
        ad.insert(new AdUser("qweqw", "rrrrrrr"));
        context.close(); 

NOTE 

In questo caso abbiamo utilizzato la connessione da un pool gestito dalle librerie :

commons-dbcp-1.4.jar
commons-pool-1.4.jar

Si può anche decidere di utilizzare il DriverManagerDataSource di Spring che ci ritorna una connessione ogni volta che viene richiesta. Oppure il SingleConnectionDataSource che torna ogni volta la stessa connessione già utilizzata, come se si trattase di un pool di connessioni con size pari a 1.
Di seguito la configurazione per l'implementazione del DriverManagerDataSource:


<bean id="dataSource"
  class="org.springframework.jdbc.datasource.DriverManagerDataSource">

  <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
  <property name="url" value="jdbc:sqlserver://localhost:1433;dataBaseName=hibernatetest" />
  <property name="username" value="pippo" />
  <property name="password" value="pippo" />
 </bean>




mercoledì 29 aprile 2015

BAT per stop Tomcat clean directory e restart servizio

Con questo script è possibile stoppare tomcat ripulire le directory e fare il restart.
E' meglio utilizzare il comando NET START o NET STOP piuttosto che sc in quanto sc è asincrono per cui si rischia vada in errore la cancellazione dei file.
Lo script è il seguente:


    @echo OFF

    set CATALINA_HOME=D:\lavoro\apache-tomcat-7.0.53
    net stop TomcatService
   
    
    

    echo removing work
    rmdir /S /Q "%CATALINA_HOME%\work"
    echo making new work dir
    mkdir "%CATALINA_HOME%\work"
 
    echo removing temp
    rmdir /S /Q "%CATALINA_HOME%\temp"
    echo making new temp dir
    mkdir "%CATALINA_HOME%\temp"
 
    echo removing logs
    rmdir /S /Q "%CATALINA_HOME%\logs"
    echo making new logs dir
    mkdir "%CATALINA_HOME%\logs"
 
    echo starting tomcat service
  
    net start TomcatService


venerdì 17 aprile 2015

Verificare le porte di WebSPhere

WAS  utilizza porte diverse a seconda dell'accesso da console oppure da http o https.
Per verificare quali sono si può aprire il file

AboutThisProfile.txt che si trova tipicamente in

C:\Program Files\IBM\WebSphere\AppServer\profiles\[PROFILO]\logs

Il file presenta queste informazioni:


Ambiente del server delle applicazioni da creare: Server delle applicazioni
Ubicazione: C:\Program Files\IBM\WebSphere\AppServer\profiles\AppSrv01
Spazio su disco richiesto: 200 Mb
Nome profilo: AppSrv01
Imposta questo profilo come valore predefinito: True
Nome nodo: xxxxxxxx
Nome host: xxxxxxxxxxxx
Abilita sicurezza di gestione (consigliato): True
Porta della console di gestione: 9060
Porta sicura della console di gestione: 9043
Porta di trasporto HTTP: 9080
Porta di trasporto HTTPS: 9443
Porta di avvio: 2809
Porta connettore SOAP: 8880
Esegui il server delle applicazioni come servizio: True
Crea una definizione server Web: False
Impostazioni di ottimizzazione delle prestazioni: Standard



mercoledì 15 aprile 2015

PrimeFaces autoscroll dopo update eventi ajax

Spesso in form molto lunghi, quando si scrolla per la compilazione, l'utilizzo di Ajax può essere fastidioso perchè ad ogni esecuzione del codice poi sul client ci si riposiziona in alto e si perde lo scroll.
In javascript questo problema si risolve utilizzando la seguente sintassi:


document.getElementById("idComponente").scrollIntoView();


Dalla versione 3.2 di Primefaces è stato introdotto il metodo  
  RequestContext.getCurrentInstance().scrollTo

Purtroppo però non mi funzionava (stavo utilizzando la versione 3.5).
Comunque un workaround funzionante è quello di utilizzare sempre l'oggetto org.primefaces.context.RequestContext, inserendo il javascript dentro in questo modo:

 RequestContext.getCurrentInstance().execute("document.getElementById( 'componentId' ).scrollIntoView();");


Si noti che l'id deve essere quello generato dal componente a video, per capirci quello che vediamo col viewsource della pagina.