lunedì 10 giugno 2013

Sql Server ottenere le constraint di una tabella

Di seguito una query per ottenere le informazioni su tutti i constraint di una tabella


SELECT 
     t.Name as NOME_TABELLA,
    c.Name as NOME_COLONNA,
    dc.Name as NOME_CONSTRAINT,
    dc.definition as VALORE
FROM sys.tables t
INNER JOIN sys.default_constraints dc ON t.object_id = dc.parent_object_id
INNER JOIN sys.columns c ON dc.parent_object_id = c.object_id 
AND c.column_id = dc.parent_column_id 
where t.NAME='?';


venerdì 7 giugno 2013

Java lanciare un file .bat da una web app

Per lanciare un file .bat da una web application , oltre al comando nativo

java.lang.Runtime.getRuntime().exec("cmd /c ....");


è possibile utilizzare la libreria commons.exec (qui un tutorial sull'utilizzo).
Io ho utilizzato la versione 1.1..
Nel mio caso era necessario solo invocare il batch senza intercettare il risultato, ed ho fatto in questo modo (la jsp passava in un parametrochiamato batchVal il nome del .bat da invocare):

private void gestisciRichiesta(HttpServletRequest request,
   HttpServletResponse response) throws ServletException, IOException {
  try
  {
     String batchDaInvocare=request.getParameter("batchVal");
     log.info("Parametro inviato: "+batchDaInvocare);
     CommandLine commandLine = new CommandLine(batchDaInvocare );
     DefaultExecutor executor = new DefaultExecutor();
     executor.setExitValue( 0 );
     executor.execute( commandLine );
  request.setAttribute("richiestaBatchInviata", "La richiesta di avvio batch alert è stata trasmessa al server, attendere la mail di risposta prima di verificare i risultati");
  }
  catch(Throwable t)
  {
   request.setAttribute("error", "Attenzione si è verificato un errore nell'invocazione del batch, messaggio "+t.getMessage()+" errore di tipo "+t.getClass().getName());
  }
  finally{
   RequestDispatcher rd=request.getRequestDispatcher("index.jsp");
   rd.forward(request, response);
  }
 }

Comunque con la libreria di apache è agevole anche il passaggio dei parametri il parsing dell'output.
Ad esempio si possono passare dei parametri invocando il mentodo addArgument sull'oggetto Command per aggiungere dei parametri al batch etc.

martedì 4 giugno 2013

Internazionalizzazione JSF 2.0

Utilizzando JSF 2.0 (io sto usando come implementazione Mojarra) per l'internazionalizzazione bastano 2 passaggi:
  1. Creare i propri file di properties e posizionarli dove si vuole nel proprio workspace;
  2. Referenziare tale file di properties all'interno del faces-config, associando all'identificazione un nome;
  3. Referenziare all'interno dell'xhtml il nome definito al punto 2 in corrispondenza del punto in cui si vuole inserire il messaggio.
Esempio: supponiamo di aver inserito un semplice file di properties denominato message.properties all'interno del package resources del progetto.

FACES-CONFIG

 <application>
<locale-config>
<default-locale>it</default-locale>
<supported-locale>en</supported-locale>
</locale-config>
<resource-bundle>
<base-name>resources.messages</base-name>
<var>msg</var>
</resource-bundle>
</application>


Si noti che bisogna indicare nel base name il percorso del file comprensivo del package e il nome file generico.
Se all'interno del package resources inserissi anche un file denominato message_it.properties poichè it è il default locale avrei precedenza rispetto al generico message.properties.

XHTML

All'interno dell'xhtml la referenziazione alla variabile msg consente in maniera trasparente l'accesso alla proprietà, in questo modo (qui lo usiamo all'interno del p:commandButton di prime faces:


 <p:commandButton update="nomeIdColl cognomeIdColl cfIdColl" 
action="#{soggetto.valorizzaDatiIdentificazione}" icon="ui-icon-check" 
value="#{msg['miachiave']}" ></p:commandButton>


lunedì 3 giugno 2013

JAVA connettersi ad un DSN

Per connettersi ad un DSN (parliamo quindi di ambiente Windows):


import java.sql.DriverManager;
public static void main(String[] args) {
Connection con = null;
     try {
       Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;
       con = DriverManager.getConnection("jdbc:odbc:NOME_DSN","uname","pwd");
       System.out.println("DSN Connection ok.");
       con.close();

     } catch (Exception e) {
       System.err.println("Errore: "+e.getMessage());
     }

 }


sabato 1 giugno 2013

Web Service autenticazione token profile con parsing dell'header tramite SAAJ

Nel seguente esempio vediamo come abilitare la sicurezza in modalità token profile su un Web Service sfruttando per il parsing dell'header le api della libreria SAAJ.
Vediamo il servizio (volutamente banale)

import javax.jws.HandlerChain;
import javax.jws.WebService;
@WebService
@HandlerChain(file="handlers.xml")
public class HelloWorld {
public String saluta(String nome){
 return "Ciao "+nome;
}
}


Possiamo vedere come nell'annotation HandlerChain si specifica il file dove sarà definito l'handler di sicurezza; tale handler provvede a leggere username e password dall'header soap.
L'handler è di tipo SOAPHandler, ossia è in grado di leggere e gestire la sezione di header, deputata all'inserimento dei dati di autenticazione.
Vediamo il codice dell'handler

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.soap.Node;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFault;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPFaultException;
/**
 * Controlla user name e password
 * @author 
 *
 */
public class ServerHandler implements SOAPHandler {

 private static final String LoggerName = "ServerSideLogger";
 private static boolean trace=true;
 private Logger logger;
 private final boolean log_p = true; 
 public ServerHandler(){
  logger = Logger.getLogger(LoggerName);
 }
 @Override
 public void close(MessageContext context) {
  
 }

 @Override
 public boolean handleFault(SOAPMessageContext context) {
  return true;
 }

 @Override
 public boolean handleMessage(SOAPMessageContext ctx) {
  Boolean response_p = (Boolean)
    ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
    // Handle the SOAP only if it's incoming.
    if (!response_p) {
    try {
    SOAPMessage msg = ctx.getMessage();
    SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
    SOAPHeader hdr = env.getHeader();
    String user="";
    String password="";
    // Ensure that the SOAP message has a header.
    if (hdr == null)
    generateSOAPFault(msg, "Attenzione manca la parte header del messaggio soap");
    
    Iterator it =hdr.extractHeaderElements(SOAPConstants.URI_SOAP_ACTOR_NEXT);
    if (it == null || !it.hasNext())
     generateSOAPFault(msg, "Attenzione header non corretto");
     Node next = (Node) it.next();
     if(!"user".equals(next.getNodeName())){
      generateSOAPFault(msg, "attenzione header non corretto");
     }
     else
     {
      user=next.getValue();
      logger.info("Username: "+user);
     }
     if (it == null || !it.hasNext())
      generateSOAPFault(msg, "Attenzione header non corretto"); 
     Node pnode=(Node)it.next();
     if(!"pwd".equals(pnode.getNodeName())){
      generateSOAPFault(msg, "attenzione header non corretto");
     }
     else
     {
      password=pnode.getValue();
     }
     if(!("kermit".equals(user) && "thefrog".equals(password))){
      logger.info("Attenzione errore nelle credenziali di accesso");
      generateSOAPFault(msg, "Attenzione errore nelle credenziali di accesso");
     }
     
     if (trace) msg.writeTo(System.out);
    }
    catch(SOAPException e) { System.err.println(e); }
    catch(IOException e) { System.err.println(e); }
     
    }
    return true;
 }

 @Override
 public Set getHeaders() {
  // TODO Auto-generated method stub
  return null;
 }

 private void generateSOAPFault(SOAPMessage msg, String reason) {
  try {
  SOAPBody body = msg.getSOAPPart().getEnvelope().getBody();
  SOAPFault fault = body.addFault();
  fault.setFaultString(reason);
  throw new SOAPFaultException(fault);
  }
  catch(SOAPException e) { }
  }
}



Nel metodo handle message si recuperano username e password dall'header confrontandole con dei valori cablati nel codice (nella realtà ovviamente ci sarà un invocazione ad un db o un servizio LDAP).
Per pubblicare velocemente il servizio possiamo utilizzare le api della jdk 6, in particolare la classica EndPoint.publish.


Endpoint.publish("http://127.0.0.1:8089/Verifica", new HelloWorld());

Possiamo già testare il servizio con un client tipo SOAP UI. Se lo invochiamo senza inserire nulla nella sezione header avremo il seguente messaggio di errore:

<S:Fault xmlns:ns3="http://www.w3.org/2003/05/soap-envelope">
         <faultcode>S:Server</faultcode>
         <faultstring>Attenzione header non corretto</faultstring>
      </S:Fault>



Se invece effettuiamo una chiamata correttamente, ossia così:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://servizio.it/">
   <soapenv:Header>
<user xmlns="http://ch03.fib" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">kermit</user>
<pwd xmlns="http://ch03.fib" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next">thefrog</pwd>
</soapenv:Header>
   <soapenv:Body>
      <ser:saluta>
         <!--Optional:-->
         <arg0>carlo</arg0>
      </ser:saluta>
   </soapenv:Body>
</soapenv:Envelope>


La risposta in soap ui è la seguente:

<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
   <S:Body>
      <ns2:salutaResponse xmlns:ns2="http://servizio.it/">
         <return>Ciao carlo</return>
      </ns2:salutaResponse>
   </S:Body>
</S:Envelope>


Vediamo come scrivere ora un client java per il servizio. Dovremo dichiarare un handler che gestisca il messaggio in invio, scrivendo la sezione di autenticazione nell'header.

import java.io.IOException;
import java.util.Set;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
/**
 * Controlla user name e password
 * @author 
 *
 */
public class ClientHandler implements SOAPHandler {

 private static final String LoggerName = "ClientSideLogger";
 private static final String USER_NAME="kermit";
 private static final String PASSWORD="thefrog";
 private Logger logger;
 private final boolean log_p = true; 
 public ClientHandler(){
  logger = Logger.getLogger(LoggerName);
 }
 @Override
 public void close(MessageContext arg0) {
  if (log_p) logger.info("close");  
 }

 @Override
 public boolean handleFault(SOAPMessageContext ctx) {
  if (log_p) logger.info("handleFault");
  try {
  ctx.getMessage().writeTo(System.out);
  }
  catch(SOAPException e) { System.err.println(e); }
  catch(IOException e) { System.err.println(e); }
  return true;
 }

 @Override
 public boolean handleMessage(SOAPMessageContext ctx) {
  if (log_p) logger.info("handleMessage");
  Boolean request_p = (Boolean)
  ctx.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
  if (request_p) {
  try {
  SOAPMessage msg = ctx.getMessage();
  SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
  SOAPHeader hdr = env.getHeader();
  if (hdr == null) hdr = env.addHeader();
  QName qname = new QName("http://ch03.fib", "user");
  SOAPHeaderElement helem = hdr.addHeaderElement(qname);
  helem.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT); // default
  helem.addTextNode(USER_NAME);
  QName pqname=new QName("http://ch03.fib", "pwd");
  SOAPHeaderElement pelem=hdr.addHeaderElement(pqname);
  pelem.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT);
  pelem.addTextNode(PASSWORD);
  msg.saveChanges();
  msg.writeTo(System.out);
  }
  catch(SOAPException e) { System.err.println(e); }
  catch(IOException e) { System.err.println(e); }
  }
  return true; // continue down the chain
 }

 @Override
 public Set getHeaders() {
  if (log_p) logger.info("getHeaders");
  return null;
 }
}

