giovedì 12 febbraio 2015

Settare JDK su Ireport

Ireport attualmente non funziona se abbiamo installato la JDK 1.8.
La versione che ho provato io è la 4.7.0, non proprio l'ultimissima (siamo attualmente alla 5.5.0), comunque anche su quest'ultima leggo sui forum che ci sono problemi.
Io avevo installato la JDK 1.8 ma comunque ho nel path come prima entry quella della JDK 1.6 per cui ero convinto di girare comunque con la JDK 1.6 (anche la JAVA_HOME punta alla JDK 1.6).
Attenzione quindi, iReport prende la JDK da suoi ragionamenti interni ignorando le opzioni specificate a livello di sistema....

Avevo il seguente messaggio di errore (il file di log di Ireport si trova in Windows  sotto c:\Utenti\nomeutente\.ireport\4.7.0\var\log\messages.log )

java.lang.IllegalStateException: java.lang.IllegalAccessException: Class org.openide.util.WeakListenerImpl$ProxyListener can not access a member of class org.openide.filesystems.$Proxy0 with modifiers "public"

Per risolvere occorre modificare il seguente file ireport.conf che si trova sotto C:\Program Files\Jaspersoft\iReport-4.7.0\etc.

In particolare ho modificato la parte in grassetto

# ${HOME} will be replaced by user home directory according to platform
default_userdir="${HOME}/.${APPNAME}/4.7.0"
default_mac_userdir="${HOME}/Library/Application Support/${APPNAME}/4.7.0"

# options used by the launcher by default, can be overridden by explicit
# command line switches
default_options="--branding ireport -J-Xms256m -J-Xmx512m -J-Dorg.netbeans.ProxyClassLoader.level=1000 -J-XX:MaxPermSize=512m "
# for development purposes you may wish to append: -J-Dnetbeans.logger.console=true -J-ea

# default location of JDK/JRE, can be overridden by using --jdkhome <dir> switch
#
jdkhome="C:/Program Files/Java/jdk1.6.0_45"

# clusters' paths separated by path.separator (semicolon on Windows, colon on Unices)
#extra_clusters=



 

domenica 8 febbraio 2015

Javascript timer

Un contatore di secondi in Javascript:


<!DOCTYPE html>
<html>
<body>

<p>Script che starta un contatore:</p>

<p id="demo"></p>

<script>
var myVar=setInterval(function(){myTimer()},1000);
var cont=-1;
function myTimer() {
    var d = new Date();
    document.getElementById("demo").innerHTML =cont+myVar+" secondi trascorsi";
    cont=cont+1;
}
</script>

</body>
</html>


Risultato:

lunedì 12 gennaio 2015

Configurazione WAS 8.5 per chiamate HTTPS

