ORVE WS (Dynamic) (3) : Interceptors and XML conversation. Retrieving the XML Message received from server
1. Introduction
As we know from the two previous posts, there may be problems while unmarshalling the "AnyTypeArray" class.
The solution provided was:
- Generate the scaffolding package "https.ssweb_seap_minhap_es.demoorve" with wsdl2java command.
- Modify the "AnyTypeArray" class and replace all occurrences of List<Object> with List<Integer>.
- The rest of the classes are not needed for the dynamic client. So they can be deleted (except AnyTypeArray).
But if we want to analyze the XML conversation between client and server or log it or even change part of this XML, it can be used interceptors.
NOTE: I have not been able to aply interseptors to get the REQUEST, only I have got the RESPONSE XML code! For this case, I can only see how a class is transformed to XML Here is a procedure to creae an object dynamically, and the use Jackson parser to marshall to XML and after that you can test if this XML has the proper tags
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 | /** * Creates an object instance whose class name is pass as a parameter * A class loader is needed, and obtained form WS creation * A hashmap with field names and values must be provided * @param clsLoader * @param fullClassName * @param myFields * @return * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException * @throws IllegalArgumentException * @throws InvocationTargetException * @throws NoSuchMethodException * @throws SecurityException */ public static Object createObject ( ClassLoader clsLoader, String fullClassName, HashMap<String, Object> myFields, boolean showGeneratedXML) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { Class<?> myClass=clsLoader.loadClass(fullClassName); Object myInstance=myClass.getConstructor().newInstance(); myFields.forEach((k, v)-> { try { FieldUtils.writeField(myInstance, k, v , true); } catch (IllegalAccessException e) {e.printStackTrace();} }); // Only por debug purposes if (showGeneratedXML) { try { System.out.println("See XML generated for " + fullClassName + "for testing request code:\n" + JacksonUtils.ObjectToString(myInstance, MapperType.XML)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } return myInstance; } |
In Javatips.net, there is a simple example that will serve with only a few changes. Here is a simple interceptor that reads the server response and saves it to a file.
2. A beginner's example
This example is practically a copy & paste of Javatips.net with a few exceptions.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 | package ximodante.utils; import java.io.ByteArrayInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.Calendar; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.apache.cxf.io.CachedOutputStream; import org.apache.cxf.message.Message; /** * Simplifies the XML message to obtain an array with all the elements separated by a colon * @author ximo dante * */ public class MyXMLInterceptor<T extends Message> extends AbstractPhaseInterceptor<T> { public MyXMLInterceptor() { super(Phase.RECEIVE); // IMPORTANT !!!! } /** * This is a bit tricky and difficult to understand * Replace input stream with another whose message has been changed * 1. Copy the input stream * 2. Reads the XML message and make any operations * 3. Closes the input message stream * 4. Creates a new input stream with the modified XML message */ public void handleMessage(Message message) { message.put(Message.ENCODING, "UTF-8"); InputStream is = message.getContent(InputStream.class); if(is!=null){ CachedOutputStream bos = new CachedOutputStream(); try{ IOUtils.copy(is,bos); String soapMessage = new String(bos.getBytes()); bos.flush(); message.setContent(InputStream.class, is); is.close(); InputStream inputStream = new ByteArrayInputStream(operateOnXMLMessage(soapMessage).getBytes()); message.setContent(InputStream.class, inputStream); bos.close(); } catch (IOException ioe) { ioe.printStackTrace(); } } } /** * Make any operation on the XML Message. This is an skeleton * In this case, the message is saved to a file * @param soapMessage * @return modified soap message */ private String operateOnXMLMessage(String soapMessage) { //return soapMessage.replaceAll("</item><item>", ";"); Calendar cal = Calendar.getInstance(); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); FileWriter file; try { file = new FileWriter("/home/eduard/ORVE/" + sdf.format(cal.getTime()) +".txt"); PrintWriter pw = new PrintWriter(file); pw.println(soapMessage); pw.close(); file.close(); } catch (IOException e) { e.printStackTrace(); } return soapMessage; } } |
One should notice that:
- An interceptor should be placed in a phase that Apache CXF has defined. For our purpose, the interceptor is in the client and the phase is "RECEIVE".
- This interceptor could have been used to change the XML message, but in this case, we are saving the XML response of the server to a file..
- When creating the client, this interceptor must be referenced. We will see it in the next section.
3. The dynamic client
In order to use this interceptor, it should be declared in the client class. Declaring the created interceptor as in lines 28-30, this interceptor is executed.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 | 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 org.apache.cxf.message.Message; import ximodante.utils.MyXMLInterceptor; 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"); //1.1 INTERCEPTOR !!! var myInterceptor = new MyXMLInterceptor<Message>(); client.getInInterceptors().add(myInterceptor); // 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(); } } } |
Usually, interceptors may be a good tool for problem-solving.
Comments
Post a Comment