| /******************************************************************************* |
| * 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.ofbiz.service.eca; |
| |
| import java.util.HashMap; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.ofbiz.base.util.Debug; |
| import org.ofbiz.base.util.UtilGenerics; |
| import org.ofbiz.base.util.UtilValidate; |
| import org.ofbiz.service.DispatchContext; |
| import org.ofbiz.service.GenericServiceException; |
| import org.ofbiz.service.LocalDispatcher; |
| import org.ofbiz.service.ModelService; |
| import org.ofbiz.service.ServiceSynchronization; |
| import org.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; |
| } |
| } |
| } |