Se da una applicazione Web richiamiamo un url di WebSphere e questa Url è in https allora è necessario importare il certificato dentro WebSphere.
Si noti che questo vale sempre, anche se ci si connette a siti trusted (es https://www.google.it).
Mi è capitato infatti che lo stesso codice funzionante su Tomcat 7 andasse in errore su Was 8.5.
L'eccezione in fase di chiamata era la seguente :

Error 500: javax.net.ssl.SSLHandshakeException: com.ibm.jsse2.util.j: PKIX path building failed: java.security.cert.CertPathBuilderException: PKIXCertPathBuilderImpl could not build a valid CertPath.; internal cause is: java.security.cert.CertPathValidatorException: The certificate issued by OU=Equifax Secure Certificate Authority, O=Equifax, C=US is not trusted; internal cause is: java.security.cert.CertPathValidatorException: Certificate chaining error 

Per risolvere occorre seguire i passaggi seguenti

1 - Da console WAS 8.5 Sicurezza/Gestione chiavi e certificati SSL






2 - Selezionare keystore e certificati



3 - Cliccare quindi su "Certificati firmatario"







4 - Selezionare NodeDefaultTrustore per accedere alla lista

5 - Selezionare l'opzione "Richiama da porta" e quindi inserire i dati del server, la porta (di solito la 443) e un alias che possiamo definire a piacere per il nome del trustore, quindi cliccare su Richiama Informazioni Firmatario per avere i dettagli del certificato





 Salvando questa configurazione, senza necessità di riavviare WAS 8.5 la chiamata all'url in https funziona correttamente.



venerdì 9 gennaio 2015

JAX-WS generare WSDL con xsd interni al WSDL

Di default JAX-WS genera l'xsd in un file esterno che poi è referenziato all'interno della sezione types del WSDL generato.
Questa opzione è sicuramente più corretta e rende migliore la lettura del WSDL ma può capitare di volere l'opzione opposta, ossia un WSDL contenente anche gli xsd.
A quanto ho visto qui fino alla versione 2.1 di JAX-WS non era possibile avere questo risultato (nb. la versione 2.1 è quella utilizzata di default da JAVA 1.6).
Dalla jax-ws 2.2 è finalmente possibile con il comando wsgen utilizzando l'opzione inlineSchemas in questo modo

wsgen -Xendorsed -verbose -inlineSchemas   -keep -cp .  it.myclass.MyService -wsdl
 

Tuttavia non sono riuscito a trovare un modo di avere lo stesso risultato deployando il web service su un Application Server.
Anche usando JAX.WS. versione 2.2 non trovo via codice un modo di forzare la generazione del servizio con xsd esterno.

mercoledì 7 gennaio 2015

Internalizzazione con Struts 1.3

Con la vecchia versione di Struts per realizzare l'internazionalizzazione occorre:

1) definire nello struts-config.xml l'elemento message-resources
2) definire un package con i file di properties, tenendo conto che il parameter impostato al punto 1 dovrà puntare al nome del file di properties senza estensione nè localizzazione
3) caricare in sessione nella variabile org.apache.struts.Globals.LOCALE_KEY il locale prescelto

Esempio

definisco un package denominato org.common.i18

con dentro 3 files:
  • messages.properties;
  • messages_en.properties;
  • messages_it.properties
Ogni file ha una proprietà soltanto

welcome.message=Benvenuto (DEF) per il messages.properties
welcome.message=Benvenuto (EN)  per il messages_en.properties
welcome.message=Benvenuto (IT) per il messages_it.properties

Nello struts config definiamo il seguente elemento:


<message-resources key="localeBundle" parameter="org.common.i18.messages">
</message-resources>

La key serve ad individuare univocamente il bundle e quindi consente di definirne più di uno.

Sulla prima action chiamata dall'applicazione si setta il locale in questo modo:


request.getSession().setAttribute(Globals.LOCALE_KEY, request.getLocale());


Nella jsp occorre importare la taglib di struts


<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean"%> 


Per accedere alla proprietà è sufficiente quindi scrivere:


<bean:message key="welcome.message" bundle="localeBundle" />


sabato 15 novembre 2014

Primefaces combo con immagine

Primefaces (sto utilizzando la versione 3.5, ma la sintassi da utilizzare è la stessa nella  attuale 5.1)  consente agevolmente l'utilizzo di componenti web complessi, come ad esempio una combo in cui associamo una immagine per ogni elemento (esempio tipico per la scelta della lingua con la bandiera corrispondente).
Di seguito il codice utilizzato, prendendo spunto dallo showcase di PF.

POJO PER RAPPRESENTARE L'ELEMENTO DELLA COMBO


package it.test.managedBeans;

import java.io.Serializable;

public class Language implements Serializable {
 
 private static final long serialVersionUID = 442345384294917624L;
 private String code;
 private String descr;
 private String urlPath;
 
 public int hashCode() {
     return this.code.hashCode()+this.descr.hashCode()+this.urlPath.hashCode();
   }
 
