ORVE WS (Dynamic) (2). First things first in programming.
1. Introduction
The following libraries (or tools) will be used:
- Apache CXF (for web services)
- Lombok (for avoiding setters and getters boilerplate)
- Maven
- XML and WS libraries included in JVM 1.8 but not in 9 and upwards.
But I am a fan of Jackson so these libraries will be used:
- jackson-dataformat-xml (For XML )
Apache has some gems for reflection and string management
- apache-commons-lang3
2. Configuration with pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>EduWS</groupId> <artifactId>ORVEWS</artifactId> <version>0.0.1-SNAPSHOT</version> <name>ORVE WS</name> <description>ORVE WS Client</description> <properties> <cxf.version>3.2.6</cxf.version> <jax.version>2.3.0</jax.version> <lombok.version>1.18.2</lombok.version> <jackson.version>2.9.6</jackson.version> <failOnMissingWebXml>false</failOnMissingWebXml> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- Java version--> <java.version>10</java.version> </properties> <dependencies> <!-- WS DEPENDENCIES --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-frontend-jaxws</artifactId> <version>${cxf.version}</version> </dependency> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http</artifactId> <version>${cxf.version}</version> </dependency> <!-- Jetty is needed if you're are not using the CXFServlet --> <dependency> <groupId>org.apache.cxf</groupId> <artifactId>cxf-rt-transports-http-jetty</artifactId> <version>${cxf.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <!-- END WS DEPENDENCIES --> <!-- Apache commons string utils .. --> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.7</version> </dependency> <!--BEGIN Java 9 references to JEE not included in JDK9--> <!-- see http://openjdk.java.net/jeps/320--> <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl --> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>${jax.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-core --> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>${jax.version}</version> </dependency> <dependency> <groupId>com.sun.activation</groupId> <artifactId>javax.activation</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-ri</artifactId> <version>${jax.version}</version> <type>pom</type> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-ri</artifactId> <version>${jax.version}</version> <type>pom</type> </dependency> <!-- End of Dependencies required for JAVA 9!!!! --> <!-- 2018-09-24 Jackson Dataformat XML --> <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> <version>${jackson.version}</version> </dependency> </dependencies> </project> |
3. The static way. Invoking "obtenerIdentificadores"
Here is a class that implements a static client:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | package ximodante.orve.staticp; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import javax.xml.namespace.QName; import javax.xml.ws.Holder; import https.ssweb_seap_minhap_es.demoorve.FiltrosIdentificadores; import https.ssweb_seap_minhap_es.demoorve.ObtenerIdentificaoresRespuestaWS; import https.ssweb_seap_minhap_es.demoorve.Security; import https.ssweb_seap_minhap_es.demoorve.WSExportacionPortType; import https.ssweb_seap_minhap_es.demoorve.WSExportacionService; public class StaticORVEClient { private static final QName SERVICE_NAME = new QName("https://ssweb.seap.minhap.es/demoorve/", "WSExportacionService"); private StaticORVEClient() { } public static void main(String args[]) throws java.lang.Exception { URL wsdlURL = WSExportacionService.WSDL_LOCATION; if (args.length > 0 && args[0] != null && !"".equals(args[0])) { File wsdlFile = new File(args[0]); try { if (wsdlFile.exists()) { wsdlURL = wsdlFile.toURI().toURL(); } else { wsdlURL = new URL(args[0]); } } catch (MalformedURLException e) { e.printStackTrace(); } } //1. WS Ports WSExportacionService ss = new WSExportacionService(wsdlURL, SERVICE_NAME); WSExportacionPortType port = ss.getWSExportacionPort(); //2. Obtener identificadores System.out.println("1. Invoking obtenerIdentificadores..."); //2.1 Invoking param: Holder<Security> //2.1.1 Security Security security = new Security(); security.setUsername("myUser"); security.setPassword("myPassword"); //2.1.2 Holder<Security> Invoking param: Security Holder<Security> hSec = new Holder<Security>(security); //2.2 Invoking param: FiltrosIdentificadores FiltrosIdentificadores filtIden = new FiltrosIdentificadores(); filtIden.setEstado("EC"); filtIden.setFechaInicio("2018-09-01 00:00:01"); filtIden.setFechaFin("2018-09-23 23:59:59"); filtIden.setUnidad("LA1000323"); //filtIden.setOficina("O00002721"); //2.3 Invoke operation obtenerIdentificadores ObtenerIdentificaoresRespuestaWS obtIdenResp = port.obtenerIdentificadores(hSec, filtIden); if (! obtIdenResp.getCodigo().equals("00")) { System.out.println("Error " + obtIdenResp.getCodigo() + "->" + obtIdenResp.getDescripcion()); } else { int ii=0; for (Integer iden: obtIdenResp.getIdentificadores().getItem()) { System.out.println(ii++ + "--> id="+ iden.intValue()); } } System.exit(0); } } |
If we want to create a dynamic client, let's first create this utilitiy class
4. Dynamic way (1) Utility class
In order to simplify creating instances and assigning the values to attributes, a utility class is implemented.
To create an instance of a specific class, it is required to supply the name of the class and a Map<String, Object> of the pairs attribute name - attribute value
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | package ximodante.utils; import java.lang.reflect.InvocationTargetException; import java.util.Map; import org.apache.commons.lang3.reflect.FieldUtils; public class ObjectBuilder { /** * Creates an object from its canonical class name * and assing values to attributes from a map containing * attribute name and value * @param fullClassName * @param fields * @return * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws SecurityException */ public static Object getObject(String fullClassName, Map<String,Object> fields ) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { //1. Get a class loader ClassLoader classLoader=Thread.currentThread().getContextClassLoader(); //2, Load a class Class<?> MyClass=null; MyClass=classLoader.loadClass(fullClassName); //3. Get an instance of the class Object myObject = MyClass.getConstructor().newInstance(); //4. Assign field values to object for (String s: fields.keySet()) { FieldUtils.writeField(myObject, s, fields.get(s) , true); } return myObject; } public static void main(String[] args) { // TODO Auto-generated method stub } } |
So, some boilerplate code is simplified.
4. Dynamic way (2).Invoking "obtenerIdentificadores"
This class creates a dynamic client and the 2 parameter classes to invoke the operation in the WS.
Here is the class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | package ximodante.orve.dynamicp; import java.util.HashMap; import java.util.List; import javax.xml.ws.Holder; import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.cxf.endpoint.Client; import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import ximodante.utils.ObjectBuilder; public class DynamicORVEClient { public static void main(String[] args) { try { //1. Declare WSDL JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance(); Client client = dcf.createClient("https://ssweb.seap.minhap.es/demoorve/WSExportacion.wsdl"); // 2. Create a map to store fields var mapFields=new HashMap<String,Object>(); // 3. Create parameters of the WS operations //2.1 Security //2.1.1 Assign fields mapFields.clear(); // remove previous fields mapFields.put("username", "myUser"); mapFields.put("password", "myPassword"); //2.1.2 Create object var security=ObjectBuilder.getObject("https.ssweb_seap_minhap_es.demoorve.Security", mapFields); //2.2 Holder<Security> var secHolder = new Holder(security); //2.3 FiltrosIdentificadores //2.3.1 Assign fields mapFields.clear(); // remove previous fields mapFields.put("estado", "EC"); mapFields.put("fechaInicio", "2018-09-01 00:00:01"); mapFields.put("fechaFin", "2018-09-23 23:59:59"); mapFields.put("unidad", "LA1000323"); //Catarroja //mapFields.put("oficina", "O00002721");// Of. Registro de Catarroja //2.3.2 Create object var filtros=ObjectBuilder.getObject("https.ssweb_seap_minhap_es.demoorve.FiltrosIdentificadores", mapFields); //3 Invoke WS operation // 3.1 Output object (obtained by invoking the WS operation) Object[] res=null; // 3.2 Operation name from the WSDL String operationWS="obtenerIdentificadores"; // 3.3 WS invocation with operation name and input structure //res = client.invokeWrapped(operationWS,secHolder,filtros); res = client.invoke(operationWS,secHolder,filtros); var b=res[1]; //Holder<obtenerIdentificaoresRespuestaWS> var value= FieldUtils.readField(b, "value", true); //obtenerIdentificaoresRespuestaWS String codigo=(String)(FieldUtils.readField(value, "codigo", true)); String descripcion=(String)(FieldUtils.readField(value, "descripcion", true)); System.out.println(descripcion); if (! codigo.equals("00") ){ System.out.println("Error " + codigo + ": " + descripcion); } else { int ii=0; var aIden=FieldUtils.readField(value, "identificadores", true); List<Integer> lIden=(List<Integer>) FieldUtils.readField(aIden, "item", true); System.out.println(lIden.size()); for (Integer iden: lIden) { System.out.println(ii+ " --> + iden=" + iden); } } } catch (Exception e) { e.printStackTrace(); } } } |
In this case, it seems that the static way is shorter and easier to use, and the "utility class" is not used. In this particular case (as it was reported in the previous post), the problem was the "AnyTypeArray" class and the buggy way Apache CXF implements it. Once this problem is solved, the dynamic way would get rid of the generation of the scaffolding of the "https.ssweb_seap_minhap_es.demoorve" package. Although this is not a serious problem as we can delete all classes from this package except "AnyTypeArray" class. Note that this class needs to be updated as mentioned in the previous post.
This post is getting a bit long. But our solution has not bin com completed. We need to call the next WS operation "obtenerRegistro", but this is a bit tricky. So before invoking this operation, I think it's better studying a bit more the possibilities of Apache CXF.
Comments
Post a Comment