/*
* Copyright (c) 2010-2015 Evolveum
*
* Licensed 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 com.evolveum.midpoint.model.impl;
import com.evolveum.midpoint.model.api.ModelPort;
import com.evolveum.midpoint.prism.PrismContext;
import com.evolveum.midpoint.schema.result.OperationResult;
import com.evolveum.midpoint.schema.util.MiscSchemaUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectDeltaOperationListType;
import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectListType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.TaskType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.UserType;
import com.evolveum.midpoint.xml.ns._public.common.fault_3.FaultMessage;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteChangesResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteChangesType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteScriptsResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ExecuteScriptsType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.FindShadowOwnerResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.FindShadowOwnerType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.GetObjectResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.GetObjectType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ImportFromResourceResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.ImportFromResourceType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.NotifyChangeResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.NotifyChangeType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.SearchObjectsResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.SearchObjectsType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.TestResourceResponseType;
import com.evolveum.midpoint.xml.ns._public.model.model_3.TestResourceType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import javax.xml.namespace.QName;
import javax.xml.soap.Detail;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPFault;
import javax.xml.transform.dom.DOMSource;
import javax.xml.ws.Holder;
import javax.xml.ws.Provider;
import javax.xml.ws.soap.SOAPFaultException;
import java.io.PrintWriter;
import java.io.StringWriter;
/**
*
* @author mederly
*
*/
@Service
public class ModelWebServiceRaw implements Provider<DOMSource> {
private static final Trace LOGGER = TraceManager.getTrace(ModelWebServiceRaw.class);
public static final String NS_SOAP11_ENV = "http://schemas.xmlsoap.org/soap/envelope/";
public static final String NS_SOAP11_ENV_PREFIX = "SOAP-ENV";
public static final QName SOAP11_FAULT = new QName(NS_SOAP11_ENV, "Fault");
public static final QName SOAP11_FAULTCODE = new QName("", "faultcode");
public static final String SOAP11_FAULTCODE_SERVER = NS_SOAP11_ENV_PREFIX + ":Server";
public static final QName SOAP11_FAULTSTRING = new QName("", "faultstring");
public static final QName SOAP11_FAULTACTOR = new QName("", "faultactor");
public static final QName SOAP11_FAULT_DETAIL = new QName("", "detail");
public static final String ACTOR = "TODO";
@Autowired
private ModelWebService ws;
@Autowired
private PrismContext prismContext;
@Override
public DOMSource invoke(DOMSource request) {
try {
return invokeAllowingFaults(request);
} catch (FaultMessage faultMessage) {
try {
SOAPFactory factory = SOAPFactory.newInstance();
SOAPFault soapFault = factory.createFault();
soapFault.setFaultCode(SOAP11_FAULTCODE_SERVER); // todo here is a constant until we have a mechanism to determine the correct value (client / server)
soapFault.setFaultString(faultMessage.getMessage());
Detail detail = soapFault.addDetail();
serializeFaultMessage(detail, faultMessage);
// fault actor?
// stack trace of the outer exception (FaultMessage) is unimportant, because it is always created at one place
// todo consider providing stack trace of the inner exception
//Detail detail = soapFault.addDetail();
//detail.setTextContent(getStackTraceAsString(faultMessage));
throw new SOAPFaultException(soapFault);
} catch (SOAPException e) {
throw new RuntimeException("SOAP Exception: " + e.getMessage(), e);
}
}
}
public DOMSource invokeAllowingFaults(DOMSource request) throws FaultMessage {
Node rootNode = request.getNode();
Element rootElement;
if (rootNode instanceof Document) {
rootElement = ((Document) rootNode).getDocumentElement();
} else if (rootNode instanceof Element) {
rootElement = (Element) rootNode;
} else {
throw ws.createIllegalArgumentFault("Unexpected DOM node type: " + rootNode);
}
Object requestObject;
try {
requestObject = prismContext.parserFor(rootElement).parseRealValue();
} catch (SchemaException e) {
throw ws.createIllegalArgumentFault("Couldn't parse SOAP request body because of schema exception: " + e.getMessage());
}
Node response;
Holder<OperationResultType> operationResultTypeHolder = new Holder<>();
try {
if (requestObject instanceof GetObjectType) {
GetObjectType g = (GetObjectType) requestObject;
Holder<ObjectType> objectTypeHolder = new Holder<>();
ws.getObject(g.getObjectType(), g.getOid(), g.getOptions(), objectTypeHolder, operationResultTypeHolder);
GetObjectResponseType gr = new GetObjectResponseType();
gr.setObject(objectTypeHolder.value);
gr.setResult(operationResultTypeHolder.value);
response = prismContext.domSerializer().serializeAnyData(gr, ModelPort.GET_OBJECT_RESPONSE);
} else if (requestObject instanceof SearchObjectsType) {
SearchObjectsType s = (SearchObjectsType) requestObject;
Holder<ObjectListType> objectListTypeHolder = new Holder<>();
ws.searchObjects(s.getObjectType(), s.getQuery(), s.getOptions(), objectListTypeHolder, operationResultTypeHolder);
SearchObjectsResponseType sr = new SearchObjectsResponseType();
sr.setObjectList(objectListTypeHolder.value);
sr.setResult(operationResultTypeHolder.value);
response = prismContext.domSerializer().serializeAnyData(sr, ModelPort.SEARCH_OBJECTS_RESPONSE);
} else if (requestObject instanceof ExecuteChangesType) {
ExecuteChangesType e = (ExecuteChangesType) requestObject;
ObjectDeltaOperationListType objectDeltaOperationListType = ws.executeChanges(e.getDeltaList(), e.getOptions());
ExecuteChangesResponseType er = new ExecuteChangesResponseType();
er.setDeltaOperationList(objectDeltaOperationListType);
response = prismContext.domSerializer().serializeAnyData(er, ModelPort.EXECUTE_CHANGES_RESPONSE);
} else if (requestObject instanceof FindShadowOwnerType) {
FindShadowOwnerType f = (FindShadowOwnerType) requestObject;
Holder<UserType> userTypeHolder = new Holder<>();
ws.findShadowOwner(f.getShadowOid(), userTypeHolder, operationResultTypeHolder);
FindShadowOwnerResponseType fsr = new FindShadowOwnerResponseType();
fsr.setUser(userTypeHolder.value);
fsr.setResult(operationResultTypeHolder.value);
response = prismContext.domSerializer().serializeAnyData(fsr, ModelPort.FIND_SHADOW_OWNER_RESPONSE);
} else if (requestObject instanceof TestResourceType) {
TestResourceType tr = (TestResourceType) requestObject;
OperationResultType operationResultType = ws.testResource(tr.getResourceOid());
TestResourceResponseType trr = new TestResourceResponseType();
trr.setResult(operationResultType);
response = prismContext.domSerializer().serializeAnyData(trr, ModelPort.TEST_RESOURCE_RESPONSE);
} else if (requestObject instanceof ExecuteScriptsType) {
ExecuteScriptsType es = (ExecuteScriptsType) requestObject;
ExecuteScriptsResponseType esr = ws.executeScripts(es);
response = prismContext.domSerializer().serializeAnyData(esr, ModelPort.EXECUTE_SCRIPTS_RESPONSE);
} else if (requestObject instanceof ImportFromResourceType) {
ImportFromResourceType ifr = (ImportFromResourceType) requestObject;
TaskType taskType = ws.importFromResource(ifr.getResourceOid(), ifr.getObjectClass());
ImportFromResourceResponseType ifrr = new ImportFromResourceResponseType();
ifrr.setTask(taskType);
response = prismContext.domSerializer().serializeAnyData(ifrr, ModelPort.IMPORT_FROM_RESOURCE_RESPONSE);
} else if (requestObject instanceof NotifyChangeType) {
NotifyChangeType nc = (NotifyChangeType) requestObject;
TaskType taskType = ws.notifyChange(nc.getChangeDescription());
NotifyChangeResponseType ncr = new NotifyChangeResponseType();
ncr.setTask(taskType);
response = prismContext.domSerializer().serializeAnyData(ncr, ModelPort.NOTIFY_CHANGE_RESPONSE);
} else {
throw ws.createIllegalArgumentFault("Unsupported request type: " + requestObject);
}
} catch (SchemaException e) {
throwFault(e, operationResultTypeHolder.value);
// not reached
return null;
}
// brutal hack for MID-2001 (serializing and parsing eliminates the problem!)
//String serialized = DOMUtil.printDom(response).toString();
//LOGGER.trace("WEB SERVICE RESPONSE:\n{}", serialized);
//response = DOMUtil.parseDocument(serialized);
return new DOMSource(response);
}
private void serializeFaultMessage(Detail detail, FaultMessage faultMessage) {
MiscSchemaUtil.serializeFaultMessage(detail, faultMessage, prismContext, LOGGER);
}
private void throwFault(Exception ex, OperationResultType resultType) throws FaultMessage {
if (resultType != null) {
ws.throwFault(ex, OperationResult.createOperationResult(resultType));
} else {
ws.throwFault(ex, null);
}
}
}