1

I'm working with the ECCP protocol in order to integrate my CRM with the Elastix Call Center Module. The protocol uses a XML structure defined as follows:

<request id="1">
   <request_type> <!-- this will be mapped to the Java request class -->
       <attributes>
       </attributes>
   </request_type>
</request>

and

<response id="1">
    <response_type> <!-- this will be mapped to the Java response class -->
        <attributes>
        </attributes>
    </response_type>
</response>

I'm using JAX-B to map XML to Java classes but the problem is that I have to put the JAX-B generated XML inside a <request></request> XML every request and extract the content from <response></response> in every response because the ECCP protocol defines that every request and response needs to nested to their respective elements.

Here's the code I'm using to do that:

document = createDocument();
Element requestWrapper = document.createElement("request");
requestWrapper.setAttribute("id", String.valueOf(wrapped.getId()));
document.appendChild(requestWrapper);

JAXBContext jc = JAXBContext.newInstance(wrapped.getClass());
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(wrapped, requestWrapper);

Exemplifying:

One of ECCP's protocol operation is JAX-B-mapped into a class like this (getters and setters were omitted):

@XmlRootElement(name = "loginagent")
@XmlAccessorType(XmlAccessType.FIELD)
public class EccpLoginAgentRequest implements IEccpRequest {

    @XmlElement(name = "agent_number")
    private String agentNumber;

    @XmlElement(name = "password")
    private String password;
}

And JAX-B outputs the following:

<loginagent>
   <agent_number>username</agent_number>
   <password>password</password>
</loginagent>

But what the ECCP's protocol requires is:

<request id="1"> <!-- id is an auto-increment number to identify the request -->
    <loginagent>
       <username>username</username>
       <password>password</password>
    </loginagent>
</request>

The question is: is there any other way to achieve in any other better way? Thank you.

Jaumzera
  • 2,305
  • 1
  • 30
  • 44

2 Answers2

1

You can probably check out the @XmlSeeAlso annotation which will help you wrap the same content both for request and response. For the inner part you can create the separate class and map all the fields appropriately. I hope this helps you a little bit.

EDIT: Sorry for the long response time. You need to create a wrapper class with the inner structure defined as an @XmlElement. Here's the way to achieve that XML structure:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "request")
public class RequestWrapper {

@XmlElement(name = "loginagent", required = true)
protected EccpLoginAgentRequest loginagent;

public EccpLoginAgentRequest getLoginagent() {
    return loginagent;
}

public void setLoginagent(EccpLoginAgentRequest loginagent) {
    this.loginagent = loginagent;
}
}

And here's the EccpLoginAgentRequest structure:

@XmlAccessorType(XmlAccessType.FIELD)
public class EccpLoginAgentRequest {

@XmlElement(name = "agent_number")
private String agentNumber;

@XmlElement(name = "password")
private String password;

// getters and setters omitted
}

So in result, you can print the XML you want like that:

JAXBContext jaxbContext = JAXBContext.newInstance(Wrapper.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,    true);

EccpLoginAgentRequest request = new EccpLoginAgentRequest();
request.setAgentNumber("1");
request.setPassword("pass");

Wrapper wrapper = new Wrapper();
wrapper.setLoginagent(request);

jaxbMarshaller.marshal(wrapper, System.out);

It will give you the following output:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<request>
    <loginagent>
        <agent_number>1</agent_number>
        <password>pass</password>
    </loginagent>
</request>
reallol
  • 71
  • 2
  • Ok, I took a look at the @XmlSeeAlso annotation docs, but I'll improve my question to explain better the problem. – Jaumzera May 12 '16 at 16:53
  • I'd be glad if you could check the question again. Thanks in advance. – Jaumzera May 12 '16 at 17:09
  • Thanks again, @reallol, but it will work only when I send a EccpLoginAgentRequest object, while what I really need is to be able to send objects from any class that extends EccpRequest. – Jaumzera May 16 '16 at 12:58
0

I found a way to solve this in this post: XML element with attribute and content using JAXB

So I've mapped a EccpRequestWrapper object as the following:

@XmlRootElement(name = "request")
public class EccpRequestWrapper {
    @XmlAttribute
    private Long id;

    @XmlAnyElement
    private IEccpRequest request;
}

and then my request JAX-B outputs my request the way ECCP protocol requires. The @XmlAttribute and @XmlAnyElement annotation did the trick.

<request id="1">
   <login>
      <username>user</username>
      <password>****</password>
   </login>
</request>

A good JAXB guide can be found here https://jaxb.java.net/guide/Mapping_interfaces.html

Community
  • 1
  • 1
Jaumzera
  • 2,305
  • 1
  • 30
  • 44