blob: 55ce5e789d6b0b50a8714b1e5408270f62c44613 [file] [log] [blame]
/*******************************************************************************
* 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.ofbiz.service.eca;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.UtilGenerics;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.service.DispatchContext;
import org.apache.ofbiz.service.GenericServiceException;
import org.apache.ofbiz.service.LocalDispatcher;
import org.apache.ofbiz.service.ModelService;
import org.apache.ofbiz.service.ServiceSynchronization;
import org.apache.ofbiz.service.ServiceUtil;
import org.w3c.dom.Element;
/**
* ServiceEcaAction
*/
@SuppressWarnings("serial")
public class ServiceEcaAction implements java.io.Serializable {
public static final String module = ServiceEcaAction.class.getName();
protected String eventName = null;
protected String serviceName = null;
protected String serviceMode = null;
protected String resultMapName = null;
protected String runAsUser = null;
protected boolean newTransaction = false;
protected boolean resultToContext = true;
protected boolean resultToResult = false;
protected boolean ignoreFailure = false;
protected boolean ignoreError = false;
protected boolean persist = false;
protected ServiceEcaAction() {}
public ServiceEcaAction(Element action, String event) {
this.eventName = event;
this.serviceName = action.getAttribute("service");
this.serviceMode = action.getAttribute("mode");
this.runAsUser = action.getAttribute("run-as-user");
// support the old, inconsistent attribute name
if (UtilValidate.isEmpty(this.runAsUser)) this.runAsUser = action.getAttribute("runAsUser");
this.resultMapName = action.getAttribute("result-map-name");
// default is true, so anything but false is true
this.resultToContext = !"false".equals(action.getAttribute("result-to-context"));
// default is false, so anything but true is false
this.resultToResult = "true".equals(action.getAttribute("result-to-result"));
this.newTransaction = !"false".equals(action.getAttribute("new-transaction"));
this.ignoreFailure = !"false".equals(action.getAttribute("ignore-failure"));
this.ignoreError = !"false".equals(action.getAttribute("ignore-error"));
this.persist = "true".equals(action.getAttribute("persist"));
}
public String getServiceName() {
return this.serviceName;
}
public String getServiceMode() {
return this.serviceMode;
}
public boolean isPersist() {
return this.persist;
}
public String getShortDisplayDescription() {
return this.serviceName + "[" + this.serviceMode + (this.persist ? "-persist" : "") + "]";
}
public boolean runAction(String selfService, DispatchContext dctx, Map<String, Object> context, Map<String, Object> result) throws GenericServiceException {
if (serviceName.equals(selfService)) {
throw new GenericServiceException("Cannot invoke self on ECA.");
}
// pull out context parameters needed for this service.
Map<String, Object> actionContext = dctx.getModelService(serviceName).makeValid(context, ModelService.IN_PARAM);
// set the userLogin object in the context
actionContext.put("userLogin", ServiceUtil.getUserLogin(dctx, actionContext, runAsUser));
Map<String, Object> actionResult = null;
LocalDispatcher dispatcher = dctx.getDispatcher();
// if SECAs have been turned off, then just return true which has same effect as if secas ran successfully
if (dispatcher.isEcasDisabled()) {
Debug.logWarning("SECAs have been disabled on purpose and will not be run for [" + serviceName + "]", module);
return true;
}
if (eventName.startsWith("global-")) {
if (eventName.equals("global-rollback")) {
ServiceSynchronization.registerRollbackService(dctx, serviceName, runAsUser, context, "async".equals(serviceMode), persist); // using the actual context so we get updates
} else if (eventName.equals("global-commit")) {
ServiceSynchronization.registerCommitService(dctx, serviceName, runAsUser, context, "async".equals(serviceMode), persist); // using the actual context so we get updates
} else if (eventName.equals("global-commit-post-run")) {
ServiceSynchronization.registerCommitService(dctx, serviceName, runAsUser, context, "async".equals(serviceMode), persist); // using the actual context so we get updates
}
} else {
// standard ECA
if (this.serviceMode.equals("sync")) {
if (newTransaction) {
actionResult = dispatcher.runSync(this.serviceName, actionContext, -1, true);
} else {
actionResult = dispatcher.runSync(this.serviceName, actionContext);
}
} else if (this.serviceMode.equals("async")) {
dispatcher.runAsync(serviceName, actionContext, persist);
}
}
// put the results in to the defined map
if (UtilValidate.isNotEmpty(resultMapName)) {
Map<String, Object> resultMap = UtilGenerics.checkMap(context.get(resultMapName));
if (resultMap == null) {
resultMap = new HashMap<String, Object>();
}
resultMap.putAll(dctx.getModelService(this.serviceName).makeValid(actionResult, ModelService.OUT_PARAM, false, null));
context.put(resultMapName, resultMap);
}
// use the result to update the context fields.
if (resultToContext) {
context.putAll(dctx.getModelService(this.serviceName).makeValid(actionResult, ModelService.OUT_PARAM, false, null));
}
// use the result to update the result fields
if (resultToResult) {
Map<String, Object> normalizedActionResult = dctx.getModelService(selfService).makeValid(actionResult, ModelService.OUT_PARAM, false, null);
// don't copy over the error messages, use the combining code to do that later
normalizedActionResult.remove(ModelService.ERROR_MESSAGE);
normalizedActionResult.remove(ModelService.ERROR_MESSAGE_LIST);
normalizedActionResult.remove(ModelService.ERROR_MESSAGE_MAP);
normalizedActionResult.remove("failMessage");
result.putAll(normalizedActionResult);
}
// if we aren't ignoring errors check it here...
boolean success = true;
// don't do this if resultToResult, will already be copied over
if (actionResult != null && !resultToResult) {
if (!ignoreFailure) {
if (ModelService.RESPOND_FAIL.equals(actionResult.get(ModelService.RESPONSE_MESSAGE))) {
if (result != null) {
result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_FAIL);
}
success = false;
}
}
if (!ignoreError) {
if (ModelService.RESPOND_ERROR.equals(actionResult.get(ModelService.RESPONSE_MESSAGE))) {
if (result != null) {
result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_ERROR);
}
success = false;
}
}
}
// copy/combine error messages on error/failure (!success) or on resultToResult to combine any error info coming out, regardless of success status
if ((!success || resultToResult) && UtilValidate.isNotEmpty(actionResult)) {
String errorMessage = (String) actionResult.get(ModelService.ERROR_MESSAGE);
String failMessage = (String) actionResult.get("failMessage");
List<? extends Object> errorMessageList = UtilGenerics.checkList(actionResult.get(ModelService.ERROR_MESSAGE_LIST));
Map<String, ? extends Object> errorMessageMap = UtilGenerics.checkMap(actionResult.get(ModelService.ERROR_MESSAGE_MAP));
// do something with the errorMessage
if (UtilValidate.isNotEmpty(errorMessage)) {
if (UtilValidate.isEmpty(result.get(ModelService.ERROR_MESSAGE))) {
result.put(ModelService.ERROR_MESSAGE, errorMessage);
} else {
List<Object> origErrorMessageList = UtilGenerics.checkList(result.get(ModelService.ERROR_MESSAGE_LIST));
if (origErrorMessageList == null) {
origErrorMessageList = new LinkedList<Object>();
result.put(ModelService.ERROR_MESSAGE_LIST, origErrorMessageList);
}
origErrorMessageList.add(0, errorMessage);
}
}
// do something with the errorMessageList
if (UtilValidate.isNotEmpty(errorMessageList)) {
List<Object> origErrorMessageList = UtilGenerics.checkList(result.get(ModelService.ERROR_MESSAGE_LIST));
if (origErrorMessageList == null) {
result.put(ModelService.ERROR_MESSAGE_LIST, errorMessageList);
} else {
origErrorMessageList.addAll(errorMessageList);
}
}
// do something with the errorMessageMap
if (UtilValidate.isNotEmpty(errorMessageMap)) {
Map<String, Object> origErrorMessageMap = UtilGenerics.checkMap(result.get(ModelService.ERROR_MESSAGE_MAP));
if (origErrorMessageMap == null) {
result.put(ModelService.ERROR_MESSAGE_MAP, errorMessageMap);
} else {
origErrorMessageMap.putAll(errorMessageMap);
}
}
// do something with the fail message
if (UtilValidate.isNotEmpty(failMessage)) {
String origFailMessage = (String) result.get("failMessage");
if (UtilValidate.isEmpty(origFailMessage)) {
result.put("failMessage", failMessage);
} else {
result.put("failMessage", origFailMessage + ", " + failMessage);
}
}
}
return success;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ServiceEcaAction) {
ServiceEcaAction other = (ServiceEcaAction) obj;
if (!UtilValidate.areEqual(this.eventName, other.eventName)) return false;
if (!UtilValidate.areEqual(this.serviceName, other.serviceName)) return false;
if (!UtilValidate.areEqual(this.serviceMode, other.serviceMode)) return false;
if (!UtilValidate.areEqual(this.resultMapName, other.resultMapName)) return false;
if (!UtilValidate.areEqual(this.runAsUser, other.runAsUser)) return false;
if (this.newTransaction != other.newTransaction) return false;
if (this.resultToContext != other.resultToContext) return false;
if (this.resultToResult != other.resultToResult) return false;
if (this.ignoreFailure != other.ignoreFailure) return false;
if (this.ignoreError != other.ignoreError) return false;
if (this.persist != other.persist) return false;
return true;
} else {
return false;
}
}
}