 public boolean equals(Object o){
  if(o instanceof Language && o!=null) {
   Language l=(Language)o;
   
   if(l.getCode()!=null && l.getDescr()!=null 
&& l.getUrlPath()!=null && l.getCode().equals(this.code) && l.getDescr().equals(this.descr) 
&& l.getUrlPath().equals(this.urlPath)){
    return true;
   }
   else
   {
    return false;
   }
  }
  else
  {
   return false;
  }
 }
 public Language(){
  
 }
 public Language(String code,String descr,String urlPath){
  this.code=code;
  this.descr=descr;
  this.urlPath=urlPath;
 }
 public String getCode() {
  return code;
 }
 public void setCode(String code) {
  this.code = code;
 }
 public String getDescr() {
  return descr;
 }
 public void setDescr(String descr) {
  this.descr = descr;
 }
 public String getUrlPath() {
  return urlPath;
 }
 public void setUrlPath(String urlPath) {
  this.urlPath = urlPath;
 }
 
}


MANAGED BEAN

package it.test.managedBeans;
import it.dao.LanguageRetrievalDao;
import it.daoImpl.LanguageRetrievalDaoImpl;
import it.object.Language;
import it.util.Utility;
import java.util.List;
import java.util.Locale;
import javax.annotation.PostConstruct;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
@ManagedBean(name="languageLoader")
@SessionScoped
public class LanguageLoader {
 
 private  String locale = Locale.getDefault().getDisplayLanguage();

    public void setLocale(String locale1) {
      this.locale = locale1;
    }

    public synchronized String getLocale() {
      return locale;
    }
 
  private List listaLingue;
 
  private Language linguaSelezionata=null;
  @PostConstruct
     public void init() {
   try
   {
    
    LanguageRetrievalDao ldao=LanguageRetrievalDaoImpl.getInstance();
    this.listaLingue=ldao.getListaLinguaggi();
    Language loc=ldao.getLanguageByCode("it");
    this.locale=loc.getCode();
   this.linguaSelezionata=loc;
   }
   catch(Exception ex){
    Utility.aggiungiMessaggioErrore(ex.getMessage());
   }
  }

 public List getListaLingue() {
  return listaLingue;
 }

 public void setListaLingue(List listaLingue) {
  this.listaLingue = listaLingue;
 }

 public Language getLinguaSelezionata() {
  return linguaSelezionata;
 }

 public void setLinguaSelezionata(Language linguaSelezionata) {
  this.linguaSelezionata = linguaSelezionata;
 }
  

  
 public void prova(ActionEvent ev){
   
  Utility.aggiungiMessaggioInformativo("E' stato selezionato il valore "+this.linguaSelezionata.getDescr());
  this.setLocale(this.linguaSelezionata.getCode());
 
 }
 
 public void prova3(){
   
  Utility.aggiungiMessaggioInformativo("E' stato selezionato il valore "+this.linguaSelezionata.getDescr());
  this.setLocale(this.linguaSelezionata.getCode());
  Locale.setDefault(new Locale(this.linguaSelezionata.getCode()));
 
 }
}



I due metodi prova e prova3 sono invocati il primo ad un onchange della combo, l'altro invece è un metodo invocato da un actionlistener.

ESEMPIO XHTML CON EVENTO CHE SCATTA ALL'ONCHANGE


<html xmlns="http://www.w3c.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"  xmlns:f="http://java.sun.com/jsf/core" 
xmlns:ui="http://java.sun.com/jsf/facelets"   xmlns:p="http://primefaces.org/ui"  xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<f:view contentType="text/html" locale="#{languageLoader.locale}">
<h:head >
</h:head>
<h:body> 
<h:form id="mainForm">
<br/>
<br/>
<br/>
 <p:growl id="msgs" showDetail="true"  />
<br/>
<br/>
<br/>
<br/>
<br/>
<br/>
<p:selectOneMenu value="#{languageLoader.linguaSelezionata}"  var="immagine">
<f:converter converterId="myComboLanguageConverter"></f:converter>
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{languageLoader.listaLingue}" var="lingua"
itemLabel="#{lingua.descr}" itemValue="#{lingua}"/>
<p:ajax event="change" update="msgs"  
                            listener="#{languageLoader.prova3}" /> 
