/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF 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.apache.yoko.bindings.corba.interceptors;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.ws.Holder;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.jaxb.JAXBUtils;
import org.apache.cxf.jaxb.WrapperHelper;
import org.apache.cxf.jaxb.io.EventDataReader;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.model.BindingInfo;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.service.model.InterfaceInfo;
import org.apache.cxf.service.model.MessageInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.service.model.ServiceInfo;
import org.apache.cxf.ws.addressing.EndpointReferenceType;
import org.apache.schemas.yoko.bindings.corba.ArgType;
import org.apache.schemas.yoko.bindings.corba.ModeType;
import org.apache.schemas.yoko.bindings.corba.OperationType;
import org.apache.schemas.yoko.bindings.corba.ParamType;
import org.apache.schemas.yoko.bindings.corba.TypeMappingType;
import org.apache.yoko.bindings.corba.ContextUtils;
import org.apache.yoko.bindings.corba.CorbaDestination;
import org.apache.yoko.bindings.corba.CorbaMessage;
import org.apache.yoko.bindings.corba.CorbaStaxObject;
import org.apache.yoko.bindings.corba.CorbaStreamable;
import org.apache.yoko.bindings.corba.CorbaTypeMap;
import org.apache.yoko.bindings.corba.CorbaUtils;
import org.apache.yoko.bindings.corba.types.CorbaHandlerUtils;
import org.apache.yoko.bindings.corba.types.CorbaObjectHandler;
import org.apache.yoko.wsdl.CorbaConstants;
import org.omg.CORBA.Any;
import org.omg.CORBA.NVList;
import org.omg.CORBA.ORB;
import org.omg.CORBA.ServerRequest;
public class CorbaInInterceptor extends AbstractPhaseInterceptor<Message> {
protected static CorbaStaxObject corbaStaxObject;
private List<CorbaTypeMap> typeMaps;
private XMLOutputFactory xof;
private XMLInputFactory xif;
private ORB orb;
private ServiceInfo service;
public CorbaInInterceptor() {
super();
setPhase(Phase.UNMARSHAL);
corbaStaxObject = new CorbaStaxObject();
}
public void setOrb(ORB mOrb) {
orb = mOrb;
}
public void handleMessage(Message msg) {
try {
CorbaMessage message = (CorbaMessage) msg;
CorbaDestination destination = null;
if (message.getDestination() != null) {
destination = (CorbaDestination)message.getDestination();
} else {
destination = (CorbaDestination)message.getExchange().getDestination();
}
typeMaps = new ArrayList<CorbaTypeMap>();
service = destination.getBindingInfo().getService();
List<TypeMappingType> corbaTypes = service.getDescription().getExtensors(TypeMappingType.class);
if (corbaTypes != null) {
CorbaUtils.createCorbaTypeMap(typeMaps, corbaTypes);
corbaStaxObject.setTypeMaps(typeMaps);
corbaStaxObject.setServiceInfo(service);
}
// TODO: where does encoding constant go?
//String encoding = (String)message.get("Encoding");
// check to see if we have an input or output message
if (!ContextUtils.isRequestor(msg)) {
handleNotRequestMessage(message, destination);
} else {
handleRequestMessage(message, destination);
}
} catch (Exception ex) {
throw new Fault(ex);
}
}
protected void handleNotRequestMessage(CorbaMessage message,
CorbaDestination destination)
throws Exception {
QName opQName = null;
OperationType opType = null;
BindingInfo bInfo = destination.getBindingInfo();
InterfaceInfo info = bInfo.getInterface();
EventDataReader reader = (EventDataReader) ContextUtils.getDataReader(message);
Exchange exchange = message.getExchange();
orb = (ORB)exchange.get(ORB.class);
if (corbaStaxObject != null) {
corbaStaxObject.setOrb(orb);
} else {
corbaStaxObject = new CorbaStaxObject(orb);
}
String opName = message.getExchange().get(String.class);
Iterator i = bInfo.getOperations().iterator();
BindingOperationInfo bopInfo = null;
while (i.hasNext()) {
bopInfo = (BindingOperationInfo)i.next();
if (bopInfo.getName().getLocalPart().equals(opName)) {
opType = bopInfo.getExtensor(OperationType.class);
opQName = bopInfo.getName();
break;
}
}
ServerRequest request = exchange.get(ServerRequest.class);
NVList list = prepareArguments(message, destination, info, opType, opQName);
request.arguments(list);
message.setList(list);
OperationInfo opInfo = processWrappedOperation(bopInfo, false);
addUnmarshalParams(message,
message,
info,
opType,
opInfo,
reader,
false);
addWrapperParams(message, bopInfo, false);
}
protected void handleRequestMessage(CorbaMessage message,
CorbaDestination destination)
throws Exception {
OperationType opType = null;
orb = (org.omg.CORBA.ORB) message.get(CorbaConstants.ORB);
if (corbaStaxObject != null) {
corbaStaxObject.setOrb(orb);
} else {
corbaStaxObject = new CorbaStaxObject(orb);
}
if (message.getStreamableException() != null) {
Endpoint ep = message.getExchange().get(Endpoint.class);
message.getInterceptorChain().abort();
if (ep.getInFaultObserver() != null) {
ep.getInFaultObserver().onMessage(message);
return;
}
}
EventDataReader reader;
reader = (EventDataReader) ContextUtils.getDataReader(message);
BindingInfo bInfo = destination.getBindingInfo();
InterfaceInfo info = bInfo.getInterface();
Exchange exchange = message.getExchange();
BindingOperationInfo bopInfo = exchange.get(BindingOperationInfo.class);
// Handle the parameters that are given for the operation
List<ParamType> paramTypes = null;
ArgType argType = null;
if (opType != null) {
paramTypes = opType.getParam();
argType = opType.getReturn();
}
CorbaMessage outMessage = (CorbaMessage)exchange.getOutMessage();
opType = bopInfo.getExtensor(OperationType.class);
OperationInfo opInfo = processWrappedOperation(bopInfo, true);
writeReturnValue(message, outMessage, opInfo, argType, reader);
addUnmarshalParams(outMessage,
message,
info,
opType,
opInfo,
reader,
true);
addWrapperParams(message, bopInfo, true);
}
/**
* REVISIT, hack to workaround 2 problems with cxf
* 1. the message part type class is not set for inner parts w.r.t wrapped doc-style wsdl
* 2. Since corba binding doesn't depend on wrapped doc-style, there is no need for cxf jaxws
* WrapperClassIn & WrapperClassOut interceptors.
*/
protected void addWrapperParams(Message message, BindingOperationInfo bopInfo, boolean isOutput)
throws Exception {
if (bopInfo.isUnwrappedCapable()) {
OperationInfo opInfo = bopInfo.getOperationInfo();
MessageInfo msgInfo = null;
if (isOutput) {
msgInfo = opInfo.getOutput();
} else {
msgInfo = opInfo.getInput();
}
Class wrapperTypeClass = msgInfo.getMessageParts().get(0).getTypeClass();
opInfo = opInfo.getUnwrappedOperation();
if (isOutput) {
msgInfo = opInfo.getOutput();
} else {
msgInfo = opInfo.getInput();
}
List objs = message.getContent(List.class);
if (objs != null) {
Object wrapperType = wrapperTypeClass.newInstance();
int i = 0;
for (MessagePartInfo p : msgInfo.getMessageParts()) {
Object part = objs.get(i);
WrapperHelper.setWrappedPart(p.getName().getLocalPart(), wrapperType, part);
i++;
}
objs = new ArrayList<Object>();
objs.add(wrapperType);
message.setContent(List.class, objs);
}
}
}
/**
* REVISIT, hack to workaround 2 problems with cxf
* 1. the message part type class is not set for inner parts w.r.t wrapped doc-style wsdl
* 2. Since corba binding doesn't depend on wrapped doc-style, there is no need for cxf jaxws
* WrapperClassIn & WrapperClassOut interceptors.
*/
protected OperationInfo processWrappedOperation(BindingOperationInfo bopInfo, boolean isOutput)
throws Exception {
OperationInfo opInfo = bopInfo.getOperationInfo();
MessageInfo msgInfo = null;
if (bopInfo.isUnwrappedCapable()) {
if (isOutput) {
msgInfo = opInfo.getOutput();
} else {
msgInfo = opInfo.getInput();
}
Class wrapperTypeClass = msgInfo.getMessageParts().get(0).getTypeClass();
opInfo = opInfo.getUnwrappedOperation();
if (isOutput) {
msgInfo = opInfo.getOutput();
} else {
msgInfo = opInfo.getInput();
}
for (MessagePartInfo part : msgInfo.getMessageParts()) {
String elementType = null;
if (part.isElement()) {
elementType = part.getElementQName().getLocalPart();
} else if (part.getTypeQName() == null) {
// handling anonymous complex type
elementType = null;
} else {
elementType = part.getTypeQName().getLocalPart();
}
part.setTypeClass(getWrappedPartClass(part.getName().getLocalPart(),
wrapperTypeClass,
elementType));
}
}
return opInfo;
}
protected void writeReturnValue(CorbaMessage message,
CorbaMessage outMessage,
OperationInfo opInfo,
ArgType argType,
EventDataReader reader)
throws Exception {
Object retValue = null;
if (outMessage.getStreamableReturn() != null) {
MessageInfo msgInfo = opInfo.getOutput();
// Handle the parameters that are given for the operation
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES,
Boolean.TRUE);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
XMLEventWriter evtWriter = outputFactory.createXMLEventWriter(outStream);
CorbaStreamable retVal = outMessage.getStreamableReturn();
corbaStaxObject.writeObjectToStax(retVal.getObject(), evtWriter,
XMLEventFactory.newInstance());
evtWriter.flush();
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
XMLEventReader evtReader = inputFactory.createXMLEventReader(inStream);
MessagePartInfo part = getReturnMessagePartInfo(msgInfo);
retValue = reader.read(part, evtReader);
List<Object> args = new ArrayList<Object>();
args.add(retValue);
message.setContent(List.class, args);
}
}
protected void addUnmarshalParams(CorbaMessage msg,
CorbaMessage message,
InterfaceInfo info,
OperationType opType,
OperationInfo opInfo,
EventDataReader reader,
boolean isOutput)
throws Exception {
MessageInfo msgInfo;
if (isOutput) {
msgInfo = opInfo.getOutput();
} else {
msgInfo = opInfo.getInput();
}
List<ParamType> params = opType.getParam();
CorbaStreamable[] streamables = msg.getStreamableArguments();
List args = message.getContent(List.class);
if (args == null) {
args = new ArrayList<Object>();
}
int index = 0;
for (int i = 0; i < params.size(); i++) {
Object obj = null;
ParamType param = params.get(i);
boolean skipRead = false;
if (!ContextUtils.isRequestor(msg)) {
if (param.getMode().equals(ModeType.OUT)) {
skipRead = true;
}
} else if (param.getMode().equals(ModeType.IN)) {
skipRead = true;
}
if (!skipRead) {
XMLInputFactory inputFactory = getXMLInputFactory();
XMLOutputFactory outputFactory = getXMLOutputFactory();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
XMLEventWriter evtWriter = outputFactory.createXMLEventWriter(outStream);
corbaStaxObject.writeObjectToStax(streamables[i].getObject(),
evtWriter,
XMLEventFactory.newInstance());
evtWriter.flush();
ByteArrayInputStream inStream = new ByteArrayInputStream(outStream.toByteArray());
XMLEventReader evtReader = inputFactory.createXMLEventReader(inStream);
MessagePartInfo part = getMessagePartInfo(msgInfo,
index,
opType.getReturn() == null,
isOutput);
Object partObj = reader.read(part, evtReader);
args.add(partObj);
index++;
} else if (!isOutput) {
args.add(obj);
}
}
message.setContent(List.class, args);
}
protected NVList prepareArguments(CorbaMessage corbaMsg,
CorbaDestination destination,
InterfaceInfo info,
OperationType opType,
QName opQName)
throws Exception {
BindingInfo bInfo = destination.getBindingInfo();
EndpointInfo eptInfo = destination.getEndPointInfo();
BindingOperationInfo bOpInfo = bInfo.getOperation(opQName);
OperationInfo opInfo = bOpInfo.getOperationInfo();
Exchange exg = corbaMsg.getExchange();
exg.put(BindingInfo.class, bInfo);
exg.put(InterfaceInfo.class, info);
exg.put(EndpointInfo.class, eptInfo);
exg.put(EndpointReferenceType.class, destination.getAddress());
exg.put(ServiceInfo.class, service);
exg.put(BindingOperationInfo.class, bOpInfo);
exg.put(OperationInfo.class, opInfo);
exg.put(MessageInfo.class, opInfo.getInput());
exg.put(String.class, opQName.getLocalPart());
exg.setInMessage(corbaMsg);
corbaMsg.put(MessageInfo.class, opInfo.getInput());
List<ParamType> paramTypes = opType.getParam();
CorbaStreamable[] arguments = new CorbaStreamable[paramTypes.size()];
NVList list = prepareDIIArgsList(corbaMsg, arguments, paramTypes, typeMaps);
return list;
}
protected NVList prepareDIIArgsList(CorbaMessage corbaMsg,
CorbaStreamable[] streamables,
List<ParamType> paramTypes,
List<CorbaTypeMap> maps)
throws Exception {
// Build the list of DII arguments, returns, and exceptions
NVList list = orb.create_list(streamables.length);
prepareArgs(corbaMsg, paramTypes);
for (int i = 0; i < paramTypes.size(); i++) {
ParamType param = paramTypes.get(i);
QName paramIdlType = param.getIdltype();
QName paramName = new QName("", param.getName());
ModeType paramMode = param.getMode();
CorbaObjectHandler obj =
CorbaHandlerUtils.initializeObjectHandler(orb, paramName, paramIdlType, maps, service);
streamables[i] = new CorbaStreamable(obj, paramName);
if (paramMode.value().equals("in")) {
streamables[i].setMode(org.omg.CORBA.ARG_IN.value);
} else if (paramMode.value().equals("out")) {
streamables[i].setMode(org.omg.CORBA.ARG_OUT.value);
} else {
streamables[i].setMode(org.omg.CORBA.ARG_INOUT.value);
}
Any value = orb.create_any();
value.insert_Streamable(streamables[i]);
list.add_value(streamables[i].getName(), value, streamables[i].getMode());
corbaMsg.addStreamableArgument(streamables[i]);
}
return list;
}
protected void prepareArgs(CorbaMessage corbaMsg, List<ParamType> paramTypes)
throws Exception {
List<Object> args = new ArrayList<Object>();
int idx = 0;
for (ParamType param : paramTypes) {
Class cls = param.getIdltype().getLocalPart().getClass();
if (cls.isAssignableFrom(Holder.class)) {
args.add(cls.newInstance());
}
idx++;
}
corbaMsg.setContent(List.class, args);
}
protected XMLOutputFactory getXMLOutputFactory() {
if (xof == null) {
xof = XMLOutputFactory.newInstance();
xof.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, Boolean.TRUE);
}
return xof;
}
protected XMLInputFactory getXMLInputFactory() {
if (xif == null) {
xif = XMLInputFactory.newInstance();
}
return xif;
}
protected MessagePartInfo getMessagePartInfo(MessageInfo msgInfo,
int index,
boolean isVoidReturn,
boolean isOutput) {
List<MessagePartInfo> parts = msgInfo.getMessageParts();
if (isOutput && !isVoidReturn) {
index++;
}
MessagePartInfo part = parts.get(index);
return part;
}
protected MessagePartInfo getReturnMessagePartInfo(MessageInfo msgInfo) {
List<MessagePartInfo> parts = msgInfo.getMessageParts();
MessagePartInfo part = parts.get(0);
return part;
}
public static Class getWrappedPartClass(String partName, Class wrapperType, String elementType)
throws Exception {
String accessor = JAXBUtils.nameToIdentifier(partName, JAXBUtils.IdentifierType.GETTER);
if (elementType != null && "boolean".equals(elementType.toLowerCase())) {
// JAXB Exception to get the Boolean property
accessor = accessor.replaceFirst("get", "is");
}
for (Method method : wrapperType.getMethods()) {
if (method.getParameterTypes().length == 0 && accessor.equals(method.getName())) {
return method.getReturnType();
}
}
return null;
}
}