views:

2108

answers:

6

I am receiving SOAP requests from a client that uses the Axis 1.4 libraries. The requests have the following form:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"&gt;
  <soapenv:Body>
    <PlaceOrderRequest xmlns="http://example.com/schema/order/request"&gt;
      <order>
        <ns1:requestParameter xmlns:ns1="http://example.com/schema/common/request"&gt;
          <ns1:orderingSystemWithDomain>
            <ns1:orderingSystem>Internet</ns1:orderingSystem>
            <ns1:domainSign>2</ns1:domainSign>
          </ns1:orderingSystemWithDomain>
        </ns1:requestParameter>
        <ns2:directDeliveryAddress ns2:addressType="0" ns2:index="1" 
                                   xmlns:ns2="http://example.com/schema/order/request"&gt;
          <ns3:address xmlns:ns3="http://example.com/schema/common/request"&gt;
            <ns4:zipcode xmlns:ns4="http://example.com/schema/common"&gt;12345&lt;/ns4:zipcode&gt;
            <ns5:city xmlns:ns5="http://example.com/schema/common"&gt;City&lt;/ns5:city&gt;
            <ns6:street xmlns:ns6="http://example.com/schema/common"&gt;Street&lt;/ns6:street&gt;
            <ns7:houseNum xmlns:ns7="http://example.com/schema/common"&gt;1&lt;/ns7:houseNum&gt;
            <ns8:country xmlns:ns8="http://example.com/schema/common"&gt;XX&lt;/ns8:country&gt;
          </ns3:address>
[...]

As you can see, several prefixes are defined for the same namespace, e.g. the namespace http://example.com/schema/common has the prefixes ns4, ns5, ns6, ns7 and ns8. Some long requests define several hundred prefixes for the same namespace.

This causes a problem with the Saxon XSLT processor, that I use to transform the requests. Saxon limits the the number of different prefixes for the same namespace to 255 and throws an exception when you define more prefixes.

Can Axis 1.4 be configured to define smarter prefixes, so that there is only one prefix for each namespace?

A: 

Could you please confirm you mapping meta-data which is embedded into Java source code ? There is an option to force custom mapping from namespace to java package but I am not sure if this will change XML output but it's worth a try.

Ignat
+1  A: 

I have the same issue. For the moment, I've worked around it by writing a BasicHandler extension, and then walking the SOAPPart myself and moving the namespace reference up to a parent node. I don't like this solution, but it does seem to work.

I really hope somebody comes along and tells us what we have to do.

EDIT

This is way too complicated, and like I said, I don't like it at all, but here we go. I actually broke the functionality into a few classes (This wasn't the only manipulation that we needed to do in that project, so there were other implementations) I really hope that somebody can fix this soon. This uses dom4j to process the XML passing through the SOAP process, so you'll need dom4j to make it work.

public class XMLManipulationHandler extends BasicHandler {
private static Log log = LogFactory.getLog(XMLManipulationHandler.class);
private static List processingHandlers;

public static void setProcessingHandlers(List handlers) {
 processingHandlers = handlers;
}

protected Document process(Document doc) {
 if (processingHandlers == null) {
  processingHandlers = new ArrayList();
  processingHandlers.add(new EmptyProcessingHandler());
 }
 log.trace(processingHandlers);
 treeWalk(doc.getRootElement());
 return doc;
}

protected void treeWalk(Element element) {
 for (int i = 0, size = element.nodeCount(); i < size; i++) {
  Node node = element.node(i);
  for (int handlerIndex = 0; handlerIndex < processingHandlers.size(); handlerIndex++) {
   ProcessingHandler handler = (ProcessingHandler) processingHandlers.get(handlerIndex);
   handler.process(node);
  }
  if (node instanceof Element) {
   treeWalk((Element) node);
  }
 }
}

public void invoke(MessageContext context) throws AxisFault {
 if (!context.getPastPivot()) {
  SOAPMessage message = context.getMessage();
  SOAPPart soapPart = message.getSOAPPart();
  ByteArrayOutputStream baos = new ByteArrayOutputStream();

  try {
   message.writeTo(baos);
   baos.flush();
   baos.close();

   ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
   SAXReader saxReader = new SAXReader();
   Document doc = saxReader.read(bais);
   doc = process(doc);
   DocumentSource ds = new DocumentSource(doc);
   soapPart.setContent(ds);
   message.saveChanges();
  } catch (Exception e) {
   throw new AxisFault("Error Caught processing document in XMLManipulationHandler", e);
  }
 }
}

}


