001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.interceptor;
019:
020: import java.lang.reflect.Constructor;
021: import java.util.ArrayList;
022: import java.util.HashMap;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.StringTokenizer;
026:
027: import javax.xml.namespace.QName;
028: import javax.xml.stream.XMLStreamException;
029: import javax.xml.stream.XMLStreamReader;
030: import javax.xml.xpath.XPathConstants;
031:
032: import org.w3c.dom.Element;
033: import org.w3c.dom.Node;
034:
035: import org.apache.cxf.common.util.StringUtils;
036: import org.apache.cxf.databinding.DataBinding;
037: import org.apache.cxf.databinding.DataReader;
038: import org.apache.cxf.helpers.DOMUtils;
039: import org.apache.cxf.helpers.XPathUtils;
040: import org.apache.cxf.message.Message;
041: import org.apache.cxf.phase.AbstractPhaseInterceptor;
042: import org.apache.cxf.phase.Phase;
043: import org.apache.cxf.service.Service;
044: import org.apache.cxf.service.model.BindingOperationInfo;
045: import org.apache.cxf.service.model.FaultInfo;
046: import org.apache.cxf.service.model.MessagePartInfo;
047: import org.apache.cxf.staxutils.W3CDOMStreamReader;
048:
049: /**
050: * Takes a Fault and converts it to a local exception type if possible.
051: *
052: * @author Dan Diephouse
053: */
054: public class ClientFaultConverter extends
055: AbstractPhaseInterceptor<Message> {
056:
057: public ClientFaultConverter() {
058: super (Phase.UNMARSHAL);
059: }
060:
061: public ClientFaultConverter(String phase) {
062: super (phase);
063: }
064:
065: public void handleMessage(Message msg) {
066: Fault fault = (Fault) msg.getContent(Exception.class);
067:
068: if (fault.getDetail() != null) {
069: processFaultDetail(fault, msg);
070: setStackTrace(fault, msg);
071: }
072: }
073:
074: protected void processFaultDetail(Fault fault, Message msg) {
075: Element exDetail = (Element) DOMUtils.getChild(fault
076: .getDetail(), Node.ELEMENT_NODE);
077: QName qname = new QName(exDetail.getNamespaceURI(), exDetail
078: .getLocalName());
079: FaultInfo faultWanted = null;
080: MessagePartInfo part = null;
081: BindingOperationInfo boi = msg.getExchange().get(
082: BindingOperationInfo.class);
083: if (boi.isUnwrapped()) {
084: boi = boi.getWrappedOperation();
085: }
086: for (FaultInfo faultInfo : boi.getOperationInfo().getFaults()) {
087: for (MessagePartInfo mpi : faultInfo.getMessageParts()) {
088: if (qname.equals(mpi.getConcreteName())) {
089: faultWanted = faultInfo;
090: part = mpi;
091: break;
092: }
093: }
094: if (faultWanted != null) {
095: break;
096: }
097: }
098: if (faultWanted == null) {
099: return;
100: }
101: Service s = msg.getExchange().get(Service.class);
102: DataBinding dataBinding = s.getDataBinding();
103:
104: Object e = null;
105: if (isDOMSupported(dataBinding)) {
106: DataReader<Node> reader = dataBinding
107: .createReader(Node.class);
108: reader.setProperty(DataReader.FAULT, fault);
109: e = reader.read(part, exDetail);
110: } else {
111: DataReader<XMLStreamReader> reader = dataBinding
112: .createReader(XMLStreamReader.class);
113: XMLStreamReader xsr = new W3CDOMStreamReader(exDetail);
114: try {
115: xsr.nextTag();
116: } catch (XMLStreamException e1) {
117: throw new Fault(e1);
118: }
119: reader.setProperty(DataReader.FAULT, fault);
120: e = reader.read(part, xsr);
121: }
122:
123: if (!(e instanceof Exception)) {
124: Class<?> exClass = faultWanted.getProperty(Class.class
125: .getName(), Class.class);
126: Class<?> beanClass = e.getClass();
127: try {
128: Constructor constructor = exClass
129: .getConstructor(new Class[] { String.class,
130: beanClass });
131: e = constructor.newInstance(new Object[] {
132: fault.getMessage(), e });
133: } catch (Exception e1) {
134: throw new Fault(e1);
135: }
136: }
137: msg.setContent(Exception.class, e);
138: }
139:
140: private boolean isDOMSupported(DataBinding db) {
141: boolean supportsDOM = false;
142: for (Class c : db.getSupportedWriterFormats()) {
143: if (c.equals(Node.class)) {
144: supportsDOM = true;
145: }
146: }
147: return supportsDOM;
148: }
149:
150: private void setStackTrace(Fault fault, Message msg) {
151: Map<String, String> ns = new HashMap<String, String>();
152: XPathUtils xu = new XPathUtils(ns);
153: String ss = (String) xu.getValue("//" + Fault.STACKTRACE
154: + "/text()", fault.getDetail(), XPathConstants.STRING);
155: List<StackTraceElement> stackTraceList = new ArrayList<StackTraceElement>();
156: if (StringUtils.isEmpty(ss)) {
157: StringTokenizer st = new StringTokenizer(ss, "\n");
158: while (st.hasMoreTokens()) {
159: String oneLine = st.nextToken();
160: StringTokenizer stInner = new StringTokenizer(oneLine,
161: "!");
162: StackTraceElement ste = new StackTraceElement(stInner
163: .nextToken(), stInner.nextToken(), stInner
164: .nextToken(), Integer.parseInt(stInner
165: .nextToken()));
166: stackTraceList.add(ste);
167: }
168: if (stackTraceList.size() > 0) {
169: StackTraceElement[] stackTraceElement = new StackTraceElement[stackTraceList
170: .size()];
171: Exception e = msg.getContent(Exception.class);
172: e.setStackTrace(stackTraceList
173: .toArray(stackTraceElement));
174: }
175: }
176:
177: }
178: }
|