<p:column>
<p:graphicImage value="/images/lang/#{immagine.urlPath}" width="40" height="50"/>
</p:column>
<p:column>
#{immagine.code} - #{immagine.descr}
</p:column>
</p:selectOneMenu>
</h:form>
 </h:body>
 </f:view>
</html>


ESEMPIO XHTML CON EVENTO SCATENATO DA PRESSIONE DI BOTTONE


<html xmlns="http://www.w3c.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"  xmlns:f="http://java.sun.com/jsf/core" 
xmlns:ui="http://java.sun.com/jsf/facelets"   xmlns:p="http://primefaces.org/ui"  xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<f:view contentType="text/html" locale="#{languageLoader.locale}">
<h:head >
</h:head>
<h:body> 
<h:form id="mainForm">
<br/>
<br/>
<br/>
 <p:growl id="msgs" showDetail="true"  />
<br/>
<br/>
<p:selectOneMenu value="#{languageLoader.linguaSelezionata}" id="combo1"  var="immagine">
<f:converter converterId="myComboLanguageConverter"></f:converter>
<f:selectItem itemLabel="Select One" itemValue="" />
<f:selectItems value="#{languageLoader.listaLingue}" var="lingua"
itemLabel="#{lingua.descr}" itemValue="#{lingua}"/>
<p:column>
<p:graphicImage value="/images/lang/#{immagine.urlPath}" width="40" height="50"/>
</p:column>
<p:column>
#{immagine.code} - #{immagine.descr}
</p:column>
</p:selectOneMenu>
<br/>
<p:commandButton actionListener="#{languageLoader.prova}" value="TEST"  update="msgs combo1"></p:commandButton>
<br/>
<br/>
<br/>
</h:form>
 </h:body>
 </f:view>
</html>


CONVERTER

Si noti che il converter si utilizza per trasformare l'oggetto in stringa e viceversa e non entra in gioco nella rappresentazione della combo stessa con le immagini ma negli eventi successivi al click del pulsante oppure al cambiamento della combo stessa.

package it.test.managedBeans;
import it.dao.LanguageRetrievalDao;
import it.daoImpl.LanguageRetrievalDaoImpl;
import it.object.Language;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
@FacesConverter("myComboLanguageConverter")
public class LanguageConverter implements Converter {

 @Override
 public Object getAsObject(FacesContext context, UIComponent
   component, String value) {
  LanguageRetrievalDao lr=LanguageRetrievalDaoImpl.getInstance();
  return lr.getLanguageByCode(value);
 }

 @Override
 public String getAsString(FacesContext context, UIComponent component, Object value) {
  if(value instanceof Language){
   return ((Language)value).getCode();
  }
  else
  {
   return "";
  }
  
 }

}



Attenzione è importantissimo nella selectOneMenu impostare l'itemValue direttamente con il valore dell'oggetto, non con il codice della lingua, infatti poi è il componente di primefaces che sfruttando i metodi equals ed hascode dell'oggetto Language associa correttamente immagini e descrizioni al codice dato ("it" oppure "en").

mercoledì 22 ottobre 2014

Inserire shared library su WAS 8.5

Per inserire una shared library su WAS 8.5
occorre entrare nella console di WebSphere cliccare su Ambiente/Librerie Condivise

Quindi creare una nuova libreria condivisa associando i 2 jar necessari comprensivi del percorso corretto

Esempio

 Ho specificato poi nell'ambito "Tutti gli ambiti" in modo che la mia shared library fosse visibile all'applicazione web di interesse.

A questo punto andare su applicazioni/Applicazioni Enterprise WebSphere e selezionare il progetto web di interesse.

Su Applicazioni Enterprise/NOME_WEB_APP/Riferimenti libreria condivisa
selezionare il nome della applicazione quindi andare su "Librerie condivise di riferimento".


Quindi occorre far ripartire la nostra applicazione che a questo punto avrà nel classpath la shared library.