public interface ProcessingHandler {
    public Node process(Node node);
}


public class NamespaceRemovalHandler implements ProcessingHandler {
private static Log log = LogFactory.getLog(NamespaceRemovalHandler.class);
private Namespace namespace;
private String targetElement;
private Set ignoreElements;

public NamespaceRemovalHandler() {
 ignoreElements = new HashSet();
}

public Node process(Node node) {
 if (node instanceof Element) {
  Element element = (Element) node;
  if (element.isRootElement()) {
   // Evidently, we never actually see the root node when we're called from
   // SOAP...
  } else {
   if (element.getName().equals(targetElement)) {
    log.trace("Found the target Element.  Adding requested namespace");
    Namespace already = element.getNamespaceForURI(namespace.getURI());
    if (already == null) {
     element.add(namespace);
    }
   } else if (!ignoreElements.contains(element.getName())) {
    Namespace target = element.getNamespaceForURI(namespace.getURI());
    if (target != null) {
     element.remove(target);
     element.setQName(new QName(element.getName(), namespace));
    }
   }
   Attribute type = element.attribute("type");
   if (type != null) {
    log.trace("Replacing type information: " + type.getText());
    String typeText = type.getText();
    typeText = typeText.replaceAll("ns[0-9]+", namespace.getPrefix());
    type.setText(typeText);
   }
  }
 }

 return node;
}

public Namespace getNamespace() {
 return namespace;
}

public void setNamespace(Namespace namespace) {
 this.namespace = namespace;
}

/**
 * @return the targetElement
 */
public String getTargetElement() {
 return targetElement;
}

/**
 * @param targetElement the targetElement to set
 */
public void setTargetElement(String targetElement) {
 this.targetElement = targetElement;
}

/**
 * @return the ignoreElements
 */
public Set getIgnoreElements() {
 return ignoreElements;
}

/**
 * @param ignoreElements the ignoreElements to set
 */
public void setIgnoreElements(Set ignoreElements) {
 this.ignoreElements = ignoreElements;
}

public void addIgnoreElement(String element) {
 this.ignoreElements.add(element);
}
}

No warranty, etc, etc.

Ian McLaird
+1  A: 

Alter your client's wsdd to set enableNamespacePrefixOptimization to true

<globalConfiguration >
  <parameter name="enableNamespacePrefixOptimization" value="true"/>
Stephen Denne
Is this documented anywhere? I'd like a good list of what I can do to configure the client, preferably without reading the actual source code.
Ian McLaird
I found that parameter by looking through an old project. Does it work?
Stephen Denne
A: 

Ian, would You be willing to share that BasicHandler? It might be great, while waiting for an official solution.

I can be reached from [email protected] if that sharing is possible.

Thanks, jarif

enableNamespacePrefixOptimization does not work, at all. I tried to set it false from true and no difference.

Wow, I should really keep up on my old answers. Code will be forthcoming.
Ian McLaird
A: 

Hello Christian/Jari, did you get any official solution for you problem? we are facing the same issue.

No, I don't have a solution. We accepted the situation for now, until our client can upgrade to a newer Axis version.
Christian Berg
A: 

Ian, would You be willing to share that BasicHandler? If not, please let me know the details of the class like whether it has to extend any class ..

I can be reachable in the below email [email protected]