/*
* 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);
}
}
}
}