Propòsit
El propòsit del connector és proporcionar una interfície java per accedir a la PICA (Plataforma d’Integració i Col·laboració Administrativa).
El connector amb la PICA disposa de dos tipus de comunicació, un d’ells a través de web service síncron, i l’altre, mitjançant web service asíncron.
Instal.lació i Configuració
Instal.lació
Per d’instal-lar el mòdul de PICA, afegir manualment en el pom.xml
de l’aplicació la següent dependència:
<properties>
...
<canigo.integration.pica.version>[3.1.0,3.2.0)</canigo.integration.pica.version>
</properties>
<dependencies>
...
<dependency>
<groupId>cat.gencat.ctti</groupId>
<artifactId>canigo.integration.pica</artifactId>
<version>${canigo.integration.pica.version}</version>
</dependency>
</dependencies>
A la Matriu de Compatibilitats es pot comprovar la versió del mòdul compatible amb la versió de Canigó utilitzada.
Configuració
Son necessaris els següents arxius de configuració:
- pica.properties
- pica.signature.properties
- client.axis2.xml
- modules.list
- rampart-1.3.mar
- certificats.jks
Alguns d’ells es troben en aquest zip adjunt. A continuació es descriu el detall de cadascun.
Ubicació: <PROJECT_ROOT>/src/main/resources/config/props/pica.properties
Propietat | Requerit | Descripció |
---|---|---|
*.pica.modes.passwordType | No | Tipus de password per a la PICA. Per defecte: PasswordText |
*.pica.requirer.signatureFile | Sí | Arxiu de configuració de la seguretat |
*.pica.requirer.petitionerId | Sí | Identificador del solicitant |
*.pica.requirer.transmitionId | Sí | Identificador de la transmissió |
*.pica.requirer.petitionerName | Sí | Nom del peticionari |
*.pica.requirer.user | Sí | Usuari que vol consumir un producte/modalitat de la PICA |
*.pica.requirer.password | Sí | Password de l’usuari que vol consumir un producte/modalitat de la PICA |
*.pica.axisdefinition.location | Sí | Localització de l’arxiu d’axisdefinition |
*.pica.trustStore.location | No | Localització de l’arxiu de certificats per a la configuració SSL |
*.pica.trustStore.type | No | Tipus de keystore |
*.pica.trustStore.password | No | Password de la keystore |
Ubicació: <PROJECT_ROOT>/src/main/resources/axis2client/conf/client.axis2.xml
Adjunt en el zip.
Ubicació: <PROJECT_ROOT>/src/main/resources/axis2client/conf/rampart-1.3.mar
Adjunt en el zip.
Ubicació: <PROJECT_ROOT>/src/main/resources/axis2client/conf/modules.list
Adjunt en el zip.
Ubicació: <PROJECT_ROOT>/src/main/resources/config/cert/certificats.jks
Ha de ser proporcionat per cada projecte que utilitzi aquest connector, ja que conté les claus i certificats específics necessaris per a la signatura i/o xifrat segons la configuració de seguretat de cada entorn.
Ubicació: <PROJECT_ROOT>/src/main/resources/config/cert/pica.signature.properties
Propietat | Descripció |
---|---|
org.apache.ws.security.crypto.provider | Defineix el proveïdor de seguretat que s’utilitza per gestionar la criptografia |
org.apache.ws.security.crypto.merlin.file | Ruta del keystore (JKS) que conté el certificat/clau privada. |
org.apache.ws.security.crypto.merlin.keystore.type | Tipus d’emmagatzematge de claus, pot ser JKS, PKCS12, etc. |
org.apache.ws.security.crypto.merlin.keystore.password | Contrasenya per accedir al keystore |
org.apache.ws.security.crypto.merlin.keystore.provider | Proveïdor de Java que gestiona el keystore |
org.apache.ws.security.crypto.merlin.keystore.alias | Àlies dins del keystore per identificar la clau/certificat |
org.apache.ws.security.crypto.merlin.alias.password | Contrasenya per accedir a la clau privada associada a l’àlies anterior |
Ubicació: <PROJECT_ROOT>/src/main/resources/spring/app-integration-custom.xml
Es detalla en l’apartat següent.
Important
Si l'aplicació ha de ser desplegada en format empaquetat (.war, .ear) caldrà indicar la ubicació de la carpeta de configuració d'axis2 com a Path absolut dins el servidor on desplegarà. Aquest Path s'indicarà sobreescrivint el valor de la propietat pica.axisdefinition.location del fitxer pica.properties amb el Path absolut on s'ha deixat la carpeta d'axis2client als servidors. S'haurà de pactar la ubicació amb els responsables del CPD on desplegarà.
Exemple:
pica.properties:
int.pica.axisdefinition.location=file:/export/AppJavaDades/int/.../axis2client/
pre.pica.axisdefinition.location=file:/export/AppJavaDades/pre/.../axis2client/
pro.pica.axisdefinition.location=file:/export/AppJavaDades/pro/.../axis2client/
Utilització del Mòdul
REST
app-integration-custom.xml
Aquest arxiu XML conté la configuració de Spring per al servei de PICA. En l’exemple configurem el servei de PICA per invocar el producte/modalitat “PADRO_MUNICIPI_RESIDENCIA”.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="picaCanigoService" parent="abstractPicaService"
class="cat.gencat.ctti.canigo.arch.integration.pica.PicaServiceWrapperImpl"
scope="prototype">
<property name="requeridor" ref="requeridor"/>
<property name="modalitats">
<map>
<entry key="PADRO_MUNICIPI_RESIDENCIA">
<bean parent="producteModalitatBase">
<property name="signat" value="false"/>
<property name="urlPICA"
value="http://preproduccio.pica.intranet.gencat.cat/pica_cataleg/AppJava/services/PADRO_MUNICIPI_RESIDENCIA"/>
<property name="codCertificado"
value="PADRO_MUNICIPI_RESIDENCIA"/>
<property name="codProducto" value="PADRO"/>
<property name="finalidad" value="PROVES"/>
<property name="nifEmisor" value="Q0801175A"/>
<property name="nombreEmisor" value="CONSORCI AOC"/>
</bean>
</entry>
</map>
</property>
</bean>
<bean id="picaCanigoServiceError" parent="picaCanigoService">
<property name="requeridor" ref="requeridorErrorPassword"/>
</bean>
<bean id="requeridorErrorPassword" parent="requeridor">
<property name="password" value="PICAERROR"/>
<property name="user" value="USER_ERROR"/>
</bean>
</beans>
PicaAplicacioService.java
Classe Java amb la lògica de les peticions que es realitzin, i la connectivitat amb el mòdul de la PICA.
En aquesta classe es pot visualiztar:
- Injecció del servei de PICA.
- Invocació del producte/modalitat “PADRO_MUNICIPI_RESIDENCIA” definit en el map de modalitats que es troba al fitxer de configuració xml de Spring.
import cat.gencat.ctti.canigo.arch.integration.pica.PicaServiceWrapperImpl;
import cat.gencat.pica.api.peticio.beans.DadesEspecifiques;
import cat.gencat.pica.api.peticio.beans.Funcionari;
import cat.gencat.pica.api.peticio.beans.Titular;
import cat.gencat.pica.api.peticio.core.IPICAServiceSincron;
import com.generalitat.mp.ws.CridaSincronaResponseDocument;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.inject.Inject;
import javax.inject.Named;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
@Service("picaAplicacioService")
public class PicaAplicacioService {
private static final Logger log = LoggerFactory.getLogger(PicaAplicacioService.class);
private static final int TIPO_DOC_TITULAR_NIF = 2;
@Autowired
private final PicaServiceWrapperImpl picaServiceWrapperImpl;
public String ferPeticioAlServei() {
try {
IPICAServiceSincron service = picaServiceWrapperImpl.getPicaWebServiceSincronInstance("PADRO_MUNICIPI_RESIDENCIA");
service.setFuncionari(getFuncionari());
service.setTitular(creaTitular());
service.setDadesEspecifiques(createDadesEspecifiques());
//Identificador únic de petició
service.crearPeticio("PROVA_OTCANIGO_" + System.currentTimeMillis());
//fer peticio
CridaSincronaResponseDocument resp = picaServiceWrapperImpl.ferPeticioAlServei(service);
//extreure resultat
List<DadesEspecifiques> resposta = picaServiceWrapperImpl.extreuDadesEspecifiques(service, resp);
Iterator<DadesEspecifiques> it = resposta.iterator();
while (it.hasNext()) {
DadesEspecifiques object = it.next();
String dadesXML = object.getDadesXML();
// Parsejar resposta
parseXML(dadesXML);
}
message = "Test correcte";
} catch (Exception e) {
log.error(e.getMessage(), e);
return "Test amb errors: " + e.getMessage();
}
return "Test correcte";
}
private Funcionari getFuncionari() {
Funcionari funcionari = new Funcionari();
funcionari.setNombreFuncionario("Nom Funcionari");
funcionari.setNifFuncionario("55555555A");
funcionari.setEmailFuncionario("prova@gencat.com");
return funcionari;
}
private Titular creaTitular() {
Titular tit = new Titular();
tit.setTitularTipoDocumentacion(TIPO_DOC_TITULAR_NIF);
tit.setTitularDocumentacion("NIF_TITULAR"); // Es posa el NIF real
tit.setTitularNombreCompleto("NOM_COMPLET_TITULAR"); // Es posa el nom real
return tit;
}
private List<DadesEspecifiques> createDadesEspecifiques() {
List<DadesEspecifiques> dadesEspecifiquesXML = new ArrayList<>();
StringBuilder sb = new StringBuilder("<ns1:request xmlns:ns1=\"http://www.gencat.net/tfn\">");
sb.append("<ns1:simpleparam name=\"NUMTIT\">83746573</ns1:simpleparam>");
sb.append("<ns1:simpleparam name=\"NUMNIF\">111111111H</ns1:simpleparam>");
sb.append("</ns1:request>");
DadesEspecifiques dades = new DadesEspecifiques();
dades.setIdSolicitud("1");
dades.setDadesXML(sb.toString());
dadesEspecifiquesXML.add(dades);
return dadesEspecifiquesXML;
}
private void parseXML(String dadesXML) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource inStream = new InputSource();
boolean error = false;
inStream.setCharacterStream(new StringReader(dadesXML));
Document doc = builder.parse(inStream);
NodeList nodes = doc.getElementsByTagName("error");
if (nodes.getLength() == 0) {
nodes = doc.getElementsByTagName("sol:SolicitudError");
error = true;
}
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
if (!error) {
log.info(dadesXML);
} else {
log.info(element.getTextContent());
}
}
}
}
}
Cal destacar que l’identificador de la petició ha de ser únic, per aquest motiu es concatena un prefix de text qualsevol amb el timestamp del sistema.
Per a més informació respecte l’especificació tècnica i funcional podeu contactar amb l’OT PICA.
En aquest exemple, els mètodes privats crearFuncionari() i crearTitular() (creats simplement per aquest test) s’encarreguen de setejar les propietats del funcionari que fa la petició i titular sobre el que es fa la petició respectivament. El mètode també privat createDadesEspecifiques() conté una llista de les sol.licituds, en format XML, que s’enviaran dins la petició.
Dins una petició (llista de dades específiques) es poden incloure diverses sol·licituds, els identificadors de les quals han de ser únics dins una mateixa petició. Si volguéssim afegir una altra sol- licitud en l’exemple, només caldria instanciar un nou objecte DadesEspecifiques, amb IdSolicitud=“2”, un nou StringBuffer amb les dades i afegir-lo a la llista dadesEspecifiquesXML dins del mètode createDadesEspecifiques() de l’exemple.
PicaServiceController.java
Controller que publica les operacions disponibles per a qui hagi de consumir-les
import io.swagger.annotations.Api;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = {"canigo-pica-test"})
@RestController
@RequestMapping("/pica")
public class PicaAplicacioController {
private final PicaAplicacioService picaAplicacioService;
public PicaAplicacioController(PicaAplicacioService picaAplicacioService) {
this.picaAplicacioService = picaAplicacioService;
}
@GetMapping(produces = { MediaType.APPLICATION_JSON_VALUE })
public String testPica() {
return picaAplicacioService.ferPeticioAlServei();
}
}
Més informació
Per a més informació sobre el connector de la PICA teniu: