/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * Copyright (c) 2014, MPL CodeInside http://codeinside.ru */ package ru.codeinside.gses.activiti.forms; import com.google.common.base.Splitter; import org.activiti.engine.ActivitiException; import org.activiti.engine.delegate.Expression; import org.activiti.engine.delegate.VariableScope; import org.activiti.engine.impl.db.DbSqlSession; import org.activiti.engine.impl.interceptor.Command; import org.activiti.engine.impl.interceptor.CommandContext; import org.activiti.engine.impl.persistence.entity.ExecutionEntity; import ru.codeinside.adm.AdminServiceProvider; import ru.codeinside.adm.database.ClientRequestEntity; import ru.codeinside.gses.activiti.forms.api.definitions.BlockNode; import ru.codeinside.gses.activiti.forms.api.definitions.EnclosureNode; import ru.codeinside.gses.activiti.forms.api.definitions.NullAction; import ru.codeinside.gses.activiti.forms.api.definitions.PropertyNode; import ru.codeinside.gses.activiti.forms.api.definitions.PropertyTree; import ru.codeinside.gses.activiti.forms.api.definitions.PropertyType; import ru.codeinside.gses.activiti.forms.api.definitions.ToggleNode; import ru.codeinside.gses.activiti.forms.types.AttachmentType; import ru.codeinside.gses.activiti.forms.values.VariableTracker; import ru.codeinside.gses.activiti.history.HistoricDbSqlSession; import ru.codeinside.gses.beans.Smev; import ru.codeinside.gses.beans.filevalues.SmevFileValue; import ru.codeinside.gses.service.Fn; import ru.codeinside.gses.service.Some; import ru.codeinside.gses.webui.form.AttachmentConverter; import ru.codeinside.gses.webui.form.DataAccumulator; import ru.codeinside.gses.webui.form.FormOvSignatureSeq; import ru.codeinside.gses.webui.form.ProtocolUtils; import ru.codeinside.gses.webui.form.SignatureType; import ru.codeinside.gses.webui.form.TmpAttachment; import ru.codeinside.gws.api.ClientRequest; import ru.codeinside.gws.api.Packet; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import java.util.regex.Pattern; public class SubmitFormDataCmd implements Command<Void> { final PropertyTree propertyTree; final VariableScope variableScope; final DataAccumulator accumulator; final AttachmentConverter attachmentConverter; final Map<String, Object> properties; final Map<SignatureType, Signatures> signatures; final Map<String, Boolean> requiredMap = new HashMap<String, Boolean>(); final Logger logger = Logger.getLogger(getClass().getName()); final String tmpAttachmentIdPattern = "^(?i)[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}" + AttachmentType.SUFFIX + "$"; public SubmitFormDataCmd(PropertyTree propertyTree, VariableScope variableScope, Map<String, Object> properties, Map<SignatureType, Signatures> signatures, AttachmentConverter attachmentConverter, DataAccumulator accumulator) { this.propertyTree = propertyTree; this.variableScope = variableScope; this.properties = new HashMap<String, Object>(properties); this.signatures = signatures; this.attachmentConverter = attachmentConverter; this.accumulator = accumulator; } @Override public Void execute(final CommandContext commandContext) { // TODO: нужно ли для СМЭВ переключатели видимости обрабатывать? // засейвить ServerResponse и ClientRequest saveServerResponse(); saveClientRequest(); restoreOriginalTmpAttachments(); // Замена требований. for (final PropertyNode node : propertyTree.getNodes()) { if (node.getPropertyType() == PropertyType.TOGGLE) { ToggleNode toggle = (ToggleNode) node; boolean required = !toggle.getToggleTo(); Object valueObject = properties.get(toggle.getToggler().getId()); String value = valueObject == null ? null : valueObject.toString(); if (toggle.getToggleValue().equals(value)) { required = !required; } for (PropertyNode target : toggle.getToggleNodes()) { if (required != target.isFieldRequired()) { requiredMap.put(target.getId(), required); } } } } for (PropertyNode node : propertyTree.getNodes()) { submit(node, "", commandContext); } for (final String propertyId : properties.keySet()) { PropertyContext.withWritePath(propertyId, new PropertyContext.Action() { @Override public void inContext() { Object originalValue = properties.get(propertyId); Object modelValue = attachmentConverter.convertAttachment(commandContext, originalValue); variableScope.setVariable(propertyId, modelValue); addSmevSignature(commandContext, originalValue, propertyId); } }); } if (signatures != null) { HistoricDbSqlSession session = (HistoricDbSqlSession) commandContext.getSession(DbSqlSession.class); session.addSignatures(signatures); session.linkPropertyValuesWithSignatures(); } return null; } /** * Заменить айдишники временных вложений на сами вложения */ private void restoreOriginalTmpAttachments() { for (Map.Entry<String, Object> entry : properties.entrySet()) { String value = String.valueOf(entry.getValue()); if (Pattern.matches(tmpAttachmentIdPattern, value)) { TmpAttachment attachment = accumulator.getAttachment(value.substring(0, value.length() - AttachmentType.SUFFIX.length())); if (attachment != null) { entry.setValue(attachment); } } } } private void saveClientRequest() { if (accumulator == null || accumulator.getClientRequest() == null) { return; } ClientRequestEntity clientRequestEntity = createClientRequestEntity( accumulator.getServiceName(), accumulator.getClientRequest() ); long requestId = AdminServiceProvider.get().saveClientRequestEntity(clientRequestEntity); String key = accumulator.getServiceName() + FormOvSignatureSeq.REQUEST_ID; properties.put(key, requestId); } private void saveServerResponse() { if (accumulator == null || accumulator.getServerResponse() == null) { return; } long responseId = Fn.withEngine( new ProtocolUtils.CreateAndSaveServiceResponseEntity(), accumulator.getServerResponse(), accumulator.getTaskId(), accumulator.getUsedEnclosures() ); properties.put(Smev.SERVER_RESPONSE_ID, responseId); } private ClientRequestEntity createClientRequestEntity(String serviceName, ClientRequest request) { final ClientRequestEntity entity = new ClientRequestEntity(); entity.name = serviceName; if (request.action != null) { entity.action = request.action.getLocalPart(); entity.actionNs = request.action.getNamespaceURI(); } if (request.port != null) { entity.port = request.port.getLocalPart(); entity.portNs = request.port.getNamespaceURI(); } if (request.service != null) { entity.service = request.service.getLocalPart(); entity.serviceNs = request.service.getNamespaceURI(); } if (request.appData != null) { entity.appData = request.appData; } entity.portAddress = request.portAddress; entity.requestMessage = request.requestMessage; final Packet packet = request.packet; entity.gservice = packet.typeCode.name(); entity.status = packet.status.name(); entity.date = new Date(); entity.exchangeType = packet.exchangeType; entity.requestIdRef = packet.requestIdRef; entity.originRequestIdRef = packet.originRequestIdRef; entity.serviceCode = packet.serviceCode; entity.caseNumber = packet.caseNumber; entity.testMsg = packet.testMsg; entity.signRequired = request.signRequired; entity.enclosureDescriptor = request.enclosureDescriptor; return entity; } void submit(final PropertyNode node, final String suffix, final CommandContext commandContext) { final PropertyType type = node.getPropertyType(); if (type == PropertyType.TOGGLE || type == PropertyType.VISIBILITY_TOGGLE) { return; } final String id = node.getId() + suffix; Object blockValue = null; if (type == PropertyType.BLOCK) { // упрощение идентификации блоков, когда есть заначние без префикса '+' if (!properties.containsKey(id) && properties.containsKey(id.substring(1))) { properties.put(id, properties.remove(id.substring(1))); } if (properties.containsKey(id)) { blockValue = properties.get(id); } else { Expression expression = node.getDefaultExpression(); if (expression != null) { blockValue = expression.getExpressionText(); } } } PropertyContext.withWritePath(id, new PropertyContext.Action() { @Override public void inContext() { submitFormNode(node, id, commandContext, suffix); } }); if (type == PropertyType.BLOCK) { int size = 0; if (blockValue != null) { try { size = Integer.parseInt(blockValue.toString()); } catch (NumberFormatException e) { throw new ActivitiException("Size = '" + blockValue + "' for " + id + " is not integer!"); } } BlockNode block = (BlockNode) node; if (size < block.getMinimum()) { throw new ActivitiException("Size = " + size + " for " + id + " is less then minimum " + block.getMinimum()); } if (size > block.getMaximum()) { throw new ActivitiException("Size = " + size + " for " + id + " is greater then minimum " + block.getMaximum()); } for (int i = 1; i <= size; i++) { for (PropertyNode child : block.getNodes()) { submit(child, suffix + "_" + i, commandContext); } } } if (node instanceof EnclosureNode) { String attachments = (String) variableScope.getVariable(id); if (attachments != null) { EnclosureNode enclosureNode = (EnclosureNode) node; Iterable<String> varNamesForRefToAttachment = Splitter.on(';').omitEmptyStrings().trimResults().split(attachments); for (String varName : varNamesForRefToAttachment) { PropertyNode child = enclosureNode.createEnclosure(varName); submit(child, suffix, commandContext); } } } } public void submitFormNode(PropertyNode node, String id, CommandContext commandContext, String suffix) { if (!node.isFieldWritable()) { if (properties.containsKey(id)) { throw new ActivitiException("form property '" + id + "' is not writable"); } } boolean required; if (requiredMap.containsKey(id)) { required = requiredMap.get(id); } else { required = node.isFieldRequired() && node.isVisible(); } if (required && !properties.containsKey(id) && node.getDefaultExpression() == null) { throw new ActivitiException("form property '" + id + "' is required"); } if (!node.isVarWritable()) { logger.info("skip " + id + " by #write=false"); return; } Object modelValue = null; if (properties.containsKey(id)) { Object propertyValue = properties.remove(id); modelValue = node.getVariableType().convertFormValueToModelValue(propertyValue, node.getPattern(), node.getParams()); } else if (node.getDefaultExpression() != null) { Object expressionValue = node.getDefaultExpression().getValue(variableScope); if (expressionValue != null) { modelValue = node.getVariableType().convertFormValueToModelValue(expressionValue, node.getPattern(), node.getParams()); } else if (required) { throw new ActivitiException("form property '" + id + "' is required"); } } if (modelValue != null) { Object originalValue = modelValue; modelValue = attachmentConverter.convertAttachment(commandContext, modelValue); // TODO: разделить на трекер чтения и трекер записи! VariableTracker tracker = new VariableTracker(variableScope); if (node.getVariableName() != null) { tracker.setVariable(node.getVariableName() + suffix, modelValue); } else if (node.getVariableExpression() != null) { node.getVariableExpression().setValue(modelValue, tracker); } else { tracker.setVariable(id, modelValue); } Some<String> usedVariable = tracker.getUsedVariable(); if (usedVariable.isPresent() && usedVariable.get() != null) { String varName = usedVariable.get(); addSmevSignature(commandContext, originalValue, varName); } } else { applyNullValue(node, id, required); } } private void addSmevSignature(CommandContext commandContext, Object originalValue, String varName) { if (originalValue instanceof SmevFileValue && variableScope instanceof ExecutionEntity) { HistoricDbSqlSession session = (HistoricDbSqlSession) commandContext.getSession(DbSqlSession.class); session.addSignaturesBySmevFileValue(((ExecutionEntity)variableScope).getProcessDefinitionId(), varName, (SmevFileValue) originalValue); } } //TODO: varTracker! private void applyNullValue(PropertyNode node, String id, boolean required) { if (!node.isFieldWritable() || NullAction.skip == node.getNullAction()) { return; } if (required) { throw new ActivitiException("Значение для свойства '" + id + "' обязательно!"); } if (NullAction.set == node.getNullAction()) { if (node.getVariableName() != null) { variableScope.setVariable(node.getVariableName(), null); } else if (node.getVariableExpression() != null) { node.getVariableExpression().setValue(null, variableScope); } else { variableScope.setVariable(id, null); } } else if (NullAction.remove == node.getNullAction()) { if (node.getVariableName() != null) { variableScope.removeVariable(node.getVariableName()); } else if (node.getVariableExpression() != null) { // в выражении не можем удалить, ставим NULL node.getVariableExpression().setValue(null, variableScope); } else { variableScope.removeVariable(id); } } else { throw new IllegalStateException("Не известное поведение для null"); } } }