/* * Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.wso2.carbon.mediator.fault; import org.apache.axiom.soap.SOAP11Constants; import org.wso2.carbon.mediator.service.ui.AbstractMediator; import org.wso2.carbon.mediator.service.MediatorException; import org.apache.axiom.om.*; import org.apache.axiom.soap.SOAP12Constants; import org.apache.synapse.util.xpath.SynapseXPath; import org.apache.synapse.config.xml.SynapseXPathSerializer; import org.apache.synapse.config.xml.XMLConfigConstants; import org.apache.synapse.config.xml.OMElementUtils; import org.apache.synapse.config.xml.SynapseXPathFactory; import org.jaxen.JaxenException; import javax.xml.namespace.QName; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import java.util.ArrayList; import java.util.Iterator; public class FaultMediator extends AbstractMediator { public static final String WSA_ACTION = "Action"; /** Make a SOAP 1.1 fault */ public static final int SOAP11 = 1; /** Make a SOAP 1.2 fault */ public static final int SOAP12 = 2; /** Make a POX fault */ public static final int POX = 3; /** Holds the SOAP version to be used to make the fault, if specified */ private int soapVersion = 1; /** Whether to mark the created fault as a response or not */ private boolean markAsResponse = true; /** Whether it is required to serialize the response attribute or not */ private boolean serializeResponse = false; // -- fault elements -- /** The fault code QName to be used */ private QName faultCodeValue = null; /** An XPath expression that will give the fault code QName at runtime */ private SynapseXPath faultCodeExpr = null; /** The fault reason to be used */ private String faultReasonValue = null; /** An XPath expression that will give the fault reason string at runtime */ private SynapseXPath faultReasonExpr = null; /** The fault node URI to be used */ private URI faultNode = null; /** The fault role URI to be used - if applicable */ private URI faultRole = null; /** The fault detail to be used */ private String faultDetail = null; /** An XPath expression that will give the fault code QName at runtime */ private SynapseXPath faultDetailExpr = null; /** array of fault detail elements */ private List<OMElement> faultDetailElements = new ArrayList<OMElement>(); private static final String SOAP11_STRING = "soap11"; private static final String SOAP12_STRING = "soap12"; private static final String POX_STRING = "pox"; public String getTagLocalName() { return "makefault"; } public int getSoapVersion() { return soapVersion; } public void setSoapVersion(int soapVersion) { this.soapVersion = soapVersion; } public boolean isMarkAsResponse() { return markAsResponse; } public void setMarkAsResponse(boolean markAsResponse) { this.markAsResponse = markAsResponse; } public boolean isSerializeResponse() { return serializeResponse; } public void setSerializeResponse(boolean serializeResponse) { this.serializeResponse = serializeResponse; } public QName getFaultCodeValue() { return faultCodeValue; } public void setFaultCodeValue(QName faultCodeValue) { if (soapVersion == SOAP11) { this.faultCodeValue = faultCodeValue; } else if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals( faultCodeValue.getNamespaceURI()) && (SOAP12Constants.FAULT_CODE_DATA_ENCODING_UNKNOWN.equals( faultCodeValue.getLocalPart()) || SOAP12Constants.FAULT_CODE_MUST_UNDERSTAND.equals( faultCodeValue.getLocalPart()) || SOAP12Constants.FAULT_CODE_RECEIVER.equals( faultCodeValue.getLocalPart()) || SOAP12Constants.FAULT_CODE_SENDER.equals( faultCodeValue.getLocalPart()) || SOAP12Constants.FAULT_CODE_VERSION_MISMATCH.equals( faultCodeValue.getLocalPart())) ) { this.faultCodeValue = faultCodeValue; } else { throw new MediatorException("Invalid Fault code value for a SOAP 1.2 fault : " + faultCodeValue); } } public SynapseXPath getFaultCodeExpr() { return faultCodeExpr; } public void setFaultCodeExpr(SynapseXPath faultCodeExpr) { this.faultCodeExpr = faultCodeExpr; } public String getFaultReasonValue() { return faultReasonValue; } public void setFaultReasonValue(String faultReasonValue) { this.faultReasonValue = faultReasonValue; } public SynapseXPath getFaultReasonExpr() { return faultReasonExpr; } public void setFaultReasonExpr(SynapseXPath faultReasonExpr) { this.faultReasonExpr = faultReasonExpr; } public URI getFaultNode() { return faultNode; } public void setFaultNode(URI faultNode) { if (soapVersion == SOAP11) { throw new MediatorException("A fault node does not apply to a SOAP 1.1 fault"); } this.faultNode = faultNode; } public URI getFaultRole() { return faultRole; } public void setFaultRole(URI faultRole) { this.faultRole = faultRole; } public String getFaultDetail() { return faultDetail; } public void setFaultDetail(String faultDetail) { this.faultDetail = faultDetail; } public SynapseXPath getFaultDetailExpr() { return faultDetailExpr; } public void setFaultDetailExpr(SynapseXPath faultDetailExpr) { this.faultDetailExpr = faultDetailExpr; } public List<OMElement> getFaultDetailElements() { return faultDetailElements; } public void addFaultDetailElement(OMElement element) { faultDetailElements.add(element); } public void addAllFaultDetailElements(List<OMElement> list) { faultDetailElements.addAll(list); } public OMElement removeFaultDetailElement(int pos) { return faultDetailElements.remove(pos); } public OMElement serialize(OMElement parent) { OMElement fault = fac.createOMElement("makefault", synNS); saveTracingState(fault, this); if (soapVersion == SOAP11) { fault.addAttribute(fac.createOMAttribute( "version", nullNS, SOAP11_STRING)); } else if(soapVersion == org.apache.synapse.mediators.transform.FaultMediator.SOAP12) { fault.addAttribute(fac.createOMAttribute( "version", nullNS, SOAP12_STRING)); } else if(soapVersion == org.apache.synapse.mediators.transform.FaultMediator.POX) { fault.addAttribute(fac.createOMAttribute( "version", nullNS, POX_STRING)); } if (serializeResponse) { if (markAsResponse) { fault.addAttribute(fac.createOMAttribute("response", nullNS, "true")); } else { fault.addAttribute(fac.createOMAttribute("response", nullNS, "false")); } } OMElement code = soapVersion != POX ?fac.createOMElement("code", synNS, fault):null; if (faultCodeValue != null && code != null) { OMNamespace ns = code.declareNamespace(faultCodeValue.getNamespaceURI(), faultCodeValue.getPrefix()); code.addAttribute(fac.createOMAttribute( "value", nullNS, ns.getPrefix() + ":" + faultCodeValue.getLocalPart())); } else if (faultCodeExpr != null) { SynapseXPathSerializer.serializeXPath(faultCodeExpr, code, "expression"); } else if (soapVersion != POX) { throw new MediatorException("Fault code is required for a fault " + "mediator unless it is a pox fault"); } OMElement reason = fac.createOMElement("reason", synNS, fault); if (faultReasonValue != null) { reason.addAttribute(fac.createOMAttribute( "value", nullNS, faultReasonValue)); } else if (faultReasonExpr != null) { SynapseXPathSerializer.serializeXPath( faultReasonExpr, reason, "expression"); } else if (soapVersion != POX) { throw new MediatorException("Fault reason is required for a fault " + "mediator unless it is a pox fault"); } if (faultNode != null && (soapVersion != SOAP11 && soapVersion != POX)) { OMElement node = fac.createOMElement("node", synNS, fault); node.setText(faultNode.toString()); } if (faultRole != null && soapVersion != POX) { OMElement role = fac.createOMElement("role", synNS, fault); role.setText(faultRole.toString()); } if (faultDetailExpr != null) { OMElement detail = fac.createOMElement("detail", synNS, fault); SynapseXPathSerializer.serializeXPath( faultDetailExpr, detail, "expression"); } else if (faultDetail != null) { OMElement detail = fac.createOMElement("detail", synNS, fault); detail.setText(faultDetail); } else if (faultDetailElements.size() > 0) { OMElement detail = fac.createOMElement("detail", synNS, fault); for (OMElement e : faultDetailElements) { detail.addChild(e); } } if (parent != null) { parent.addChild(fault); } return fault; } private static final QName ATT_VERSION_Q = new QName(XMLConfigConstants.NULL_NAMESPACE, "version"); private static final QName ATT_RESPONSE_Q = new QName(XMLConfigConstants.NULL_NAMESPACE, "response"); private static final QName CODE_Q = new QName(XMLConfigConstants.SYNAPSE_NAMESPACE, "code"); private static final QName REASON_Q = new QName(XMLConfigConstants.SYNAPSE_NAMESPACE, "reason"); private static final QName NODE_Q = new QName(XMLConfigConstants.SYNAPSE_NAMESPACE, "node"); private static final QName ROLE_Q = new QName(XMLConfigConstants.SYNAPSE_NAMESPACE, "role"); private static final QName DETAIL_Q = new QName(XMLConfigConstants.SYNAPSE_NAMESPACE, "detail"); public void build(OMElement elem) { OMAttribute version = elem.getAttribute(ATT_VERSION_Q); if (version != null) { if (SOAP11_STRING.equals(version.getAttributeValue())) { soapVersion = SOAP11; } else if (SOAP12_STRING.equals(version.getAttributeValue())) { soapVersion = SOAP12; } else if (POX_STRING.equals(version.getAttributeValue())) { soapVersion = POX; } else { throw new MediatorException("Invalid SOAP version"); } }else { //although not complete ,we will try to implicitly derive a SOAP version //we will check for available namesapaces and derive from that extractImplicitSoapVersionFrom(elem); } OMAttribute response = elem.getAttribute(ATT_RESPONSE_Q); if (response != null) { if ("true".equals(response.getAttributeValue())) { markAsResponse = true; } else if ("false".equals(response.getAttributeValue())) { markAsResponse = false; } else { throw new MediatorException("Invalid value '" + response.getAttributeValue() + "' passed as response. Expected 'true' or 'false'"); } serializeResponse = true; } OMElement code = elem.getFirstChildWithName(CODE_Q); if (code != null) { OMAttribute value = code.getAttribute(ATT_VALUE); OMAttribute expression = code.getAttribute(ATT_EXPRN); if (value != null) { String strValue = value.getAttributeValue(); String prefix = null; String name = null; if (strValue.indexOf(":") != -1) { prefix = strValue.substring(0, strValue.indexOf(":")); name = strValue.substring(strValue.indexOf(":")+1); } else { throw new MediatorException("A QName is expected for fault code as prefix:name"); } String namespaceURI = OMElementUtils.getNameSpaceWithPrefix(prefix, code); if (namespaceURI == null) { throw new MediatorException("Invalid namespace prefix '" + prefix + "' in code attribute"); } faultCodeValue = new QName(namespaceURI, name, prefix); } else if (expression != null) { try { faultCodeExpr = SynapseXPathFactory.getSynapseXPath(code, ATT_EXPRN); } catch (JaxenException je) { throw new MediatorException("Invalid fault code expression : " + je.getMessage()); } } else { throw new MediatorException("A 'value' or 'expression' attribute must specify the fault code"); } } else if (soapVersion != POX) { throw new MediatorException("The fault code is a required attribute for the " + "makefault mediator unless it is a pox fault"); } OMElement reason = elem.getFirstChildWithName(REASON_Q); if (reason != null) { OMAttribute value = reason.getAttribute(ATT_VALUE); OMAttribute expression = reason.getAttribute(ATT_EXPRN); if (value != null) { faultReasonValue = value.getAttributeValue(); } else if (expression != null) { try { faultReasonExpr = SynapseXPathFactory.getSynapseXPath(reason, ATT_EXPRN); } catch (JaxenException je) { throw new MediatorException("Invalid fault reason expression : " + je.getMessage()); } } else { throw new MediatorException("A 'value' or 'expression' attribute must specify the fault code"); } } else if (soapVersion != POX) { throw new MediatorException("The fault reason is a required attribute for the " + "makefault mediator unless it is a pox fault"); } // after successfully creating the mediator // set its common attributes such as tracing etc processAuditStatus(this, elem); OMElement node = elem.getFirstChildWithName(NODE_Q); if (node != null && node.getText() != null) { try { faultNode = new URI(node.getText()); } catch (URISyntaxException e) { throw new MediatorException("Invalid URI specified for fault node : " + node.getText()); } } OMElement role = elem.getFirstChildWithName(ROLE_Q); if (role != null && role.getText() != null) { try { faultRole = new URI(role.getText()); } catch (URISyntaxException e) { throw new MediatorException("Invalid URI specified for fault role : " + role.getText()); } } OMElement detail = elem.getFirstChildWithName(DETAIL_Q); if (detail != null) { OMAttribute detailExpr = detail.getAttribute(ATT_EXPRN); if (detailExpr != null && detailExpr.getAttributeValue() != null) { try { faultDetailExpr = SynapseXPathFactory.getSynapseXPath(detail, ATT_EXPRN); } catch (JaxenException e) { throw new MediatorException("Unable to build the XPath for fault detail " + "from the expression : " + detailExpr.getAttributeValue()); } } else if (detail.getFirstOMChild() != null) { OMNode detailNode = detail.getFirstOMChild(); if (detailNode instanceof OMText) { faultDetail = detail.getText(); } else if (detailNode instanceof OMElement) { Iterator it = detail.getChildElements(); while (it.hasNext()) { faultDetailElements.add((OMElement) it.next()) ; } } } } } public void extractImplicitSoapVersionFrom(OMElement elem) { boolean searchChildren = true; Iterator allNamespaces = elem.getAllDeclaredNamespaces(); while (allNamespaces.hasNext()) { OMNamespace ns = (OMNamespace) allNamespaces.next(); if (ns.getNamespaceURI().equals(SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI)) { searchChildren = false; soapVersion = SOAP12; break; } else if (ns.getNamespaceURI().equals(SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI)) { searchChildren = false; soapVersion = SOAP11; break; } } if(searchChildren){ Iterator children = elem.getChildElements(); while (children.hasNext()) { OMElement child = (OMElement) children.next(); extractImplicitSoapVersionFrom(child); } } } }