A questo punto, dopo aver generato il client Java al servizio tramite il comando wsimport, prima di effettuare la chiamata è necessario settare da codice l'handler, sfruttando la proprietà setHandlerResolver della classe HelloWorldService generata dal wsimport, in questo modo:

import it.handlers.ClientHandler;
import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
public class CallService {

 public static void  main(String[] args){
  HelloWorldService servizio=new HelloWorldService();
  servizio.setHandlerResolver(new ClientHandlerResolver());
  System.out.println(servizio.getHelloWorldPort().saluta("muttillo"));
 }
}
class ClientHandlerResolver implements HandlerResolver {
 public List getHandlerChain(PortInfo port_info) {
  List hchain = new ArrayList();
  hchain.add(new ClientHandler());
  //hchain.add(new TestHandler()); // for illustration only
  return hchain;
 }
}



giovedì 30 maggio 2013

Capire dal .class la java version

I compilati Java, con estensione .class, hanno una struttura iniziale che ci consente di capire con quale java version sono stati compilati.
Tutti i .class iniziano con la sequenza 0xCAFEBABE, detto magic number, il numero esadecimale che consente di capire il formato del file.
Sulla storia di questo magic number sono raccontate in rete storie divertenti, secondo Wikipedia inglese pare che tutto venga da un caffè frequentato dai Grateful Dead (http://en.wikipedia.org/wiki/Java_class_file).
Dopo il magic number c'è l'identificativo di versione major e minor.
I valori del major identificano la versione e sono i seguenti:
46 -> java 1.2
47-> java 1.3
48-> java 1.4
49-> java 1.5
50 -> java 1.6
51-> java 1.7

Di seguito incollo il testo di una classe Java che dato un file .class restituisce la versione Java.


package it.test;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
public class CheckCompiledVersion {
 static Map myMap=null;
 private static CheckCompiledVersion istanza;
 private CheckCompiledVersion(){
  
 }
 public static CheckCompiledVersion getInstance(){
  if(istanza==null){
   istanza=new CheckCompiledVersion();
  }
  return istanza;
 }
 static
 {

      myMap=new HashMap();
      myMap.put(46, "Java 1.2");
      myMap.put(47, "Java 1.3");
      myMap.put(48, "Java 1.4");
      myMap.put(49, "Java 1.5");
      myMap.put(50, "Java 1.6");
      myMap.put(51, "Java 1.7");
 }
 public static void main(String[] args) throws IOException {
  System.out.println(CheckCompiledVersion.getInstance().checkClassVersion("out/Myfile.class"));
 }

 public String checkClassVersion(String filename)
         throws IOException
     {
         DataInputStream in = new DataInputStream(new FileInputStream(filename));
         int magic = in.readInt();
         if(magic != 0xcafebabe) {
           return filename + " non è un .class";
         }
         int minor = in.readUnsignedShort();
         int major = in.readUnsignedShort();
         System.out.println(filename + ": " + major + " . " + minor);
         in.close();
         return myMap.get(major);
     }
}


sabato 18 maggio 2013

UDDI

L'UDDI (acronimo di Universal Description Discovery and Integration) è un registry (ovvero una base dati ordinata e indicizzata), basato su XML e indipendente dalla piattaforma hardware, che permette alle aziende la pubblicazione dei propri dati e dei servizi offerti su internet. (cit. wikipedia)

  UDDI include un  XML Schema che descrive 4 tipi di informazioni principali:
  • businessEntity (include informazioni sul business name,la descrizione etc);
  • businessService (include informazioni sui web service)
  • bindingTemplate (include informazioni su come e dove accedere il web service)
  • tModel (Technical model, include descrizioni o puntatori a specifiche tecniche esterne oppure a tassonomie).
UDDI può avere come identificativo di un servizio un numero detto Dun & Bradstreet D-U-N-S® Number, un numero di nove cifre codificato secondo un certo standard (vedi qui ).

 Vediamo degli esempi:

businessEntity



<businessEntity
businessKey="0076b468-eb27-42e5-ac09-9955cff462a3"
operator="Microsoft Corporation" authorizedName="Martin Kohlleppel">
<name>Microsoft Corporation</name>
<description xml:lang="en">Empowering people through great software
- any time, any place and on any device is Microsoft's vision. As the
worldwide leader in software for personal and business computing, we
strive to produce innovative products and services that meet our
customer's...
</description>
<contacts>
<contact useType="Corporate Addresses and telephone">
<description xml:lang="en">Corporate Mailing Addresses</
description>
<personName />
<phone useType="Corporate Headquarters">(425) 882-8080</phone>
<address sortCode="~" useType="Corporate Headquarters">
<addressLine>Microsoft Corporation</addressLine>
<addressLine>One Microsoft Way</addressLine>
<addressLine>Redmond, WA 98052-6399</addressLine>
<addressLine>USA</addressLine>
</address>
</contact>
<contact useType="Technical Contact - Corporate UD">
<description xml:lang="en">World Wide Operations</description>
<personName>Martin Kohlleppel</personName>
<email>martink@microsoft.com</email>
</contact>
</contacts>
<identifierBag>
<keyedReference
tModelKey="uuid:8609c81e-ee1f-4d5a-b202-3eb13ad01823"
keyName="D-U-N-S" keyValue="08-146-6849" />
</identifierBag>
<categoryBag>
<keyedReference
tModelKey="uuid:c0b9fe13-179f-413d-8a5b-5004db8e5bb2"
keyName="NAICS: Software Publisher" keyValue="51121" />
</categoryBag>
</businessEntity>


business service / binding Template


<businessService
serviceKey="d5921160-3e16-11d5-98bf-002035229c64"
businessKey="ba744ed0-3aaf-11d5-80dc-002035229c64">
<name>XMethods Delayed Stock Quotes</name>
<description xml:lang="en">20-minute delayed stock quotes</description>
<bindingTemplates>
<bindingTemplate
serviceKey="d5921160-3e16-11d5-98bf-002035229c64"
bindingKey="d594a970-3e16-11d5-98bf-002035229c64">
<description xml:lang="en">
SOAP binding for delayed stock quotes service
</description>
<accessPoint URLType="http">
http://services.xmethods.net:80/soap
</accessPoint>
<tModelInstanceDetails>
<tModelInstanceInfo
tModelKey="uuid:0e727db0-3e14-11d5-98bf-002035229c64" />
</tModelInstanceDetails>
</bindingTemplate>
</bindingTemplates>
</businessService>


tModel 


<tModel
tModelKey="uuid:0e727db0-3e14-11d5-98bf-002035229c64"
operator="www.ibm.com/services/uddi" authorizedName="0100001QS1">
<name>XMethods Simple Stock Quote</name>
<description xml:lang="en">Simple stock quote interface</description>
<overviewDoc>
<description xml:lang="en">wsdl link</description>
<overviewURL>
www.it-ebooks.info
Web Services Essentials
144
http://www.xmethods.net/tmodels/SimpleStockQuote.wsdl
</overviewURL>
</overviewDoc>
<categoryBag>
<keyedReference
tModelKey="uuid:c1acf26d-9672-4404-9d70-39b756e62ab4"
keyName="uddi-org:types" keyValue="wsdlSpec" />
</categoryBag>
</tModel>


Quindi esiste una API per interfacciare UDDI che si divide in 2 macro aree:
  • Inquiry API;
  • Publisher API.
La prima per ricercare servizi UDDI e la seconda invece per pubblicarli o aggiornarli o rimuoverli.
Questa API è basata su SOAP e comprende una serie di funzioni, essitono quindi librerie declinate nel linguaggio di specifico interesse che consentono di effettuare le chiamate al registro UDDI.

Inquiry API

find_binding cerca bindings associati ad uno specifico servizio
find_business cerca un tipo di business che rispetti il criterio specificato
find_service cerca i servizi associati a quello specifico business
find_tModel cerca i technical model che rispettano il criterio specificato
get_bindingDetail per ottenere un completo binding detail
get_businessDetail per ottenere un completo record di una businessEntity
get_serviceDetail per ottenere un completo record di un servizio
get_tModelDetail per ottenere un completo record di un tmodel

Publishing API

get_authToken : richiede un token di autenticazione. Il token verrà richiesto anche per tutte le successive invocazioni
discard_authToken: invalida il token
save_binding Inserisce o aggiorna un bindingTemplate record.
save_business Inserisce o aggiorna un businessEntity record.
save_service Inserisce o aggiorna un businessService record.
save_tModel Inserisce o aggiorna un tModel record.
delete_binding Cancella il  bindingTemplate record specificato dalla bindingKey.
delete_business Cancella il businessEntity record specificato dallabusinessKey.
delete_service Cancella il  businessService record specificagto dalla serviceKey.
delete_tModel nasconde il tModel record specificato dalla tModelKey (non si possono cancellare tModel)