From 7d9d5ed35d530d514bceba6fe0213cb6b1428438 Mon Sep 17 00:00:00 2001 From: "446052889@qq.com" <446052889@qq.com> Date: Sat, 2 Jul 2022 03:02:07 +0800 Subject: [PATCH] =?UTF-8?q?Aris=E6=B5=81=E7=A8=8B=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E8=BF=81=E7=A7=BB=E6=97=A5=E5=BF=97=E8=AE=B0=E5=BD=95=E5=A4=84?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ....actionsoft.apps.coe.pal.datamigration.jar | Bin 139332 -> 147075 bytes .../aris/constant/ArisConstant.java | 16 + .../pal/datamigration/aris/util/XMLUtil.java | 14 +- .../aris/web/ArisXmlHandleWeb.java | 33 +- .../aris/web/ArisXmlImportRun.java | 1330 ++++++++++++++ .../aris/web/ArisXmlImportWeb.java | 1554 +++-------------- .../cache/DataMigrationCache.java | 26 + .../pal/datamigration/constant/Constant.java | 28 +- .../coe/pal/datamigration/plugin/Plugins.java | 5 + 9 files changed, 1680 insertions(+), 1326 deletions(-) create mode 100644 com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/constant/ArisConstant.java create mode 100644 com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlImportRun.java create mode 100644 com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/cache/DataMigrationCache.java diff --git a/com.actionsoft.apps.coe.pal.datamigration/lib/com.actionsoft.apps.coe.pal.datamigration.jar b/com.actionsoft.apps.coe.pal.datamigration/lib/com.actionsoft.apps.coe.pal.datamigration.jar index 4f4ed4651a06e8a0b7f0c7c6d57e61b3faaa0249..53d4d2e7ae1f8c2b54b6b9e5e9f703993efb2426 100644 GIT binary patch delta 56106 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 S3bJr?NuZz>VIb=W>i+>{8$-+h diff --git a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/constant/ArisConstant.java b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/constant/ArisConstant.java new file mode 100644 index 00000000..7fee0f76 --- /dev/null +++ b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/constant/ArisConstant.java @@ -0,0 +1,16 @@ +package com.actionsoft.apps.coe.pal.datamigration.aris.constant; + +public class ArisConstant { + + public final static String REPOSITORY_NAME = "arisXML";// aris xml文件导入dc根目录 + + public final static String UPFILE = "upfile";// aris xml文件上传根目录,在REPOSITORY_NAME之下 + + public final static String LOG_GROUP_VALUE = "log";// aris xml文件导入日志根目录,在REPOSITORY_NAME之下 + + public final static String IMPORT_LOG_FILE_SIMPLE = "simpleImport.log";// 简要日志,展示给前端,体现大致的导入内容和进度 + public final static String IMPORT_LOG_FILE_FULL = "fullImport.log";// 详细日志,包括全量信息内容 + public final static String IMPORT_LOG_FILE_WARN = "warnErrImport.log";// 错误&警告日志,单独记录错误&警告日志,同时详细日志中也有记录 + + +} diff --git a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/util/XMLUtil.java b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/util/XMLUtil.java index e7173514..1edf383a 100755 --- a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/util/XMLUtil.java +++ b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/util/XMLUtil.java @@ -24,12 +24,12 @@ public class XMLUtil { * @param fromFilePath * @param toFilePath */ - public static void unicode2String(String fromFilePath, String toFilePath) { + public static void unicode2String(String fromFilePath, String toFilePath) throws DocumentException, FileNotFoundException{ Document d = XMLUtil.readXML(fromFilePath, true); XMLUtil.writeXml(d, toFilePath); } - public static Document readXML(String filePath, boolean ignoreDtd) { + public static Document readXML(String filePath, boolean ignoreDtd) throws DocumentException, FileNotFoundException { if (filePath == null) { return null; } @@ -60,16 +60,12 @@ public class XMLUtil { return document; } catch (DocumentException e) { - File fil = new File(filePath); - try { - document = reader.read(fil); - } catch (Exception e1) { - - } + e.printStackTrace(); + throw e; } catch (Exception e) { e.printStackTrace(); + throw e; } - return null; } public static Document readXMLFromInputStream(InputStream in) { diff --git a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlHandleWeb.java b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlHandleWeb.java index 5e302355..bc3735e1 100644 --- a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlHandleWeb.java +++ b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlHandleWeb.java @@ -2,12 +2,15 @@ package com.actionsoft.apps.coe.pal.datamigration.aris.web; import com.actionsoft.apps.coe.pal.datamigration.aris.mapping.ModelMappingAPIManager; import com.actionsoft.apps.coe.pal.datamigration.aris.model.*; +import com.actionsoft.apps.coe.pal.datamigration.constant.Constant; +import com.actionsoft.apps.coe.pal.datamigration.util.LogUtil; import com.actionsoft.bpms.util.UtilString; import com.alibaba.fastjson.JSONObject; import org.apache.commons.lang.StringUtils; import org.dom4j.Document; import org.dom4j.Element; +import java.io.File; import java.util.*; /** @@ -29,22 +32,22 @@ public class ArisXmlHandleWeb { public Map> objDefLinkerMap = new HashMap<>();// 记录所有定义形状的连线map记录 - - // 连线 todo - - // 属性 todo - // 处理文档 - public void handleXmlDoc(Document doc) { - // 获取根元素节点 - Element root = doc.getRootElement(); - String groupPath = "/"; - getNodes(root, groupPath); - // 整合Model路径 - calculateModelPath(); - // 计算定义形状之间的连线 - calculateObjDefLinker(); - test(); + public void handleXmlDoc(Document doc) throws Exception{ + try { + // 获取根元素节点 + Element root = doc.getRootElement(); + String groupPath = "/"; + getNodes(root, groupPath); + // 整合Model路径 + calculateModelPath(); + // 计算定义形状之间的连线 + calculateObjDefLinker(); + // test(); + } catch (Exception e) { + e.printStackTrace(); + } + } /** diff --git a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlImportRun.java b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlImportRun.java new file mode 100644 index 00000000..06d45f34 --- /dev/null +++ b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlImportRun.java @@ -0,0 +1,1330 @@ +package com.actionsoft.apps.coe.pal.datamigration.aris.web; + +import com.actionsoft.apps.coe.pal.datamigration.aris.mapping.ModelMappingAPIManager; +import com.actionsoft.apps.coe.pal.datamigration.aris.model.*; +import com.actionsoft.apps.coe.pal.datamigration.cache.DataMigrationCache; +import com.actionsoft.apps.coe.pal.datamigration.constant.Constant; +import com.actionsoft.apps.coe.pal.datamigration.util.ShapeUtil; +import com.actionsoft.apps.coe.pal.pal.method.model.PALMethodAttributeModel; +import com.actionsoft.apps.coe.pal.pal.repository.PALRepositoryAPIManager; +import com.actionsoft.apps.coe.pal.pal.repository.PALRepositoryQueryAPIManager; +import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache; +import com.actionsoft.apps.coe.pal.pal.repository.dao.CoeProcessLevelDaoFacotory; +import com.actionsoft.apps.coe.pal.pal.repository.dao.PALRepository; +import com.actionsoft.apps.coe.pal.pal.repository.dao.PALRepositoryPropertyDao; +import com.actionsoft.apps.coe.pal.pal.repository.designer.CoeDesignerShapeAPIManager; +import com.actionsoft.apps.coe.pal.pal.repository.designer.constant.CoeDesignerConstant; +import com.actionsoft.apps.coe.pal.pal.repository.designer.manage.CoeDesignerAPIManager; +import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel; +import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.dao.DesignerShapeRelationDao; +import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel; +import com.actionsoft.apps.coe.pal.pal.repository.designer.util.CoeDesignerUtil; +import com.actionsoft.apps.coe.pal.pal.repository.model.PALRepositoryModel; +import com.actionsoft.apps.coe.pal.pal.repository.model.PALRepositoryPropertyModel; +import com.actionsoft.apps.coe.pal.pal.repository.model.impl.PALRepositoryModelImpl; +import com.actionsoft.apps.coe.pal.pal.repository.util.CoeProcessLevelUtil; +import com.actionsoft.bpms.server.UserContext; +import com.actionsoft.bpms.util.UUIDGener; +import com.actionsoft.bpms.util.UtilString; +import com.actionsoft.exception.AWSException; +import com.actionsoft.sdk.local.SDK; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.lang.StringUtils; + +import java.io.File; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +public class ArisXmlImportRun { + + private UserContext uc; + private String wsId; + private String logId; + private String logPath; + private File simpleLogFile; + private File fullLogFile; + private File warnLogFile; + private String filePath; + private String fileName; + + public ArisXmlImportRun(UserContext uc, String wsId, String logId, String logPath, File simpleLogFile, File fullLogFile, File warnLogFile, String filePath, String fileName) { + this.uc = uc; + this.wsId = wsId; + this.logId = logId; + this.logPath = logPath; + this.simpleLogFile = simpleLogFile; + this.fullLogFile = fullLogFile; + this.warnLogFile = warnLogFile; + this.filePath = filePath; + this.fileName = fileName; + } + + public void execute(ArisXmlHandleWeb handleWeb) { + Map groupMap = handleWeb.groupMap;// 文件夹/组基本信息map记录 + + Map modelMap = handleWeb.modelMap;// 模型基本信息map记录 + + Map objDefMap = handleWeb.objDefMap;// 形状定义map记录 + + Map> modelObjOccMap = handleWeb.modelObjOccMap;// 模型内形状map记录 + + Map objOccMap = handleWeb.objOccMap;// 所有形状 + + Map> cxnOccMap = handleWeb.cxnOccMap;// 形状连线记录 + + Map> objDefLinkerMap = handleWeb.objDefLinkerMap;// 记录所有定义形状的连线map记录 + + Map> methodAttrsMap = new HashMap<>();// 属性存储 + + + // 获取所有IT系统图,并查询所有IT系统形状 + Map itShapeMap = new HashMap<>(); + Set ids = new HashSet<>(); + List itModels = new ArrayList<>(); + PALRepositoryCache.getAllChildrenModelsByPid(wsId, "itsystem", itModels, ids); + for (PALRepositoryModel itModel : itModels) { + String definition = PALRepositoryQueryAPIManager.getInstance().getProcessDefinition(null, itModel.getId()); + List list = com.actionsoft.apps.coe.pal.pal.repository.designer.util.ShapeUtil.getShapeJsonToJsonObject(definition); + for (JSONObject shape: list) { + JSONObject obj = new JSONObject(); + obj.put("shapeId", shape.getString("id")); + obj.put("plId", itModel.getId()); + obj.put("shapeName", shape.getString("text")); + itShapeMap.put(shape.getString("text"), obj); + } + } + + PALRepository coeProcessLevel = CoeProcessLevelDaoFacotory.createCoeProcessLevel(); + + // 存储匹配到与未匹配到的模型信息 + List matchModels = new ArrayList<>(); + List unMatchModels = new ArrayList<>(); + // 存储已经匹配上但是文件里已经有内容【可能导入重复】的模型信息 + List repeatModels = new ArrayList<>(); + // 存储不包含图形的流程,无任何形状的流程不进行导入 + List currentModelNoShape = new ArrayList<>(); + for (Map.Entry entry : modelMap.entrySet()) { + ModelModel arisModel = entry.getValue(); + // 创建角色模型 + List objOccModels = modelObjOccMap.get(arisModel.getId()); + if (objOccModels == null || objOccModels.size() == 0) { + currentModelNoShape.add(arisModel); + printMsg("流程" + arisModel.getName() + arisModel.getId() + "无任何模型,导入忽略"); + continue; + } + // 匹配模型 + PALRepositoryModel palModel = matchPalModel(arisModel, wsId); + if (palModel != null) { + matchModels.add(arisModel); + String plId = palModel.getId(); + // 模型是否可导入 + BaseModel defineModel = CoeDesignerAPIManager.getInstance().getDefinition(plId, 0); + if (defineModel == null) { + defineModel = CoeDesignerUtil.createModel(plId, 0); + defineModel.setCreateHistory(false); + } + String timestamp = new SimpleDateFormat(CoeDesignerConstant.DATE_TIME_STYLE_YYYY_MM_DD_HH_MM_SS).format(new Date()); + defineModel.setUpdateTime(timestamp); + String define = defineModel.getDefinition(); + JSONObject definition = JSONObject.parseObject(define); + JSONObject elements = definition.getJSONObject("elements"); + if (elements != null && !elements.isEmpty()) { + // 导入模型已存在数据,不允许导入 todo + repeatModels.add(arisModel); + printMsg("[" + arisModel.getName() + "] 导入流程模型已存在数据,不允许导入,对同名角色模型进行忽略处理"); + continue; + } + + String rolefolderId = checkAndCreatePalRoleFolderModel(coeProcessLevel, wsId);// 创建/获取角色文件夹ID,作为角色的顶级文件夹 + Map arisFunIdRelationPalRoleMap = new HashMap<>();// aris功能模型与aris角色模型的id映射,key:aris fun shape id,value:pal role id + Map palRoleIdRelationNameMap = new HashMap<>();// key pal role shape id ,value:pal role shape text + // 创建角色模型和角色元素,并且获取aris角色与pal角色映射关系 + String roleMdoelId = createRoleModelAndElements(coeProcessLevel, rolefolderId, wsId, currentModelNoShape, palModel, arisModel, modelObjOccMap, objDefMap, objOccMap, cxnOccMap, objDefLinkerMap, arisFunIdRelationPalRoleMap, methodAttrsMap, palRoleIdRelationNameMap); + + // 存储当前模型下ARIS图形ID与PAL图形ID映射关系 + Map idRelationMap = new HashMap<>(); + + Map palShapeIdRelationArisOccIdMap = new HashMap<>(); + // 创建形状和连线 + JSONObject newElements = createShapeElement(wsId, idRelationMap, palModel, arisModel, modelObjOccMap, objDefMap, objOccMap, cxnOccMap, palShapeIdRelationArisOccIdMap); + + // 处理输入输出活动属性 + this.handleShapeInputOutAttr(palModel, newElements); + + // 处理角色属性与流程相应的活动节点关联 + this.handleProcessAttrRoleRelation(wsId, palModel.getId(), arisFunIdRelationPalRoleMap, palShapeIdRelationArisOccIdMap, newElements, arisModel, modelObjOccMap, objDefMap, roleMdoelId, palRoleIdRelationNameMap); + + // 处理流程关联属性IT系统 + this.handleProcessAttrItSystemRelation(wsId, idRelationMap, palModel.getId(), newElements, arisModel, modelObjOccMap, objDefMap, objDefLinkerMap, itShapeMap); + + this.handleProcessAttrLeadOrRearProcess(wsId, currentModelNoShape, idRelationMap, palModel.getId(), newElements, arisModel, modelObjOccMap, objDefMap); + + // 增加其他默认的属性,值默认为空 by孙连辉 20220626 + this.handleShapeDefaultAttr(wsId, palModel, newElements, methodAttrsMap); + + definition.put("elements", newElements); + // 设置画布大小 + setDiagramHeightWidth(definition, newElements); + defineModel.setDefinition(definition.toString()); + // 保存文件 + CoeDesignerAPIManager.getInstance().storeDefinition(defineModel);// dao操作 + + } else { + unMatchModels.add(arisModel); + } + } + + } + + + /** + * 校验和创建角色模型文件夹 + * @param coeProcessLevel + * @param wsId + * @return 已经存在的或新创建的角色模型ID + */ + private String checkAndCreatePalRoleFolderModel(PALRepository coeProcessLevel, String wsId) { + // 组织下创建【角色模型】文件夹 + List defaultModels = PALRepositoryQueryAPIManager.getInstance().getPalRepositoryModelsByWsIdAndMethodId(wsId, "org"); + defaultModels = defaultModels.stream() + .filter(model -> "default".equals(model.getMethodId())) + .filter(model -> Constant.DEFAULT_FOLDER_NAME.equals(model.getName())).collect(Collectors.toList()); + if (defaultModels.size() == 0) { + String id = UUIDGener.getUUID(); + + int orderIndex = coeProcessLevel.getChildrenMaxOrderIndexByPidAndWsId("org", wsId) + 1; + Timestamp nowTime = new Timestamp(System.currentTimeMillis()); + PALRepositoryModelImpl defaultModel = CoeProcessLevelUtil.createPALRepositoryModel(id, UUIDGener.getUUID(), wsId, Constant.DEFAULT_FOLDER_NAME, "", orderIndex, "org", "org", true, 1, + id, false, "default", "0", 1, null, null, uc.getUID(), uc.getUID(), nowTime, null, null, null, null, + null, null, null, null, null, -1); + coeProcessLevel.insert(defaultModel); + defaultModels.add(defaultModel); + printMsg("角色模型文件夹创建成功 " + defaultModel.getId()); + return defaultModel.getId(); + } else { + printMsg("角色模型文件夹已存在,不再重复创建"); + return defaultModels.get(0).getId(); + } + } + + /** + * 自定义属性 + * @param wsId + * @param palModel + * @param elements + * @param methodAttrsMap + */ + private void handleShapeDefaultAttr(String wsId, PALRepositoryModel palModel, JSONObject elements, Map> methodAttrsMap) { + for (String key : elements.keySet()) { + JSONObject shape = elements.getJSONObject(key); + if ("linker".equals(shape.getString("name"))) { + continue; + } + String shapeMehtodId = shape.getString("category").replace("_", "."); + String shapeName = shape.getString("name"); + + if (methodAttrsMap.containsKey(palModel.getMethodId()) && methodAttrsMap.containsKey(shapeName)) { + } else { + if (!methodAttrsMap.containsKey(palModel.getMethodId())) { + methodAttrsMap.put(palModel.getMethodId(), new HashMap<>()); + } + JSONObject attrs = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), shapeMehtodId, palModel.getMethodId(), shapeName); + if (attrs != null) { + methodAttrsMap.get(palModel.getMethodId()).put(shapeName, attrs); + } + } + JSONObject attrs = methodAttrsMap.get(palModel.getMethodId()).get(shapeName);// 最终属性内容 + attrs = JSONObject.parseObject(attrs.toString());// 复制 + JSONArray dataAttributes = shape.getJSONArray("dataAttributes"); + if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { + for (Object attribute : dataAttributes) { + JSONObject obj = (JSONObject) attribute; + if (obj.containsKey("attributesJsonArray")) { + JSONArray attributesJsonArray = obj.getJSONArray("attributesJsonArray"); + Set attrIds = new HashSet<>(); + for (int i = 0; i < attributesJsonArray.size(); i++) { + if (attributesJsonArray.getJSONObject(i).containsKey("id")) { + attrIds.add(attributesJsonArray.getJSONObject(i).getString("id")); + } + } + for (String attrId : attrs.keySet()) { + if (!attrIds.contains(attrId)) { + JSONObject eleAttrObj = getDefaultAttrObj(attrs.getJSONObject(attrId)); + attributesJsonArray.add(eleAttrObj); + } + } + } + } + } + } + } + + /** + * 创建PAL形状 + * + * @param palModel + * @param arisModel + * @param modelObjOccMap + * @param objDefMap + * @return + */ + private JSONObject createShapeElement(String wsId, Map idRelationMap, PALRepositoryModel palModel, ModelModel arisModel, Map> modelObjOccMap, Map objDefMap, Map objOccMap, Map> cxnOccMap, Map palShapeIdRelationArisOccIdMap) { + // aris中该模型所有形状 + List objOccModels = modelObjOccMap.get(arisModel.getId()); + int zindex = 1; + JSONObject elements = new JSONObject(); + Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); + for (ObjOccModel objOccModel : objOccModels) { + ObjDefModel objDefModel = objDefMap.get(objOccModel.getDefId());// 形状定义 + if (objDefMappingMap.containsKey(objDefModel.getTypeNum() + "-" + objOccModel.getSymbolNum())) { + ObjDefMappingModel objDefMappingModel = objDefMappingMap.get(objDefModel.getTypeNum() + "-" + objOccModel.getSymbolNum());// Aris与PAL形状映射关系 + String shapeMethodId = objDefMappingModel.getShapeMethod(); + String shapeType = objDefMappingModel.getShapeType(); + // 伊利导入形状定制 + String symbolNum = objDefMappingModel.getSymbolNum(); + String typeNum = objDefMappingModel.getTypeNum(); + String arisShapeName = objDefMap.get(objOccModel.getDefId()).getName(); + String method = shapeMethodId; + String shapeName = shapeType; + // fun +// if ("OT_FUNC".equals(symbolNum) && "ST_FUNC".equals(typeNum)) { + if ("ST_FUNC".equals(symbolNum) && "OT_FUNC".equals(typeNum)) { + if (arisShapeName.contains("审批") || arisShapeName.contains("审核")) { + shapeName = "method_service_node"; + } else { + shapeName = "method_service_node4"; + } +// } else if ("OT_FUNC".equals(symbolNum) && "ST_SYS_FUNC_ACT".equals(typeNum)) {// sys_fun + } else if ("ST_SYS_FUNC_ACT".equals(symbolNum) && "OT_FUNC".equals(typeNum)) {// sys_fun + if (arisShapeName.contains("审批") || arisShapeName.contains("审核")) { + shapeName = "method_approval_node"; + } else { + shapeName = "method_approval_node3"; + } + } + + JSONObject shape = ShapeUtil.getProcessShapeDefinitionByName(shapeMethodId, shapeName); + String shapeId = UUIDGener.getObjectId(); + palShapeIdRelationArisOccIdMap.put(shapeId, objOccModel.getId()); + idRelationMap.put(objOccModel.getId(), shapeId);// 记录形状aris形状id与pal形状id + shape.put("id", shapeId); + // 处理当前图形节点的关联属性【编号】问题 + if (objDefModel.getAttrData().containsKey("AT_PROC_CODE")) { + List attributeModels = CoeDesignerShapeAPIManager.getInstance().getValidAttributeModels(wsId, objDefMappingModel.getShapeMethod(), shapeName, objDefMappingModel.getShapeMethod()); + attributeModels = attributeModels.stream().filter(item -> Constant.METHOD_NUMBER.equals(item.getKey())).collect(Collectors.toList()); + if (attributeModels.size() == 0) { + throw new AWSException("请打开建模管理应用,查看当前【过程链】建模分类下是否存在【编号/" + Constant.METHOD_NUMBER + "】建模属性"); + } + PALMethodAttributeModel attributeModel = attributeModels.get(0); + JSONObject attrNumberObj = new JSONObject(); + attrNumberObj.put("value", objDefModel.getAttrData().getString("AT_PROC_CODE")); + attrNumberObj.put("key", attributeModel.getKey()); + attrNumberObj.put("isRequired", attributeModel.getIsRequired()); + attrNumberObj.put("ref", attributeModel.getRef()); + attrNumberObj.put("readonly", attributeModel.getReadonly()); + attrNumberObj.put("scope", attributeModel.getScope()); + attrNumberObj.put("name", attributeModel.getTitle()); + attrNumberObj.put("id", attributeModel.getKey()); + attrNumberObj.put("textarea", attributeModel.getType()); + attrNumberObj.put("groupPath", attributeModel.getGroupPath()); + attrNumberObj.put("desc", attributeModel.getDesc()); + + JSONArray dataAttributes = shape.getJSONArray("dataAttributes"); + if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { + for (Object attribute : dataAttributes) { + JSONObject obj = (JSONObject) attribute; + if (obj.containsKey("attributesJsonArray")) { + obj.getJSONArray("attributesJsonArray").add(attrNumberObj); + break; + } + } + } + } + + +// 处理活动节点描述 --by shang + if (objDefModel.getAttrData().containsKey("AT_DESC")) { + List attributeModels = CoeDesignerShapeAPIManager.getInstance().getValidAttributeModels(wsId, objDefMappingModel.getShapeMethod(), "process", objDefMappingModel.getShapeMethod()); + attributeModels = attributeModels.stream().filter(item -> Constant.METHOD_DESC.equals(item.getKey())).collect(Collectors.toList()); + if (attributeModels.size() == 0) { + throw new AWSException("请打开建模管理应用,查看当前【过程链】建模分类下是否存在【活动描述/" + Constant.METHOD_DESC + "】建模属性"); + } + PALMethodAttributeModel attributeModel = attributeModels.get(0); + JSONObject attrDescObj = new JSONObject(); + attrDescObj.put("value", objDefModel.getAttrData().getString("AT_DESC")); + attrDescObj.put("key", attributeModel.getKey()); + attrDescObj.put("isRequired", attributeModel.getIsRequired()); + attrDescObj.put("ref", attributeModel.getRef()); + attrDescObj.put("readonly", attributeModel.getReadonly()); + attrDescObj.put("scope", attributeModel.getScope()); + attrDescObj.put("name", attributeModel.getTitle()); + attrDescObj.put("id", attributeModel.getKey()); + attrDescObj.put("textarea", attributeModel.getType()); + attrDescObj.put("groupPath", attributeModel.getGroupPath()); + attrDescObj.put("desc", attributeModel.getDesc()); + + JSONArray dataAttributes = shape.getJSONArray("dataAttributes"); + if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { + for (Object attribute : dataAttributes) { + JSONObject obj = (JSONObject) attribute; + if (obj.containsKey("attributesJsonArray")) { + + // 处理图形上默认勾选的属性,没有值的属性置空 --by shang +// List allValidAndUseShapeAttributeModels = CoeDesignerShapeAPIManager.getInstance().getAllValidAndUseShapeAttributeModels(wsId, objDefMappingModel.getShapeMethod()); + List usedAttributeModels = CoeDesignerShapeAPIManager.getInstance().getValidAndUseAttributeModels(wsId, objDefMappingModel.getShapeMethod(), shapeName, objDefMappingModel.getShapeMethod()); + usedAttributeModels.forEach(item -> { + attrDescObj.put("id", item.getKey()); + attrDescObj.put("value",""); + }); + obj.getJSONArray("attributesJsonArray").add(attrDescObj); + + break; + } + } + } + } + + + // 定义位置、大小 + if (shape == null) { + // pal形状不存在,记录日志 todo + printMsg("pal没有对应形状定义"); + continue; + } + if (shape.containsKey("attribute") && shape.getJSONObject("attribute").containsKey("editable") && !shape.getJSONObject("attribute").getBooleanValue("editable")) {// 不可编辑名称 + + } else {// 重命名名称 + String name = objDefMap.get(objOccModel.getDefId()).getName();// 形状名称 + shape.put("text", name); + } + + JSONObject props = shape.getJSONObject("props");// 位置大小 + props.put("zindex", zindex++); + props.put("x", objOccModel.getX()); + props.put("y", objOccModel.getY()); + props.put("w", objOccModel.getW()); + props.put("h", objOccModel.getH()); + elements.put(shapeId, shape); + } else { + // pal缺少对应的形状 + printMsg("pal缺少对应的形状:" + objDefModel.getName()); + System.out.println(objDefModel.getTypeNum() + "-" + objDefModel.getSymbolNum()); + System.out.println(objDefMappingMap.containsKey(objDefModel.getTypeNum() + "-" + objDefModel.getSymbolNum())); + } + } + // 形状连线处理 + for (ObjOccModel occ : objOccModels) { + if (cxnOccMap.containsKey(occ.getId())) { + List cxnOccModels = cxnOccMap.get(occ.getId()); + for (CxnOccModel cxn : cxnOccModels) { + if (idRelationMap.containsKey(cxn.getId()) && idRelationMap.containsKey(cxn.getToId())) { + List positionModels = cxn.getPositionList(); + JSONObject linkerObj = ModelMappingAPIManager.getInstance().getLinkerDef(); + String linkerId = UUIDGener.getObjectId(); + linkerObj.put("id", linkerId); + JSONObject props = linkerObj.getJSONObject("props"); + props.put("zindex", zindex++);// 层次 + linkerObj.put("props", props); + linkerObj.put("points", getLinkerPoints(positionModels)); + JSONObject from = linkerObj.getJSONObject("from"); + from.put("id", idRelationMap.get(cxn.getId())); + from.put("angle", getLinkerAngle(positionModels, "from")); + from.put("x", positionModels.get(0).getX()); + from.put("y", positionModels.get(0).getY()); + linkerObj.put("from", from); + JSONObject to = linkerObj.getJSONObject("to"); + to.put("id", idRelationMap.get(cxn.getToId())); + to.put("angle", getLinkerAngle(positionModels, "to")); + to.put("x", positionModels.get(positionModels.size() - 1).getX()); + to.put("y", positionModels.get(positionModels.size() - 1).getY()); + linkerObj.put("to", to); + elements.put(linkerId, linkerObj); + } else { + // 不包含的连线 + } + } + } + } + return elements; + } + + /** + * 在现有输出的图形结构上转化输入 输出活动属性,并将图上输入输出及连线删除 + */ + private void handleShapeInputOutAttr(PALRepositoryModel palModel, JSONObject elements) { + // 存放待删除图形的KEY + List removeKey = new ArrayList<>(); + + Map> nextShapeMap = new HashMap<>();// 记录当前形状的下一个(多个)形状 + Map> prevShapeMap = new HashMap<>();// 记录当前形状的上一个(多个)形状 + for (String key : elements.keySet()) { + JSONObject shapeObj = elements.getJSONObject(key); + if ("linker".equals(shapeObj.getString("name"))) { + // 输入 + String shapeId = shapeObj.getString("id"); + // 查找入线 + String fromId = shapeObj.getJSONObject("from").getString("id"); + String toId = shapeObj.getJSONObject("to").getString("id"); + // 记录from->to Map + if (!nextShapeMap.containsKey(fromId)) { + nextShapeMap.put(fromId, new HashSet<>()); + } + nextShapeMap.get(fromId).add(toId); + + if (!prevShapeMap.containsKey(toId)) { + prevShapeMap.put(toId, new HashSet<>()); + } + prevShapeMap.get(toId).add(fromId); + } + } + + Map> shapeInputMap = new HashMap<>();// 记录形状的所有输出 + Map> shapeOutMap = new HashMap<>();// 记录形状的所有输入 + for (String key : elements.keySet()) { + JSONObject shapeObj = elements.getJSONObject(key); + if (!"linker".equals(shapeObj.getString("name"))) { + // 输入 + String shapeId = shapeObj.getString("id"); + // 查找入线(输入) + if (prevShapeMap.containsKey(shapeId)) { + for (Map.Entry> entry : prevShapeMap.entrySet()) { + if (key.equals(entry.getKey())) { + Set prevShapeIds = entry.getValue(); + for (String prevShapeId : prevShapeIds) { + JSONObject prevShape = elements.getJSONObject(prevShapeId); + if ("document".equals(prevShape.getString("name"))) { + if (!shapeInputMap.containsKey(shapeId)) { + shapeInputMap.put(shapeId, new HashSet<>()); + } + shapeInputMap.get(shapeId).add(prevShape.getString("text")); + } + } + } + } + } + // 查找出线 + if (nextShapeMap.containsKey(shapeId)) { + for (Map.Entry> entry : nextShapeMap.entrySet()) { + if (key.equals(entry.getKey())) { + Set nextShapeIds = entry.getValue(); + for (String nextShapeId : nextShapeIds) { + JSONObject nextShape = elements.getJSONObject(nextShapeId); + if ("document".equals(nextShape.getString("name"))) { + if (!shapeOutMap.containsKey(shapeId)) { + shapeOutMap.put(shapeId, new HashSet<>()); + } + shapeOutMap.get(shapeId).add(nextShape.getString("text")); + } + } + } + } + } + } + } + + + for (String key : elements.keySet()) { + JSONObject shapeObj = elements.getJSONObject(key); + if ("linker".equals(shapeObj.getString("name"))) { + JSONObject from = elements.getJSONObject(shapeObj.getJSONObject("from").getString("id")); + if ("document".equals(from.getString("name"))) { + removeKey.add(key); + removeKey.add(from.getString("id")); + } + JSONObject to = elements.getJSONObject(shapeObj.getJSONObject("to").getString("id")); + if ("document".equals(to.getString("name"))) { + removeKey.add(key); + removeKey.add(to.getString("id")); + } + } + } + // 删除画布上的输入输出和其连线 + removeKey.stream().forEach(key -> elements.remove(key)); + + Map attrMap = new HashMap<>(); + JSONObject attrs1 = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), palModel.getMethodId(), palModel.getMethodId(), "method_service_node"); + attrMap.put("method_service_node", attrs1); + JSONObject attrs2 = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), palModel.getMethodId(), palModel.getMethodId(), "method_service_node4"); + attrMap.put("method_service_node4", attrs2); + JSONObject attrs3 = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), palModel.getMethodId(), palModel.getMethodId(), "method_approval_node"); + attrMap.put("method_approval_node", attrs3); + JSONObject attrs4 = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), palModel.getMethodId(), palModel.getMethodId(), "method_approval_node3"); + attrMap.put("method_approval_node3", attrs4); + + for (String key : elements.keySet()) { + JSONObject shapeObj = elements.getJSONObject(key); + if (!"linker".equals(shapeObj.getString("name"))) { + if (attrMap.containsKey(shapeObj.getString("name"))) { + JSONObject attrs = attrMap.get(shapeObj.getString("name")); + if (shapeInputMap.containsKey(key)) {// 有输入属性 + // 输入属性 + if (attrs != null && attrs.size() > 0 && attrs.containsKey(Constant.METHOD_INPUT)) { + JSONObject attrObj = JSONObject.parseObject(attrs.getJSONObject(Constant.METHOD_INPUT).toString()); + List contentList = new ArrayList<>(shapeInputMap.get(key)); + Collections.sort(contentList); + attrObj.put("value", StringUtils.join(contentList, ",")); + JSONArray dataAttributes = shapeObj.getJSONArray("dataAttributes"); + if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { + for (Object attribute : dataAttributes) { + JSONObject obj = (JSONObject) attribute; + if (obj.containsKey("attributesJsonArray")) { + JSONArray attributesJsonArray = obj.getJSONArray("attributesJsonArray"); + attributesJsonArray.add(attrObj); + printMsg("流程" + palModel.getName() + "的节点" + shapeObj.getString("text") + "输入属性内容" + attrObj.getString("value")); + } + } + } + } else { + printMsg("流程" + palModel.getName() + "的节点" + shapeObj.getString("text") + "没有配置输入属性"); + } + } + if (shapeOutMap.containsKey(key)) {// 有输出属性 + // 输出属性 + if (attrs != null && attrs.size() > 0 && attrs.containsKey(Constant.METHOD_OUTPUT)) { + JSONObject attrObj = JSONObject.parseObject(attrs.getJSONObject(Constant.METHOD_OUTPUT).toString()); + List contentList = new ArrayList<>(shapeOutMap.get(key)); + Collections.sort(contentList); + attrObj.put("value", StringUtils.join(contentList, ",")); + JSONArray dataAttributes = shapeObj.getJSONArray("dataAttributes"); + if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { + for (Object attribute : dataAttributes) { + JSONObject obj = (JSONObject) attribute; + if (obj.containsKey("attributesJsonArray")) { + JSONArray attributesJsonArray = obj.getJSONArray("attributesJsonArray"); + attributesJsonArray.add(attrObj); + printMsg("流程" + palModel.getName() + "的节点" + shapeObj.getString("text") + "输出属性内容" + attrObj.getString("value")); + } + } + } + } else { + printMsg("流程" + palModel.getName() + "的节点" + shapeObj.getString("text") + "没有配置输出属性"); + } + } + + } + } + } + } + + /** + * 处理流程属性前后置流程 + * + * @param wsId + * @param currentModelNoShape + * @param idRelationMap + * @param repositoryModelId + * @param elements + * @param arisModel + * @param modelObjOccMap + * @param objDefMap + */ + private void handleProcessAttrLeadOrRearProcess(String wsId, List currentModelNoShape, Map idRelationMap, String repositoryModelId, JSONObject elements, ModelModel arisModel, + Map> modelObjOccMap, Map objDefMap) { + // 如果当前流程下无图形信息 直接返回 + List objOccModels = modelObjOccMap.get(arisModel.getId()); + if (objOccModels == null || objOccModels.size() == 0) { + currentModelNoShape.add(arisModel); + return; + } + // 获取ARIS图形定义与PAL图形定义关系 + Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); + ObjDefMappingModel objDefMappingModel = objDefMappingMap.get("OT_FUNC-ST_PRCS_IF"); + List attributeModels = PALRepositoryAPIManager.getInstance().getValidAttributeModels(wsId, objDefMappingModel.getShapeMethod()); +// List leadProcess = attributeModels.stream().filter(item -> "lead_process".equals(item.getKey())).collect(Collectors.toList()); +// --by shang + List leadProcess = attributeModels.stream().filter(item -> Constant.METHOD_PRE_PROCESS.equals(item.getKey())).collect(Collectors.toList()); + PALMethodAttributeModel leadAttrModel = leadProcess.get(0); + List rearProcess = attributeModels.stream().filter(item -> Constant.METHOD_NEXT_PROCESS.equals(item.getKey())).collect(Collectors.toList()); + PALMethodAttributeModel rearAttrModel = rearProcess.get(0); + // 存放待删除图形的KEY + List removeKey = new ArrayList<>(); + // 流程关联属性结果集 + List relationList = new ArrayList<>(); + for (ObjOccModel objOccModel : objOccModels) { + ObjDefModel objDefModel = objDefMap.get(objOccModel.getDefId());// 形状定义 + // 根据ARIS图形定义信息判断当前模型下的所有形状里是否有系统形状 + if (objDefModel.getTypeNum().equals(objDefMappingModel.getTypeNum()) && objDefModel.getSymbolNum().equals(objDefMappingModel.getSymbolNum())) { + // 如果有输入输出形状 取出关联的PAL模型ID + String shapeId = idRelationMap.get(objOccModel.getId()); + JSONObject leadOrRearObj = elements.getJSONObject(shapeId); + for (String key : elements.keySet()) { + JSONObject tempShapeObj = elements.getJSONObject(key); + if ("linker".equals(tempShapeObj.getString("name"))) { + if (tempShapeObj.getJSONObject("from").getString("id").equals(shapeId)) { + // lead_process + PALRepositoryPropertyDao propertyDao = new PALRepositoryPropertyDao(); + PALRepositoryPropertyModel propertyModel = new PALRepositoryPropertyModel(); + propertyModel.setId(UUIDGener.getUUID()); + propertyModel.setPlId(repositoryModelId); + propertyModel.setPropertyId(leadAttrModel.getKey()); + propertyModel.setPropertyName(leadAttrModel.getNewTitle()); + JSONObject propValue = new JSONObject(); + propValue.put("fileId", repositoryModelId); + propValue.put("shapeId", ""); + propValue.put("shapeText", ""); + propValue.put("attrId", leadAttrModel.getKey()); + propValue.put("relationFileId", new JSONArray()); + propValue.put("relationShapeId", ""); + propValue.put("relationShapeText", ""); + propValue.put("groupPath", leadAttrModel.getGroupPath()); + List repositoryModels = PALRepositoryQueryAPIManager.getInstance().getPalRepositoryModelsByWsIdAndMethodId(wsId, "process.epc"); + repositoryModels = repositoryModels.stream().filter(model -> leadOrRearObj.getString("text").equals(model.getName())).collect(Collectors.toList()); + if (repositoryModels.size() > 0) { + propValue.getJSONArray("relationFileId").add(repositoryModels.get(0).getId()); + } + propertyModel.setPropertyValue(propValue.toString()); + propertyModel.setOrderIndex(0); + propertyDao.insert(propertyModel); + removeKey.add(key); + removeKey.add(shapeId); + break; + } else if (tempShapeObj.getJSONObject("to").getString("id").equals(shapeId)) { + // rear_process + PALRepositoryPropertyDao propertyDao = new PALRepositoryPropertyDao(); + PALRepositoryPropertyModel propertyModel = new PALRepositoryPropertyModel(); + propertyModel.setId(UUIDGener.getUUID()); + propertyModel.setPlId(repositoryModelId); + propertyModel.setPropertyId(rearAttrModel.getKey()); + propertyModel.setPropertyName(rearAttrModel.getNewTitle()); + JSONObject propValue = new JSONObject(); + propValue.put("fileId", repositoryModelId); + propValue.put("shapeId", ""); + propValue.put("shapeText", ""); + propValue.put("attrId", rearAttrModel.getKey()); + propValue.put("relationFileId", new JSONArray()); + propValue.put("relationShapeId", ""); + propValue.put("relationShapeText", ""); + propValue.put("groupPath", ""); + List repositoryModels = PALRepositoryQueryAPIManager.getInstance().getPalRepositoryModelsByWsIdAndMethodId(wsId, "process.epc"); + repositoryModels = repositoryModels.stream().filter(model -> leadOrRearObj.getString("text").equals(model.getName())).collect(Collectors.toList()); + if (repositoryModels.size() > 0) { + propValue.getJSONArray("relationFileId").add(repositoryModels.get(0).getId()); + } + propertyModel.setPropertyValue(propValue.toString()); + propertyModel.setOrderIndex(0); + propertyDao.insert(propertyModel); + removeKey.add(key); + removeKey.add(shapeId); + break; + } else { + continue; + } + } + } + } + } + removeKey.stream().forEach(key -> elements.remove(key)); + } + + /** + * 处理流程关联属性IT系统 + * @param wsId + * @param idRelationMap + * @param repositoryModelId + * @param elements + * @param arisModel + * @param modelObjOccMap + * @param objDefMap + * @param objDefLinkerMap + * @param itShapeMap + */ + private void handleProcessAttrItSystemRelation(String wsId, Map idRelationMap, String repositoryModelId, JSONObject elements, ModelModel arisModel, + Map> modelObjOccMap, + Map objDefMap, Map> objDefLinkerMap, Map itShapeMap) { + // 获取ARIS图形定义与PAL图形定义关系 + Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); + ObjDefMappingModel objDefMappingModel = objDefMappingMap.get("OT_APPL_SYS_TYPE-ST_APPL_SYS_TYPE"); + // 获取当前ARIS模型下所有的图形信息 + List objOccModels = modelObjOccMap.get(arisModel.getId()); + Map> shapeRelationItMap = new HashMap<>();// 记录PAL形状关联的IT系统文本 + for (ObjOccModel objOccModel: objOccModels) { + String objDefId = objOccModel.getDefId(); + // 获取定义形状通过连线进行连接的所有定义形状 + Set toObjDefIds = objDefLinkerMap.get(objDefId); + if (toObjDefIds == null || toObjDefIds.size() == 0) { + continue; + } + // 取出所有IT系统 + Set shapeRelationItObjDefNames = new HashSet<>();// 记录当前形状的IT系统(s) + for (String toObjDefId: toObjDefIds) { + ObjDefModel objDefModel = objDefMap.get(toObjDefId); + if (objDefModel.getSymbolNum().equals(objDefMappingModel.getSymbolNum()) && objDefModel.getTypeNum().equals(objDefMappingModel.getTypeNum())) { + // 是IT系统 + shapeRelationItObjDefNames.add(objDefModel.getName()); + } + } + if (shapeRelationItObjDefNames.size() > 0) { + shapeRelationItMap.put(idRelationMap.get(objOccModel.getId()), shapeRelationItObjDefNames); + } + } + List relationList = new ArrayList<>(); + for (Map.Entry> entry: shapeRelationItMap.entrySet()) { + String shapeId = entry.getKey(); + Set itShapeNames = entry.getValue(); + for (String itShapeName: itShapeNames) { + if (itShapeMap.containsKey(itShapeName)) { + DesignerShapeRelationModel m = new DesignerShapeRelationModel(); + m.setId(UUIDGener.getUUID()); + m.setFileId(repositoryModelId); + m.setShapeId(shapeId); + m.setShapeText(elements.getJSONObject(shapeId).getString("text")); + m.setRelationFileId(itShapeMap.get(itShapeName).getString("plId")); + m.setRelationShapeId(itShapeMap.get(itShapeName).getString("shapeId")); + m.setRelationShapeText(itShapeMap.get(itShapeName).getString("shapeName")); + m.setAttrId(Constant.METHOD_INFO_SYSTEM); + relationList.add(m); + } else { + // todo warn + printMsg("流程【" + arisModel.getName() + "】中的活动节点【" + elements.getJSONObject(shapeId).getString("text") + "】未找到IT系统【" + itShapeName + "】"); + } + } + } + // 保存关联关系 + if (relationList.size() > 0) { + DesignerShapeRelationDao relationDao = new DesignerShapeRelationDao(); + relationList.stream().forEach(item -> printMsg("流程【" + arisModel.getName() + "】中的活动节点【" + item.getShapeText() + "】关联当前流程下IT系统【" + item.getRelationShapeText() + "】")); + relationDao.barchInsert(relationList); + } + } + + /** + * 处理关联属性【角色】与流程关联 + * @param wsId + * @param repositoryModelId + * @param arisFunIdRelationPalRoleMap + * @param palShapeIdRelationArisOccIdMap + * @param elements + * @param arisModel + * @param modelObjOccMap + * @param objDefMap + * @param roleMdoelId + * @param palRoleIdRelationNameMap + * @throws AWSException + */ + private void handleProcessAttrRoleRelation(String wsId, String repositoryModelId, Map arisFunIdRelationPalRoleMap, Map palShapeIdRelationArisOccIdMap, JSONObject elements, ModelModel arisModel, + Map> modelObjOccMap, Map objDefMap, String roleMdoelId, Map palRoleIdRelationNameMap) throws AWSException { + // 获取ARIS图形定义与PAL图形定义关系 + Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); + ObjDefMappingModel objDefMappingModel = objDefMappingMap.get("OT_PERS_TYPE-ST_EMPL_TYPE"); + // 获取当前ARIS模型下所有的图形信息 + List objOccModels = modelObjOccMap.get(arisModel.getId()); + // 存放待删除图形的KEY + List removeKey = new ArrayList<>(); + // 流程关联属性结果集 + List relationList = new ArrayList<>(); + + Map map = new HashMap<>(); + for (Map.Entry entry : palShapeIdRelationArisOccIdMap.entrySet()) { + String shapeId = entry.getKey(); + String arisShapeId = entry.getValue(); + if (arisFunIdRelationPalRoleMap.containsKey(arisShapeId)) { + String roleShapeId = arisFunIdRelationPalRoleMap.get(arisShapeId); + DesignerShapeRelationModel m = new DesignerShapeRelationModel(); + m.setId(UUIDGener.getUUID()); + m.setFileId(repositoryModelId); + m.setShapeId(shapeId); + m.setShapeText(elements.getJSONObject(shapeId).getString("text")); + m.setRelationFileId(roleMdoelId); + m.setRelationShapeId(roleShapeId); + m.setRelationShapeText(palRoleIdRelationNameMap.get(roleShapeId)); + m.setAttrId(Constant.METHOD_ROLE); + relationList.add(m); + } + } + + Set roleIdSet = new HashSet<>(); + for (String key : elements.keySet()) { + JSONObject tempShapeObj = elements.getJSONObject(key); + if ("role".equals(tempShapeObj.getString("name"))) { + roleIdSet.add(key); + } + } + for (String key : elements.keySet()) { + JSONObject tempShapeObj = elements.getJSONObject(key); + if ("linker".equals(tempShapeObj.getString("name"))) { + String text = ""; + if (roleIdSet.contains(tempShapeObj.getJSONObject("from").getString("id"))) { + text = elements.getJSONObject(tempShapeObj.getJSONObject("from").getString("id")).getString("text"); + // 删除图形与连线 + removeKey.add(key); + removeKey.add(tempShapeObj.getJSONObject("from").getString("id")); + } else if (roleIdSet.contains(tempShapeObj.getJSONObject("to").getString("id"))) { + text = elements.getJSONObject(tempShapeObj.getJSONObject("to").getString("id")).getString("text"); + // 删除图形与连线 + removeKey.add(key); + removeKey.add(tempShapeObj.getJSONObject("to").getString("id")); + } + printMsg("流程" + arisModel.getName() + "删除角色形状" + text + "和其连线"); + } + } + + // 删除没有与活动进行连线相连的角色形状(角色图中已包含该角色图标) + for (String key : elements.keySet()) { + JSONObject tempShapeObj = elements.getJSONObject(key); + if ("role".equals(tempShapeObj.getString("name")) && !removeKey.contains(tempShapeObj.getString("id"))) { + removeKey.add(key); + printMsg("流程" + arisModel.getName() + "删除角色形状" + tempShapeObj.getString("text") + ",该角色无连线连接到活动"); + } + } + + // 保存关联关系 + if (relationList.size() > 0) { + DesignerShapeRelationDao relationDao = new DesignerShapeRelationDao(); + relationList.stream().forEach(item -> printMsg("流程【" + arisModel.getName() + "】中的活动节点【" + item.getShapeText() + "】关联当前流程下角色【" + item.getRelationShapeText() + "】")); + relationDao.barchInsert(relationList); + } + removeKey.stream().forEach(key -> elements.remove(key)); + } + + /** + * 设置画布大小 + * + * @param elements + */ + private void setDiagramHeightWidth(JSONObject definition, JSONObject elements) { + // 获取最大宽高,给100长度富余 + JSONObject maxHW = getMaxPositionXY(elements); + int maxX = maxHW.getInteger("maxX") + 150; + int maxH = maxHW.getInteger("maxY") + 150; + JSONObject page = definition.getJSONObject("page"); + int pageW = page.getInteger("width"); + int pageH = page.getInteger("height"); + page.put("width", pageW > maxX ? pageW : maxX); + page.put("height", pageH > maxH ? pageH : maxH); + definition.put("page", page); + } + + private JSONObject getMaxPositionXY(JSONObject elements) { + int maxX = -99999; + int maxY = -99999; + Iterator it = elements.keySet().iterator(); + while (it.hasNext()) { + String key = it.next(); + JSONObject shape = elements.getJSONObject(key); + String shapeName = shape.getString("name"); + if (!"linker".equals(shapeName)) { + JSONObject props = shape.getJSONObject("props"); + int x = props.getInteger("x"); + int y = props.getInteger("y"); + maxX = maxX < x ? x : maxX; + maxY = maxY < y ? y : maxY; + } + } + JSONObject result = new JSONObject(); + result.put("maxX", maxX); + result.put("maxY", maxY); + return result; + } + + + + + + /** + * 创建具有合理位置的节点数据 + * + * @param elements + * @param shapeRowCount + * @return + */ + private JSONArray getMethodElementsJSONArray(JSONArray elements, int shapeRowCount) { + JSONArray result = new JSONArray(); + int zindex = 0; + int initX = 0; + int initY = 0; + int pageEdge = 100; + int count = 0; + initX += pageEdge; + initY += pageEdge; + for (int i = 0; i < elements.size(); i++) { + JSONObject shape = elements.getJSONObject(i); + count++; + if (count % (shapeRowCount + 1) == 0) { + count = 1; + initY += 130; + // 换行 + initX = 0; + initX = pageEdge + initX; + } + zindex++; + if (shape.containsKey("dataAttributes")) { + JSONArray dataAttributes = JSONArray.parseArray(shape.getString("dataAttributes")); + for (int index = 0; index < dataAttributes.size(); index++) { + dataAttributes.getJSONObject(index).put("id", UUIDGener.getObjectId()); + } + shape.put("dataAttributes", dataAttributes); + } + int totalWidth = 240;// 每个节点总宽度,空白+节点+空白 + int totalHeight = 200;// 每个节点总高度,空白+节点+空白 + int x = 0; + int y = 0; + int w = validateJson(shape.getJSONObject("props").getInteger("w")); + int h = validateJson(shape.getJSONObject("props").getInteger("h")); + int leftBlankWidth = (totalWidth - w) / 2; + int topBlankHeight = (totalHeight - h) / 2; + x = initX + leftBlankWidth; + initX = x + w + leftBlankWidth; + y = initY + topBlankHeight; +// y = pageEdge + initY; +// if (y < 0) { +// y = 100; +// } + JSONObject props = shape.getJSONObject("props"); + props.put("x", x); + props.put("y", y); + props.put("zindex", zindex); + shape.put("props", props); + result.add(shape); + } + return result; + } + + /** + * 创建角色模型和角色元素,并且获取aris角色与pal角色映射关系 + * 角色与流程活动都是以角色为起点连接流程活动 + * 角色与岗位都是以岗位为起点连接角色 + * 活动与角色是1对1关系,不存在单活动对应多个角色 + * @param coeProcessLevel + * @param parentId + * @param wsId + * @param currentModelNoShape + * @param palModel + * @param arisModel + * @param modelObjOccMap + * @param objDefMap + * @param objOccMap + * @param cxnOccMap + * @param objDefLinkerMap + * @param arisFunIdRelationPalRoleMap + * @param methodAttrsMap + * @return + */ + private String createRoleModelAndElements(PALRepository coeProcessLevel, String parentId, String wsId, List currentModelNoShape, PALRepositoryModel palModel, ModelModel arisModel, Map> modelObjOccMap, Map objDefMap, Map objOccMap, Map> cxnOccMap, Map> objDefLinkerMap, Map arisFunIdRelationPalRoleMap, Map> methodAttrsMap, Map palRoleIdRelationNameMap) { + // 统计模型内的角色信息,创建角色与形状的关联关系,提前创建活动与角色的id关联关系,建立角色的角色图,角色图中处理岗位为文本属性内容 + + // 统计模型内所有的角色形状 + List objOccModels = modelObjOccMap.get(arisModel.getId()); + // 获取角色 + List roleObjOccModels = new ArrayList<>(); + for (ObjOccModel objOccModel : objOccModels) { + ObjDefModel objDefModel = objDefMap.get(objOccModel.getDefId()); + if (objDefModel.getTypeNum().equals("OT_PERS_TYPE") && objDefModel.getSymbolNum().equals("ST_EMPL_TYPE")) {// 角色 + roleObjOccModels.add(objOccModel); + } + } + if (roleObjOccModels.size() == 0) { + printMsg("流程模型" + palModel.getName() + "无任何角色模型,忽略角色与岗位导入"); + return null; + } + + Set noneRelationRole = new HashSet<>(); + + // 创建角色与形状关联关系 + // 获取当前aris模型内的所有角色list + List roleCxnOccModels = new ArrayList<>(); + for (ObjOccModel roleOccModel : roleObjOccModels) { + List list = cxnOccMap.get(roleOccModel.getId()); + // list为null,该角色在该模型中没有连接任何的活动,忽略导入该角色 + if (list == null) { + printMsg("流程模型" + palModel.getName() + "检测到角色" + objDefMap.get(roleOccModel.getDefId()).getName() + "尚未连接到任何活动上,忽略该角色"); + noneRelationRole.add(objDefMap.get(roleOccModel.getDefId()).getName()); + continue; + } + for (CxnOccModel cxnOccModel : list) { + if (cxnOccModel.getModelId().equals(arisModel.getId())) { + roleCxnOccModels.add(cxnOccModel); + } + } + } + if (roleCxnOccModels.size() == 0) { + printMsg("流程模型" + palModel.getName() + "无任何角色模型与流程活动进行连接,忽略角色与岗位导入"); + return null; + } + + // 记录重复的角色,根据名称进行记录 + Map> repeatRoleMap = new HashMap<>(); + // 记录aris功能活动与角色的关系 + Map arisFunRelationRoleMap = new HashMap<>(); + // 记录重复的角色名称 + for (CxnOccModel cxnOccModel: roleCxnOccModels) { + ObjOccModel occModel = objOccMap.get(cxnOccModel.getId()); + ObjDefModel objDefModel = objDefMap.get(occModel.getDefId()); + arisFunRelationRoleMap.put(cxnOccModel.getToId(), objDefModel.getName()); + String roleName = objDefModel.getName(); + if (!repeatRoleMap.containsKey(roleName)) { + repeatRoleMap.put(roleName, new HashSet<>()); + } + repeatRoleMap.get(roleName).add(occModel.getId()); + } + // 没有关联活动的角色,也加入到角色图中 + for (String roleName : noneRelationRole) { + if (!repeatRoleMap.containsKey(roleName)) { + repeatRoleMap.put(roleName, new HashSet<>()); + } + } + + // 创建角色图的名称与PAL角色图形状ID对应关系 + Map roleNamePalIdMap = new HashMap<>(); + for (String roleName : repeatRoleMap.keySet()) { + String roleShapeId = UUIDGener.getObjectId(); + roleNamePalIdMap.put(roleName, roleShapeId); + palRoleIdRelationNameMap.put(roleShapeId, roleName); + } + // 记录Aris功能Occ ID与PALroleId关联关系 + for (Map.Entry entry : arisFunRelationRoleMap.entrySet()) { + if (roleNamePalIdMap.containsKey(entry.getValue())) { + arisFunIdRelationPalRoleMap.put(entry.getKey(), roleNamePalIdMap.get(entry.getValue())); + } + } + + // 角色名称与岗位名称合集 + Map> roleRelationPositonMap = new HashMap<>(); + // 查找角色对应的岗位 + for (ObjOccModel roleOccModel : roleObjOccModels) { + ObjDefModel roleObjDefModel = objDefMap.get(roleOccModel.getDefId()); + String linkedModelIds = roleObjDefModel.getLinkedModelIds(); + if (UtilString.isEmpty(linkedModelIds)) {// 角色无关联角色图 + printMsg("流程模型" + palModel.getName() + roleObjDefModel.getName() + "角色无任何关联岗位,忽略该角色岗位"); + } else {// 角色有关联角色图 + List relationPositonList = modelObjOccMap.get(linkedModelIds);// linkedModelIds按照单个值对待,暂无发现多值 + if (relationPositonList == null || relationPositonList.size() == 0) {// 角色有关联图但是关联的角色图查询不到 + printMsg("流程模型" + palModel.getName() + roleObjDefModel.getName() + "角色存在关联LinkedModels.IdRefs:" + linkedModelIds + " 但无法查询对应Model内容"); + } else { + for (ObjOccModel objOccModel: relationPositonList) { + ObjDefModel positionDefModel = objDefMap.get(objOccModel.getDefId()); + if (positionDefModel.getTypeNum().equals("OT_POS") && positionDefModel.getSymbolNum().equals("ST_POS")) { + // 查询出岗位,记录到角色中,角色名称为key,岗位名称为value + if (!roleRelationPositonMap.containsKey(roleObjDefModel.getName())) { + roleRelationPositonMap.put(roleObjDefModel.getName(), new HashSet<>()); + } + roleRelationPositonMap.get(roleObjDefModel.getName()).add(positionDefModel.getName()); + } + } + } + } + } + + // 生成一个空的与流程同名角色模型文件 + String id = UUIDGener.getUUID(); + int orderIndex = coeProcessLevel.getChildrenMaxOrderIndexByPidAndWsId(parentId, wsId) + 1; + Timestamp nowTime = new Timestamp(System.currentTimeMillis()); + + PALRepositoryModelImpl model = CoeProcessLevelUtil.createPALRepositoryModel(id, UUIDGener.getUUID(), wsId, arisModel.getName(), "", orderIndex, parentId, "org", true, 1, + id, false, "org.role", "0", 1, null, null, uc.getUID(), uc.getUID(), nowTime, null, null, null, null, + null, null, null, null, null, -1); + coeProcessLevel.insert(model); + printMsg("与流程同名的角色空模型创建完成【文件ID】" + model.getId()); + BaseModel baseModel = CoeDesignerAPIManager.getInstance().getDefinition(model.getId(), 0); + if (baseModel == null) { + baseModel = CoeDesignerUtil.createModel(model.getId(), 0); + baseModel.setCreateHistory(false); + } + baseModel.setUpdateTime(new SimpleDateFormat(CoeDesignerConstant.DATE_TIME_STYLE_YYYY_MM_DD_HH_MM_SS).format(new Date())); + String define = baseModel.getDefinition(); + JSONObject definition = JSONObject.parseObject(define); + JSONObject elements = definition.getJSONObject("elements"); + Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); + ObjDefMappingModel objDefMappingModel = objDefMappingMap.get("OT_PERS_TYPE-ST_EMPL_TYPE"); + String shapeMethodId = objDefMappingModel.getShapeMethod(); + String shapeType = objDefMappingModel.getShapeType(); + JSONObject shapeDefine = ShapeUtil.getProcessShapeDefinitionByName(shapeMethodId, shapeType); + + JSONArray shapes = new JSONArray(); + for (Map.Entry entry: roleNamePalIdMap.entrySet()) { + String shapeText = entry.getKey(); + String shapeId = entry.getValue(); + JSONObject newShape = JSONObject.parseObject(shapeDefine.toString()); + newShape.put("id", shapeId); + newShape.put("text", shapeText); + shapes.add(newShape); + } + + JSONArray newShapes = this.getMethodElementsJSONArray(shapes, 6); + for (int i = 0; i < newShapes.size(); i++) { + JSONObject shapeObj = newShapes.getJSONObject(i); + elements.put(shapeObj.getString("id"), shapeObj); + printMsg("生成角色图 角色【" + shapeObj.getString("text") + "】"); + } + + // 设置角色图形状默认属性配置 + this.handleShapeDefaultAttr(wsId, palModel, elements, methodAttrsMap); + + // 完善岗位属性 + for (String key : elements.keySet()) { + JSONObject shape = elements.getJSONObject(key); + if ("linker".equals(shape.getString("name"))) { + continue; + } + String shapeText = shape.getString("text"); + if (roleRelationPositonMap.containsKey(shapeText) && roleRelationPositonMap.get(shapeText).size() > 0) { + Set postText = roleRelationPositonMap.get(shapeText); + List list = new ArrayList<>(postText); + Collections.sort(list); + String postTextVal = StringUtils.join(list, ",");// 岗位内容 + JSONArray dataAttributes = shape.getJSONArray("dataAttributes"); + if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { + for (Object attribute : dataAttributes) { + JSONObject obj = (JSONObject) attribute; + if (obj.containsKey("attributesJsonArray")) { + JSONArray attributesJsonArray = obj.getJSONArray("attributesJsonArray"); + boolean flag = false; + for (int i = 0; i < attributesJsonArray.size(); i++) { + if (attributesJsonArray.getJSONObject(i).containsKey("id")) { + String attrId = Constant.METHOD_POST_TEXT; + if (attrId.equals(attributesJsonArray.getJSONObject(i).getString("id"))) { + flag = true; + attributesJsonArray.getJSONObject(i).put("value", postTextVal); + printMsg("角色图" + model.getName() + "角色" + shapeText + "岗位属性值为" + postTextVal); + } + } + } + if (!flag) { + printMsg("角色图" + model.getName() + "角色" + shapeText + "没有岗位属性配置" + Constant.METHOD_POST_TEXT); + } + } + } + } + } else { + printMsg("角色图" + model.getName() + "角色" + shapeText + "无岗位属性内容值"); + } + } + definition.put("elements", elements); + // 设置画布大小 + setDiagramHeightWidth(definition, elements); + baseModel.setDefinition(definition.toString()); + // 保存文件 + CoeDesignerAPIManager.getInstance().storeDefinition(baseModel);// dao操作 + return id; + } + + private int validateJson(Integer index) { + return index == null ? 0 : index; + } + + /** + * 获取连线的折点(不包括起始端) + * + * @param positionModels + * @return + */ + private Object getLinkerPoints(List positionModels) { + JSONArray result = new JSONArray(); + if (positionModels.size() > 2) { + for (int i = 1; i < positionModels.size() - 1; i++) { + JSONObject obj = new JSONObject(); + obj.put("x", positionModels.get(i).getX()); + obj.put("y", positionModels.get(i).getY()); + result.add(obj); + } + } + return result; + } + + /** + * 获取连线angle + * + * @param positionModels + * @param type + * @return + */ + private double getLinkerAngle(List positionModels, String type) { + if (positionModels.size() < 2) { + System.out.println("出错了"); + return 0; + } else if (positionModels.size() == 2) { + if (positionModels.get(0).getX() == positionModels.get(1).getX()) { + if ("from".equals(type)) { + return (positionModels.get(0).getY() - positionModels.get(1).getY() > 0) ? Constant.ANGLE_DOWN : Constant.ANGLE_UP; + } else { + return (positionModels.get(0).getY() - positionModels.get(1).getY() > 0) ? Constant.ANGLE_UP : Constant.ANGLE_DOWN; + } + } else { + if ("from".equals(type)) { + return (positionModels.get(0).getX() - positionModels.get(1).getX() > 0) ? Constant.ANGLE_RIGHT : Constant.ANGLE_LEFT; + } else { + return (positionModels.get(0).getX() - positionModels.get(1).getX() > 0) ? Constant.ANGLE_LEFT : Constant.ANGLE_RIGHT; + } + } + } else { + List list = new ArrayList<>(); + if ("from".equals(type)) { + list.add(new PositionModel(positionModels.get(0).getX(), positionModels.get(0).getY())); + list.add(new PositionModel(positionModels.get(1).getX(), positionModels.get(1).getY())); + } else { + list.add(new PositionModel(positionModels.get(positionModels.size() - 2).getX(), positionModels.get(positionModels.size() - 2).getY())); + list.add(new PositionModel(positionModels.get(positionModels.size() - 1).getX(), positionModels.get(positionModels.size() - 1).getY())); + } + return getLinkerAngle(list, type); + } + } + + /** + * 获取默认属性内容 + * @param attr + * @return + */ + private JSONObject getDefaultAttrObj (JSONObject attr) { + String ref = attr.getString("ref"); + boolean readonly = attr.getBooleanValue("readonly"); + String scope = attr.getString("scope"); + String attrName = attr.getString("title"); + String attrId = attr.getString("id"); + String type = attr.getString("type"); + String groupPath = attr.getString("groupPath"); + String attrKey = attr.getString("key"); + String attrValue = ""; + JSONObject object2 = new JSONObject(); + object2.put("ref", ref); + object2.put("readonly", readonly); + object2.put("scope", scope); + object2.put("name", attrName); + object2.put("id", attrId); + object2.put("type", type); + object2.put("groupPath", groupPath); + object2.put("key", attrKey); + object2.put("value", ""); + return object2; + } + + /** + * Aris模型匹配PAL模型 + * + * @param arisModel + * @return + */ + private PALRepositoryModel matchPalModel(ModelModel arisModel, String wsId) { + // 查询当前资产库中建模类型是EPC的所有流程文件属性 + PALRepositoryPropertyDao dao = new PALRepositoryPropertyDao(); + List propertyModels = dao.queryByWsId(wsId); + propertyModels = propertyModels.stream().filter(item -> Constant.METHOD_ARIS_URL.equals(item.getPropertyId())).collect(Collectors.toList()); + String modelPath = "\\伊利集团业务流程管理平台" + arisModel.getModelPath(); + boolean flag = false; + PALRepositoryModel repositoryModel = null; + // printMsg("MODEL PATH "+modelPath); + for (PALRepositoryPropertyModel propertyModel : propertyModels) { + if (propertyModel.getPropertyValue().equals(modelPath)) { + // printMsg("ARIS路径 "+propertyModel.getPropertyValue()); + repositoryModel = new PALRepository().getInstance(propertyModel.getPlId()); + if (arisModel.getName().trim().equals(repositoryModel.getName())) { + printMsg("匹配到的MODEL PATH " + modelPath + "\\" + arisModel.getName()); + flag = true; + break; + } else { + repositoryModel = null; + } + } + } + if (!flag) { + // 未匹配出结果,记录日志 todo + printMsg("未匹配出结果MODEL PATH " + modelPath + "\\" + arisModel.getName()); + } + return repositoryModel; + } + + private void printMsg(String msg) { + SDK.getLogAPI().consoleInfo(msg); + } +} diff --git a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlImportWeb.java b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlImportWeb.java index 9be401ce..c12a7c46 100644 --- a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlImportWeb.java +++ b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/aris/web/ArisXmlImportWeb.java @@ -1,9 +1,15 @@ package com.actionsoft.apps.coe.pal.datamigration.aris.web; +import com.actionsoft.apps.coe.pal.batch.web.create.shape.ImportShapeExcel; +import com.actionsoft.apps.coe.pal.constant.CoEConstant; +import com.actionsoft.apps.coe.pal.datamigration.aris.constant.ArisConstant; import com.actionsoft.apps.coe.pal.datamigration.aris.mapping.ModelMappingAPIManager; import com.actionsoft.apps.coe.pal.datamigration.aris.model.*; import com.actionsoft.apps.coe.pal.datamigration.aris.util.XMLUtil; +import com.actionsoft.apps.coe.pal.datamigration.cache.DataMigrationCache; import com.actionsoft.apps.coe.pal.datamigration.constant.Constant; +import com.actionsoft.apps.coe.pal.datamigration.log.model.LogModel; +import com.actionsoft.apps.coe.pal.datamigration.util.LogUtil; import com.actionsoft.apps.coe.pal.datamigration.util.ShapeUtil; import com.actionsoft.apps.coe.pal.pal.method.model.PALMethodAttributeModel; import com.actionsoft.apps.coe.pal.pal.repository.PALRepositoryAPIManager; @@ -11,7 +17,6 @@ import com.actionsoft.apps.coe.pal.pal.repository.PALRepositoryQueryAPIManager; import com.actionsoft.apps.coe.pal.pal.repository.cache.PALRepositoryCache; import com.actionsoft.apps.coe.pal.pal.repository.dao.CoeProcessLevelDaoFacotory; import com.actionsoft.apps.coe.pal.pal.repository.dao.PALRepository; -import com.actionsoft.apps.coe.pal.pal.repository.dao.PALRepositoryAttributeDao; import com.actionsoft.apps.coe.pal.pal.repository.dao.PALRepositoryPropertyDao; import com.actionsoft.apps.coe.pal.pal.repository.designer.CoeDesignerShapeAPIManager; import com.actionsoft.apps.coe.pal.pal.repository.designer.constant.CoeDesignerConstant; @@ -20,7 +25,6 @@ import com.actionsoft.apps.coe.pal.pal.repository.designer.model.BaseModel; import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.dao.DesignerShapeRelationDao; import com.actionsoft.apps.coe.pal.pal.repository.designer.relation.model.DesignerShapeRelationModel; import com.actionsoft.apps.coe.pal.pal.repository.designer.util.CoeDesignerUtil; -import com.actionsoft.apps.coe.pal.pal.repository.model.PALRepositoryAttributeModel; import com.actionsoft.apps.coe.pal.pal.repository.model.PALRepositoryModel; import com.actionsoft.apps.coe.pal.pal.repository.model.PALRepositoryPropertyModel; import com.actionsoft.apps.coe.pal.pal.repository.model.impl.PALRepositoryModelImpl; @@ -32,15 +36,20 @@ import com.actionsoft.bpms.server.UserContext; import com.actionsoft.bpms.server.fs.DCContext; import com.actionsoft.bpms.server.fs.dc.DCProfileManager; import com.actionsoft.bpms.util.UUIDGener; +import com.actionsoft.bpms.util.UtilDate; import com.actionsoft.bpms.util.UtilString; import com.actionsoft.exception.AWSException; +import com.actionsoft.i18n.I18nRes; import com.actionsoft.sdk.local.SDK; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.apache.commons.lang.StringUtils; import org.dom4j.Document; +import org.dom4j.DocumentException; import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.*; @@ -57,6 +66,74 @@ public class ArisXmlImportWeb extends ActionWeb { _uc = uc; } + private String logId; + private String logPath; + private File simpleLogFile; + private File fullLogFile; + private File warnLogFile; + private String filePath; + private String fileName; + + Timestamp startDate = new Timestamp(System.currentTimeMillis()); + + + public void initParams () { + logId = UUIDGener.getUUID();// 记录缓存 + String fileValue = "arisXML-" + new SimpleDateFormat("yyyy-MM-dd-HHmmss").format(new Date()) + "-" + _uc.getUID(); + // 创建dc目录 + DCPluginProfile dcProfile = DCProfileManager.getDCProfile(Constant.APP_ID, ArisConstant.REPOSITORY_NAME); + DCContext dc = new DCContext(_uc, dcProfile, Constant.APP_ID, ArisConstant.LOG_GROUP_VALUE, fileValue); + String dirPath = dc.getPath(); + File dir = new File(dirPath); + dir.mkdirs(); + simpleLogFile = new File(dirPath, ArisConstant.IMPORT_LOG_FILE_SIMPLE); + try { + simpleLogFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + fullLogFile = new File(dirPath, ArisConstant.IMPORT_LOG_FILE_FULL); + try { + fullLogFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + warnLogFile = new File(dirPath, ArisConstant.IMPORT_LOG_FILE_WARN); + try { + warnLogFile.createNewFile(); + } catch (IOException e) { + e.printStackTrace(); + } + + logPath = simpleLogFile.getPath();// 前端实时展示的日志 + } + + /** + * 创建日志记录Model + * @param id + * @param wsId + * @param fileName + * @param filePath + * @param createDate + * @return + */ + private void createLogModel(String id, String wsId, String fileName, String filePath, Timestamp createDate) { + LogModel model = new LogModel(); + model.setId(id); + model.setWsId(wsId); + model.setFileName(fileName); + model.setFilePath(filePath); + model.setLogPath(logPath); + model.setCreateUser(_uc.getUID()); + model.setCreateUserName(_uc.getUserName()); + model.setCreateDate(createDate); + model.setStartDate(createDate); + model.setResultType(Constant.LOG_RESULT_TYPE_RUN); + model.setMainInfo("导入进行中"); + // 存储日志db + LogUtil.createLog(model); + } + /** * 迁移测试 * @@ -64,532 +141,214 @@ public class ArisXmlImportWeb extends ActionWeb { * @return */ public String dataMigrate(String wsId, String groupValue, String fileValue, String fileName) { - ResponseObject ro = ResponseObject.newOkResponse(); - // 校验资产库 + // 初始化一些参数 + initParams(); + // 创建日志信息db + createLogModel(logId, wsId, fileName, filePath, startDate); + LogUtil.appendLog("注:该日志文件存储简要日志信息", simpleLogFile); + LogUtil.appendLog("注:该日志文件存储详细日志信息", fullLogFile); + LogUtil.appendLog("注:该日志文件记录警告、出错日志信息", warnLogFile); + + LogUtil.appendLog("Aris XML流程导入 Begin " + UtilDate.datetimeFormat(startDate), simpleLogFile, fullLogFile, warnLogFile); + + // 校验资产库是否存在可用 boolean isActive = PALRepositoryQueryAPIManager.getInstance().isActiveWorkSpace(wsId); if (!isActive) { - return ResponseObject.newErrResponse("资产库不存在或已停用").toString(); + LogUtil.appendLog(Constant.LOG_ERROR + "资产库不存在或已停用," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); } - DCPluginProfile dcProfile = DCProfileManager.getDCProfile("com.actionsoft.apps.coe.pal.datamigration", "migration"); - DCContext dc = new DCContext(_uc, dcProfile, "com.actionsoft.apps.coe.pal.datamigration", groupValue, fileValue, fileName); + LogUtil.appendLog(Constant.LOG_SUCCESS + "校验资产库存在并可用", simpleLogFile, fullLogFile); + + // 校验文件/形状属性配置是否正常 + ResponseObject checkRo = checkMethodConfig(wsId); + if (checkRo.isErr()) { + return checkRo.toString(); + } + // 校验文件是否存在 + DCPluginProfile dcProfile = DCProfileManager.getDCProfile(Constant.APP_ID, "migration");// repositoryName要调整新的路径,配合前端, todo + DCContext dc = new DCContext(_uc, dcProfile, Constant.APP_ID, groupValue, fileValue, fileName); File file = new File(dc.getFilePath()); - if (!file.exists()) { - ro = ResponseObject.newErrResponse("上传文件不存在"); - return ro.toString(); - } else if (!".xml".equals(fileName.substring(fileName.lastIndexOf(".")))) { - ro = ResponseObject.newErrResponse("上传文件格式不正确,请上传xml文件"); - return ro.toString(); + LogUtil.appendLog(Constant.LOG_ERROR + "上传文件不存在," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); + return ResponseObject.newErrResponse("上传文件不存在").toString(); } + LogUtil.appendLog(Constant.LOG_SUCCESS + "校验上传文件是否存在", simpleLogFile, fullLogFile); - // 创建日志文件 + if (!".xml".equals(fileName.substring(fileName.lastIndexOf(".")))) { + LogUtil.appendLog(Constant.LOG_ERROR + "上传文件名称格式不正确," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); + return ResponseObject.newErrResponse("上传文件名称格式不正确,请上传XML文件").toString(); + } + LogUtil.appendLog(Constant.LOG_SUCCESS + "校验上传文件是否为XML格式", simpleLogFile, fullLogFile); - // - String number = this.checkMethodInfo(wsId, "process.epc", "process", "process.epc", "过程链图", "编号", Constant.METHOD_NUMBER); - if (UtilString.isNotEmpty(number)) return ResponseObject.newWarnResponse(number).toString(); - // 校验角色图下是否有建模属性【岗位】 - // String post = this.checkMethodInfo(wsId, "org.normal", "org", "org.normal", "角色图", "岗位", Constant.METHOD_POST); - // if (UtilString.isNotEmpty(post)) return ResponseObject.newWarnResponse(post).toString(); - // 校验过程链图下是否有建模属性【角色】 - String role = this.checkMethodInfo(wsId, "process.epc", "process", "process.epc", "过程链图", "角色", Constant.METHOD_ROLE); - if (UtilString.isNotEmpty(role)) return ResponseObject.newWarnResponse(role).toString(); - // 校验过程链图下是否有建模属性【IT系统】 - String itSystem = this.checkMethodInfo(wsId, "process.epc", "process", "process.epc", "过程链图", "IT系统", Constant.METHOD_INFO_SYSTEM); - if (UtilString.isNotEmpty(itSystem)) return ResponseObject.newWarnResponse(itSystem).toString(); - // 校验过程链图下是否有建模属性【输入】 - String input = this.checkMethodInfo(wsId, "process.epc", "process", "process.epc", "过程链图", "输入", Constant.METHOD_INPUT); - if (UtilString.isNotEmpty(input)) return ResponseObject.newWarnResponse(input).toString(); - // 校验过程链图下是否有建模属性【输出】 - String out = this.checkMethodInfo(wsId, "process.epc", "process", "process.epc", "过程链图", "输出", Constant.METHOD_OUTPUT); - if (UtilString.isNotEmpty(out)) return ResponseObject.newWarnResponse(out).toString(); - List attributeModels = PALRepositoryAPIManager.getInstance().getValidAttributeModels(wsId, "process.epc"); - List leadProcess = attributeModels.stream().filter(item -> Constant.METHOD_PRE_PROCESS.equals(item.getKey())).collect(Collectors.toList()); - if (leadProcess.size() == 0) { - return ResponseObject.newWarnResponse("请打开建模管理应用,查看当前建模分类【过程链图】下是否存在【前置流程/" + Constant.METHOD_PRE_PROCESS + "】建模属性").toString(); - } - List rearProcess = attributeModels.stream().filter(item -> Constant.METHOD_NEXT_PROCESS.equals(item.getKey())).collect(Collectors.toList()); - if (rearProcess.size() == 0) { - return ResponseObject.newWarnResponse("请打开建模管理应用,查看当前建模分类【过程链图】下是否存在【后置流程/" + Constant.METHOD_NEXT_PROCESS + "】建模属性").toString(); - } - // 校验过程链图下是否有文件属性【前置流程】【后置流程】 - PALRepositoryAttributeDao attributeDao = new PALRepositoryAttributeDao(); - List fileAttributes = attributeDao.getFileAttribute(wsId, "process.epc"); - fileAttributes = fileAttributes.stream() - .filter(attrModel -> Constant.METHOD_PRE_PROCESS.equals(attrModel.getAttrId()) || Constant.METHOD_NEXT_PROCESS.equals(attrModel.getAttrId())) - .collect(Collectors.toList()); - if (fileAttributes.size() < 2) { - return ResponseObject.newWarnResponse("请打开建模管理应用,查看当前建模分类【过程链图】下是否存在【前置/后置流程|" + Constant.METHOD_PRE_PROCESS + "/" + Constant.METHOD_NEXT_PROCESS + "】建模属性").toString(); - } - - // wsId = "ad5f246a-b618-4908-92f8-94fda59c78eb";// 测试资产库--伊利项目 - // String filePath = "/Users/actionsoft/Documents/workspace/IDEA/yili/apps/com.actionsoft.apps.coe.pal.datamigration/testFile/sourceFile/"; - // String fileName = "999actionsoft.xml"; - // String fileName = "publishxmlexport.xml"; - // String fileName = "xmlexport.xml"; - // 读取xml文件 - Document d = XMLUtil.readXML(file.getPath(), true); - String toFilePath = "/Users/sunlh/Documents/ideaData/actionsoft/aws6.4.1.1008.yili2/apps/com.actionsoft.apps.coe.pal.datamigration/testFile/targetFile/"; - XMLUtil.writeXml(d, toFilePath + fileName); + // 校验xml文档是否能够正常解析 + Document doc = analysisXMLFile(file.getPath(), true); + // String toFilePath = "/Users/sunlh/Documents/ideaData/actionsoft/aws6.4.1.1008.yili2/apps/com.actionsoft.apps.coe.pal.datamigration/testFile/targetFile/"; + // XMLUtil.writeXml(d, toFilePath + fileName); // 解析xml文件 - if (d == null) { - return ResponseObject.newErrResponse().toString(); + if (doc == null) { + LogUtil.appendLog(Constant.LOG_ERROR + "解析XML文件结构," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); + return ResponseObject.newErrResponse("解析XML文件错误,详情见日志").toString(); } + LogUtil.appendLog(Constant.LOG_SUCCESS + "解析XML文件结构", simpleLogFile, fullLogFile); ArisXmlHandleWeb handleWeb = new ArisXmlHandleWeb(); - // 解析 - handleWeb.handleXmlDoc(d); - - Map groupMap = handleWeb.groupMap;// 文件夹/组基本信息map记录 - - Map modelMap = handleWeb.modelMap;// 模型基本信息map记录 - - Map objDefMap = handleWeb.objDefMap;// 形状定义map记录 - - Map> modelObjOccMap = handleWeb.modelObjOccMap;// 模型内形状map记录 - - Map objOccMap = handleWeb.objOccMap;// 所有形状 - - Map> cxnOccMap = handleWeb.cxnOccMap;// 形状连线记录 - - Map> objDefLinkerMap = handleWeb.objDefLinkerMap;// 记录所有定义形状的连线map记录 - - Map> methodAttrsMap = new HashMap<>();// 属性存储 - - // 获取所有IT系统图,并查询所有IT系统形状 - Map itShapeMap = new HashMap<>(); - Set ids = new HashSet<>(); - List itModels = new ArrayList<>(); - PALRepositoryCache.getAllChildrenModelsByPid(wsId, "itsystem", itModels, ids); - for (PALRepositoryModel itModel : itModels) { - String definition = PALRepositoryQueryAPIManager.getInstance().getProcessDefinition(null, itModel.getId()); - List list = com.actionsoft.apps.coe.pal.pal.repository.designer.util.ShapeUtil.getShapeJsonToJsonObject(definition); - for (JSONObject shape: list) { - JSONObject obj = new JSONObject(); - obj.put("shapeId", shape.getString("id")); - obj.put("plId", itModel.getId()); - obj.put("shapeName", shape.getString("text")); - itShapeMap.put(shape.getString("text"), obj); - } + // 解析Aris流程内容 + try { + handleWeb.handleXmlDoc(doc); + } catch (Exception e) { + e.printStackTrace(); + LogUtil.appendLog(Constant.LOG_ERROR + "解析XML文件内容异常,异常信息:" + e.getMessage() + "," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); } + LogUtil.appendLog(Constant.LOG_SUCCESS + "解析XML文件内容", simpleLogFile, fullLogFile); - PALRepository coeProcessLevel = CoeProcessLevelDaoFacotory.createCoeProcessLevel(); - - // 存储匹配到与未匹配到的模型信息 - List matchModels = new ArrayList<>(); - List unMatchModels = new ArrayList<>(); - // 存储已经匹配上但是文件里已经有内容【可能导入重复】的模型信息 - List repeatModels = new ArrayList<>(); - // 存储不包含图形的流程,无任何形状的流程不进行导入 - List currentModelNoShape = new ArrayList<>(); - for (Map.Entry entry : modelMap.entrySet()) { - ModelModel arisModel = entry.getValue(); - // 创建角色模型 - List objOccModels = modelObjOccMap.get(arisModel.getId()); - if (objOccModels == null || objOccModels.size() == 0) { - currentModelNoShape.add(arisModel); - printMsg("流程" + arisModel.getName() + arisModel.getId() + "无任何模型,导入忽略"); - continue; - } - // 匹配模型 - PALRepositoryModel palModel = matchPalModel(arisModel, wsId); - if (palModel != null) { - matchModels.add(arisModel); - String plId = palModel.getId(); - // 模型是否可导入 - BaseModel defineModel = CoeDesignerAPIManager.getInstance().getDefinition(plId, 0); - if (defineModel == null) { - defineModel = CoeDesignerUtil.createModel(plId, 0); - defineModel.setCreateHistory(false); - } - String timestamp = new SimpleDateFormat(CoeDesignerConstant.DATE_TIME_STYLE_YYYY_MM_DD_HH_MM_SS).format(new Date()); - defineModel.setUpdateTime(timestamp); - String define = defineModel.getDefinition(); - JSONObject definition = JSONObject.parseObject(define); - JSONObject elements = definition.getJSONObject("elements"); - if (elements != null && !elements.isEmpty()) { - // 导入模型已存在数据,不允许导入 todo - repeatModels.add(arisModel); - printMsg("[" + arisModel.getName() + "] 导入流程模型已存在数据,不允许导入,对同名角色模型进行忽略处理"); - continue; - } - - String rolefolderId = checkAndCreatePalRoleFolderModel(coeProcessLevel, wsId);// 创建/获取角色文件夹ID,作为角色的顶级文件夹 - Map arisFunIdRelationPalRoleMap = new HashMap<>();// aris功能模型与aris角色模型的id映射,key:aris fun shape id,value:pal role id - Map palRoleIdRelationNameMap = new HashMap<>();// key pal role shape id ,value:pal role shape text - // 创建角色模型和角色元素,并且获取aris角色与pal角色映射关系 - String roleMdoelId = createRoleModelAndElements(coeProcessLevel, rolefolderId, wsId, currentModelNoShape, palModel, arisModel, modelObjOccMap, objDefMap, objOccMap, cxnOccMap, objDefLinkerMap, arisFunIdRelationPalRoleMap, methodAttrsMap, palRoleIdRelationNameMap); - - // 存储当前模型下ARIS图形ID与PAL图形ID映射关系 - Map idRelationMap = new HashMap<>(); - - Map palShapeIdRelationArisOccIdMap = new HashMap<>(); - // 创建形状和连线 - JSONObject newElements = createShapeElement(wsId, idRelationMap, palModel, arisModel, modelObjOccMap, objDefMap, objOccMap, cxnOccMap, palShapeIdRelationArisOccIdMap); - - // 处理输入输出活动属性 - this.handleShapeInputOutAttr(palModel, newElements); - - // 处理角色属性与流程相应的活动节点关联 - this.handleProcessAttrRoleRelation(wsId, palModel.getId(), arisFunIdRelationPalRoleMap, palShapeIdRelationArisOccIdMap, newElements, arisModel, modelObjOccMap, objDefMap, roleMdoelId, palRoleIdRelationNameMap); - - // 处理流程关联属性IT系统 - this.handleProcessAttrItSystemRelation(wsId, idRelationMap, palModel.getId(), newElements, arisModel, modelObjOccMap, objDefMap, objDefLinkerMap, itShapeMap); - - this.handleProcessAttrLeadOrRearProcess(wsId, currentModelNoShape, idRelationMap, palModel.getId(), newElements, arisModel, modelObjOccMap, objDefMap); - - // 增加其他默认的属性,值默认为空 by孙连辉 20220626 - this.handleShapeDefaultAttr(wsId, palModel, newElements, methodAttrsMap); - - definition.put("elements", newElements); - // 设置画布大小 - setDiagramHeightWidth(definition, newElements); - defineModel.setDefinition(definition.toString()); - // 保存文件 - CoeDesignerAPIManager.getInstance().storeDefinition(defineModel);// dao操作 - - } else { - unMatchModels.add(arisModel); - } + // 统计epc流程图的个数,用以进度展示 + int totalEpcCount = countProcessMainInfo(handleWeb.modelMap); + if (totalEpcCount == 0) { + LogUtil.appendLog(Constant.LOG_ERROR + "上传文件不包含任何" + I18nRes.findValue(CoEConstant.APP_ID, Constant.PROCESS_EPC) + "," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); + return ResponseObject.newErrResponse("上传文件不包含任何" + I18nRes.findValue(CoEConstant.APP_ID, Constant.PROCESS_EPC)).toString(); } - // System.out.println(wsId); - ro = ResponseObject.newOkResponse("处理完毕"); - ro.put("matchModels", matchModels); - ro.put("unMatchModels", unMatchModels); - ro.put("repeatModels", repeatModels); - ro.put("currentModelNoShape", currentModelNoShape); + // 存储缓存,导入计数 + DataMigrationCache.getCache().put(logId, 0, true); + // 开始执行导入 + new Thread(()->{new ArisXmlImportRun(_uc, wsId, logId, logPath, simpleLogFile, fullLogFile, warnLogFile, filePath, fileName).execute(handleWeb);}) .start(); + + ResponseObject ro = ResponseObject.newOkResponse("处理完毕"); +// ro.put("matchModels", matchModels); +// ro.put("unMatchModels", unMatchModels); +// ro.put("repeatModels", repeatModels); +// ro.put("currentModelNoShape", currentModelNoShape); return ro.toString(); } - + /** + * 统计EPC流程图个数,用以展示进度 + * @param modelMap + */ + private int countProcessMainInfo(Map modelMap) { + int count = 0; + for (Map.Entry entry : modelMap.entrySet()) { + ModelModel model = entry.getValue(); + if ("MT_EEPC".equals(model.getType())) { + count++; + } + } + return count; + } /** - * 创建角色模型和角色元素,并且获取aris角色与pal角色映射关系 - * 角色与流程活动都是以角色为起点连接流程活动 - * 角色与岗位都是以岗位为起点连接角色 - * 活动与角色是1对1关系,不存在单活动对应多个角色 - * @param coeProcessLevel - * @param parentId - * @param wsId - * @param currentModelNoShape - * @param palModel - * @param arisModel - * @param modelObjOccMap - * @param objDefMap - * @param objOccMap - * @param cxnOccMap - * @param objDefLinkerMap - * @param arisFunIdRelationPalRoleMap - * @param methodAttrsMap + * 解析xml文档 + * @param path + * @param b * @return */ - private String createRoleModelAndElements(PALRepository coeProcessLevel, String parentId, String wsId, List currentModelNoShape, PALRepositoryModel palModel, ModelModel arisModel, Map> modelObjOccMap, Map objDefMap, Map objOccMap, Map> cxnOccMap, Map> objDefLinkerMap, Map arisFunIdRelationPalRoleMap, Map> methodAttrsMap, Map palRoleIdRelationNameMap) { - // 统计模型内的角色信息,创建角色与形状的关联关系,提前创建活动与角色的id关联关系,建立角色的角色图,角色图中处理岗位为文本属性内容 - - // 统计模型内所有的角色形状 - List objOccModels = modelObjOccMap.get(arisModel.getId()); - // 获取角色 - List roleObjOccModels = new ArrayList<>(); - for (ObjOccModel objOccModel : objOccModels) { - ObjDefModel objDefModel = objDefMap.get(objOccModel.getDefId()); - if (objDefModel.getTypeNum().equals("OT_PERS_TYPE") && objDefModel.getSymbolNum().equals("ST_EMPL_TYPE")) {// 角色 - roleObjOccModels.add(objOccModel); - } - } - if (roleObjOccModels.size() == 0) { - printMsg("流程模型" + palModel.getName() + "无任何角色模型,忽略角色与岗位导入"); - return null; + private Document analysisXMLFile(String path, boolean b) { + Document d = null; + try { + d = XMLUtil.readXML(path, true); + } catch (DocumentException e) { + e.printStackTrace(); + LogUtil.appendLog(Constant.LOG_ERROR + "解析XML文件结构出错,错误信息:" + e.getMessage() + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); + } catch (FileNotFoundException e) { + e.printStackTrace(); + LogUtil.appendLog(Constant.LOG_ERROR + "解析XML文件结构出错,错误信息:" + e.getMessage() + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); } + return d; + } - Set noneRelationRole = new HashSet<>(); - - // 创建角色与形状关联关系 - // 获取当前aris模型内的所有角色list - List roleCxnOccModels = new ArrayList<>(); - for (ObjOccModel roleOccModel : roleObjOccModels) { - List list = cxnOccMap.get(roleOccModel.getId()); - // list为null,该角色在该模型中没有连接任何的活动,忽略导入该角色 - if (list == null) { - printMsg("流程模型" + palModel.getName() + "检测到角色" + objDefMap.get(roleOccModel.getDefId()).getName() + "尚未连接到任何活动上,忽略该角色"); - noneRelationRole.add(objDefMap.get(roleOccModel.getDefId()).getName()); - continue; - } - for (CxnOccModel cxnOccModel : list) { - if (cxnOccModel.getModelId().equals(arisModel.getId())) { - roleCxnOccModels.add(cxnOccModel); - } - } + /** + * 校验文件/形状属性是否存在 + * @param wsId + * @return + */ + private ResponseObject checkMethodConfig(String wsId) { + // 校验EPC图的文件属性 + // 校验前置流程、后置流程 + ResponseObject checkRo = checkMethodAttrExist(wsId, Constant.PROCESS_EPC, null, Constant.METHOD_PRE_PROCESS, Constant.METHOD_NEXT_PROCESS); + if (checkRo.isErr()) { + return checkRo; } - if (roleCxnOccModels.size() == 0) { - printMsg("流程模型" + palModel.getName() + "无任何角色模型与流程活动进行连接,忽略角色与岗位导入"); - return null; + // 校验epc流程图的形状属性是否配置 + // 校验线上审批的编号、输入、输出、描述、角色、信息系统 + checkRo = checkMethodAttrExist(wsId, Constant.PROCESS_EPC, Constant.METHOD_APPROVAL_NODE, Constant.METHOD_NUMBER, Constant.METHOD_INPUT, Constant.METHOD_OUTPUT, Constant.METHOD_DESC, Constant.METHOD_ROLE, Constant.METHOD_INFO_SYSTEM); + if (checkRo.isErr()) { + return checkRo; } - - // 记录重复的角色,根据名称进行记录 - Map> repeatRoleMap = new HashMap<>(); - // 记录aris功能活动与角色的关系 - Map arisFunRelationRoleMap = new HashMap<>(); - // 记录重复的角色名称 - for (CxnOccModel cxnOccModel: roleCxnOccModels) { - ObjOccModel occModel = objOccMap.get(cxnOccModel.getId()); - ObjDefModel objDefModel = objDefMap.get(occModel.getDefId()); - arisFunRelationRoleMap.put(cxnOccModel.getToId(), objDefModel.getName()); - String roleName = objDefModel.getName(); - if (!repeatRoleMap.containsKey(roleName)) { - repeatRoleMap.put(roleName, new HashSet<>()); - } - repeatRoleMap.get(roleName).add(occModel.getId()); + // 校验线下审批的编号、输入、输出、描述、角色、信息系统 + checkRo = checkMethodAttrExist(wsId, Constant.PROCESS_EPC, Constant.METHOD_SERVICE_NODE, Constant.METHOD_NUMBER, Constant.METHOD_INPUT, Constant.METHOD_OUTPUT, Constant.METHOD_DESC, Constant.METHOD_ROLE, Constant.METHOD_INFO_SYSTEM); + if (checkRo.isErr()) { + return checkRo; } - // 没有关联活动的角色,也加入到角色图中 - for (String roleName : noneRelationRole) { - if (!repeatRoleMap.containsKey(roleName)) { - repeatRoleMap.put(roleName, new HashSet<>()); - } + LogUtil.appendLog(Constant.LOG_SUCCESS + "【EPC流程图】形状【线下审批】的属性【编号】【输入】【输出】【描述】【角色】【信息系统】", simpleLogFile, fullLogFile); + // 校验系统任务的编号、输入、输出、描述、角色、信息系统 + checkRo = checkMethodAttrExist(wsId, Constant.PROCESS_EPC, Constant.METHOD_APPROVAL_NODE3, Constant.METHOD_NUMBER, Constant.METHOD_INPUT, Constant.METHOD_OUTPUT, Constant.METHOD_DESC, Constant.METHOD_ROLE, Constant.METHOD_INFO_SYSTEM); + if (checkRo.isErr()) { + return checkRo; } - - // 创建角色图的名称与PAL角色图形状ID对应关系 - Map roleNamePalIdMap = new HashMap<>(); - for (String roleName : repeatRoleMap.keySet()) { - String roleShapeId = UUIDGener.getObjectId(); - roleNamePalIdMap.put(roleName, roleShapeId); - palRoleIdRelationNameMap.put(roleShapeId, roleName); + LogUtil.appendLog(Constant.LOG_SUCCESS + "【EPC流程图】形状【系统任务】的属性【编号】【输入】【输出】【描述】【角色】【信息系统】", simpleLogFile, fullLogFile); + // 校验人工任务的编号、输入、输出、描述、角色、信息系统 + checkRo = checkMethodAttrExist(wsId, Constant.PROCESS_EPC, Constant.METHOD_SERVICE_NODE4, Constant.METHOD_NUMBER, Constant.METHOD_INPUT, Constant.METHOD_OUTPUT, Constant.METHOD_DESC, Constant.METHOD_ROLE, Constant.METHOD_INFO_SYSTEM); + if (checkRo.isErr()) { + return checkRo; } - // 记录Aris功能Occ ID与PALroleId关联关系 - for (Map.Entry entry : arisFunRelationRoleMap.entrySet()) { - if (roleNamePalIdMap.containsKey(entry.getValue())) { - arisFunIdRelationPalRoleMap.put(entry.getKey(), roleNamePalIdMap.get(entry.getValue())); - } + LogUtil.appendLog(Constant.LOG_SUCCESS + "【EPC流程图】形状【人工任务】的属性【编号】【输入】【输出】【描述】【角色】【信息系统】", simpleLogFile, fullLogFile); + // 校验角色图的岗位属性 + // 校验角色的岗位文本 + checkRo = checkMethodAttrExist(wsId, Constant.ORG_ROLE, Constant.METHOD_ROLE, Constant.METHOD_POST_TEXT); + if (checkRo.isErr()) { + return checkRo; } + return ResponseObject.newOkResponse(); + } - // 角色名称与岗位名称合集 - Map> roleRelationPositonMap = new HashMap<>(); - // 查找角色对应的岗位 - for (ObjOccModel roleOccModel : roleObjOccModels) { - ObjDefModel roleObjDefModel = objDefMap.get(roleOccModel.getDefId()); - String linkedModelIds = roleObjDefModel.getLinkedModelIds(); - if (UtilString.isEmpty(linkedModelIds)) {// 角色无关联角色图 - printMsg("流程模型" + palModel.getName() + roleObjDefModel.getName() + "角色无任何关联岗位,忽略该角色岗位"); - } else {// 角色有关联角色图 - List relationPositonList = modelObjOccMap.get(linkedModelIds);// linkedModelIds按照单个值对待,暂无发现多值 - if (relationPositonList == null || relationPositonList.size() == 0) {// 角色有关联图但是关联的角色图查询不到 - printMsg("流程模型" + palModel.getName() + roleObjDefModel.getName() + "角色存在关联LinkedModels.IdRefs:" + linkedModelIds + " 但无法查询对应Model内容"); - } else { - for (ObjOccModel objOccModel: relationPositonList) { - ObjDefModel positionDefModel = objDefMap.get(objOccModel.getDefId()); - if (positionDefModel.getTypeNum().equals("OT_POS") && positionDefModel.getSymbolNum().equals("ST_POS")) { - // 查询出岗位,记录到角色中,角色名称为key,岗位名称为value - if (!roleRelationPositonMap.containsKey(roleObjDefModel.getName())) { - roleRelationPositonMap.put(roleObjDefModel.getName(), new HashSet<>()); - } - roleRelationPositonMap.get(roleObjDefModel.getName()).add(positionDefModel.getName()); - } - } - } - } - } - - // 生成一个空的与流程同名角色模型文件 - String id = UUIDGener.getUUID(); - int orderIndex = coeProcessLevel.getChildrenMaxOrderIndexByPidAndWsId(parentId, wsId) + 1; - Timestamp nowTime = new Timestamp(System.currentTimeMillis()); - - PALRepositoryModelImpl model = CoeProcessLevelUtil.createPALRepositoryModel(id, UUIDGener.getUUID(), wsId, arisModel.getName(), "", orderIndex, parentId, "org", true, 1, - id, false, "org.role", "0", 1, null, null, _uc.getUID(), _uc.getUID(), nowTime, null, null, null, null, - null, null, null, null, null, -1); - coeProcessLevel.insert(model); - printMsg("与流程同名的角色空模型创建完成【文件ID】" + model.getId()); - BaseModel baseModel = CoeDesignerAPIManager.getInstance().getDefinition(model.getId(), 0); - if (baseModel == null) { - baseModel = CoeDesignerUtil.createModel(model.getId(), 0); - baseModel.setCreateHistory(false); - } - baseModel.setUpdateTime(new SimpleDateFormat(CoeDesignerConstant.DATE_TIME_STYLE_YYYY_MM_DD_HH_MM_SS).format(new Date())); - String define = baseModel.getDefinition(); - JSONObject definition = JSONObject.parseObject(define); - JSONObject elements = definition.getJSONObject("elements"); - Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); - ObjDefMappingModel objDefMappingModel = objDefMappingMap.get("OT_PERS_TYPE-ST_EMPL_TYPE"); - String shapeMethodId = objDefMappingModel.getShapeMethod(); - String shapeType = objDefMappingModel.getShapeType(); - JSONObject shapeDefine = ShapeUtil.getProcessShapeDefinitionByName(shapeMethodId, shapeType); - - JSONArray shapes = new JSONArray(); - for (Map.Entry entry: roleNamePalIdMap.entrySet()) { - String shapeText = entry.getKey(); - String shapeId = entry.getValue(); - JSONObject newShape = JSONObject.parseObject(shapeDefine.toString()); - newShape.put("id", shapeId); - newShape.put("text", shapeText); - shapes.add(newShape); - } - - JSONArray newShapes = this.getMethodElementsJSONArray(shapes, 6); - for (int i = 0; i < newShapes.size(); i++) { - JSONObject shapeObj = newShapes.getJSONObject(i); - elements.put(shapeObj.getString("id"), shapeObj); - printMsg("生成角色图 角色【" + shapeObj.getString("text") + "】"); - } - - // 设置角色图形状默认属性配置 - this.handleShapeDefaultAttr(wsId, palModel, elements, methodAttrsMap); - - // 完善岗位属性 - for (String key : elements.keySet()) { - JSONObject shape = elements.getJSONObject(key); - if ("linker".equals(shape.getString("name"))) { - continue; + /** + * 校验属性是否存在 + * @param methodId + * @param shapeName + * @param attrs + * @return + */ + private ResponseObject checkMethodAttrExist(String wsId, String methodId, String shapeName, String ... attrs) { + String methodName = I18nRes.findValue(CoEConstant.APP_ID, methodId); + // 形状属性校验 + if (UtilString.isNotEmpty(shapeName)) { + JSONObject shape = ShapeUtil.getProcessShapeDefinitionByName(methodId, shapeName); + if (isEmptyJsonOject(shape)) { + LogUtil.appendLog(Constant.LOG_ERROR + "模型【" + methodName + "】中的形状【" + shapeName + "】不存在," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); + return ResponseObject.newErrResponse("模型【" + methodName + "】中的形状【" + shapeName + "】不存在"); } String shapeText = shape.getString("text"); - if (roleRelationPositonMap.containsKey(shapeText) && roleRelationPositonMap.get(shapeText).size() > 0) { - Set postText = roleRelationPositonMap.get(shapeText); - List list = new ArrayList<>(postText); - Collections.sort(list); - String postTextVal = StringUtils.join(list, ",");// 岗位内容 - JSONArray dataAttributes = shape.getJSONArray("dataAttributes"); - if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { - for (Object attribute : dataAttributes) { - JSONObject obj = (JSONObject) attribute; - if (obj.containsKey("attributesJsonArray")) { - JSONArray attributesJsonArray = obj.getJSONArray("attributesJsonArray"); - boolean flag = false; - for (int i = 0; i < attributesJsonArray.size(); i++) { - if (attributesJsonArray.getJSONObject(i).containsKey("id")) { - String attrId = Constant.METHOD_POST_TEXT; - if (attrId.equals(attributesJsonArray.getJSONObject(i).getString("id"))) { - flag = true; - attributesJsonArray.getJSONObject(i).put("value", postTextVal); - printMsg("角色图" + model.getName() + "角色" + shapeText + "岗位属性值为" + postTextVal); - } - } - } - if (!flag) { - printMsg("角色图" + model.getName() + "角色" + shapeText + "没有岗位属性配置" + Constant.METHOD_POST_TEXT); - } - } - } - } - } else { - printMsg("角色图" + model.getName() + "角色" + shapeText + "无岗位属性内容值"); + List list = CoeDesignerShapeAPIManager.getInstance().getValidAndUseAttributeModels(wsId, methodId, shapeName, methodId); + Map attrMap = new HashMap<>(); + for (PALMethodAttributeModel attrModel : list) { + attrMap.put(attrModel.getKey(), attrModel); + } + for (String attrId : attrs) { + if (!attrMap.containsKey(attrId)) { + LogUtil.appendLog(Constant.LOG_ERROR + "模型【" + methodName + "】中的形状【" + shapeText + "】属性【" + attrId + "】不存在,请检查相应属性配置," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); + return ResponseObject.newErrResponse("模型【" + methodName + "】中的形状【" + shapeName + "】属性【" + attrId + "】不存在"); + } + LogUtil.appendLog(Constant.LOG_SUCCESS + "模型【" + methodName + "】中的形状【" + shapeText + "】属性【" + attrId + "】", simpleLogFile, fullLogFile); } - } - definition.put("elements", elements); - // 设置画布大小 - setDiagramHeightWidth(definition, elements); - baseModel.setDefinition(definition.toString()); - // 保存文件 - CoeDesignerAPIManager.getInstance().storeDefinition(baseModel);// dao操作 - return id; - } - - /** - * 校验和创建角色模型文件夹 - * @param coeProcessLevel - * @param wsId - * @return 已经存在的或新创建的角色模型ID - */ - private String checkAndCreatePalRoleFolderModel(PALRepository coeProcessLevel, String wsId) { - // 组织下创建【角色模型】文件夹 - List defaultModels = PALRepositoryQueryAPIManager.getInstance().getPalRepositoryModelsByWsIdAndMethodId(wsId, "org"); - defaultModels = defaultModels.stream() - .filter(model -> "default".equals(model.getMethodId())) - .filter(model -> Constant.DEFAULT_FOLDER_NAME.equals(model.getName())).collect(Collectors.toList()); - if (defaultModels.size() == 0) { - String id = UUIDGener.getUUID(); - - int orderIndex = coeProcessLevel.getChildrenMaxOrderIndexByPidAndWsId("org", wsId) + 1; - Timestamp nowTime = new Timestamp(System.currentTimeMillis()); - PALRepositoryModelImpl defaultModel = CoeProcessLevelUtil.createPALRepositoryModel(id, UUIDGener.getUUID(), wsId, Constant.DEFAULT_FOLDER_NAME, "", orderIndex, "org", "org", true, 1, - id, false, "default", "0", 1, null, null, _uc.getUID(), _uc.getUID(), nowTime, null, null, null, null, - null, null, null, null, null, -1); - coeProcessLevel.insert(defaultModel); - defaultModels.add(defaultModel); - printMsg("角色模型文件夹创建成功 " + defaultModel.getId()); - return defaultModel.getId(); } else { - printMsg("角色模型文件夹已存在,不再重复创建"); - return defaultModels.get(0).getId(); - } - } - - /** - * 自定义属性 - * @param wsId - * @param palModel - * @param elements - * @param methodAttrsMap - */ - private void handleShapeDefaultAttr(String wsId, PALRepositoryModel palModel, JSONObject elements, Map> methodAttrsMap) { - for (String key : elements.keySet()) { - JSONObject shape = elements.getJSONObject(key); - if ("linker".equals(shape.getString("name"))) { - continue; + // 文件属性校验 + List list = PALRepositoryAPIManager.getInstance().getValidAndUseAttributeModels(wsId, methodId); + Map attrMap = new HashMap<>(); + for (PALMethodAttributeModel attrModel : list) { + attrMap.put(attrModel.getKey(), attrModel); } - String shapeMehtodId = shape.getString("category").replace("_", "."); - String shapeName = shape.getString("name"); - - if (methodAttrsMap.containsKey(palModel.getMethodId()) && methodAttrsMap.containsKey(shapeName)) { - } else { - if (!methodAttrsMap.containsKey(palModel.getMethodId())) { - methodAttrsMap.put(palModel.getMethodId(), new HashMap<>()); - } - JSONObject attrs = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), shapeMehtodId, palModel.getMethodId(), shapeName); - if (attrs != null) { - methodAttrsMap.get(palModel.getMethodId()).put(shapeName, attrs); - } - } - JSONObject attrs = methodAttrsMap.get(palModel.getMethodId()).get(shapeName);// 最终属性内容 - attrs = JSONObject.parseObject(attrs.toString());// 复制 - JSONArray dataAttributes = shape.getJSONArray("dataAttributes"); - if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { - for (Object attribute : dataAttributes) { - JSONObject obj = (JSONObject) attribute; - if (obj.containsKey("attributesJsonArray")) { - JSONArray attributesJsonArray = obj.getJSONArray("attributesJsonArray"); - Set attrIds = new HashSet<>(); - for (int i = 0; i < attributesJsonArray.size(); i++) { - if (attributesJsonArray.getJSONObject(i).containsKey("id")) { - attrIds.add(attributesJsonArray.getJSONObject(i).getString("id")); - } - } - for (String attrId : attrs.keySet()) { - if (!attrIds.contains(attrId)) { - JSONObject eleAttrObj = getDefaultAttrObj(attrs.getJSONObject(attrId)); - attributesJsonArray.add(eleAttrObj); - } - } - } + for (String attrId : attrs) { + if (!attrMap.containsKey(attrId)) { + LogUtil.appendLog(Constant.LOG_ERROR + "模型【" + methodName + "】的文件属性【" + attrId + "】不存在,请检查相应属性配置," + Constant.IMPORT_STOP_MSG, simpleLogFile, fullLogFile, warnLogFile); + return ResponseObject.newErrResponse("模型【" + methodName + "】的文件属性【" + attrId + "】不存在"); } + LogUtil.appendLog(Constant.LOG_SUCCESS + "模型【" + methodName + "】的文件属性【" + attrId + "】", simpleLogFile, fullLogFile); } } + return ResponseObject.newOkResponse(); } - /** - * 获取默认属性内容 - * @param attr - * @return - */ - private JSONObject getDefaultAttrObj (JSONObject attr) { - String ref = attr.getString("ref"); - boolean readonly = attr.getBooleanValue("readonly"); - String scope = attr.getString("scope"); - String attrName = attr.getString("title"); - String attrId = attr.getString("id"); - String type = attr.getString("type"); - String groupPath = attr.getString("groupPath"); - String attrKey = attr.getString("key"); - String attrValue = ""; - JSONObject object2 = new JSONObject(); - object2.put("ref", ref); - object2.put("readonly", readonly); - object2.put("scope", scope); - object2.put("name", attrName); - object2.put("id", attrId); - object2.put("type", type); - object2.put("groupPath", groupPath); - object2.put("key", attrKey); - object2.put("value", ""); - return object2; - } + + /** * 校验一些必备的建模属性 @@ -612,826 +371,23 @@ public class ArisXmlImportWeb extends ActionWeb { return ""; } + + + + + /** - * Aris模型匹配PAL模型 - * - * @param arisModel + * 校验是否为空的对象 + * @param o * @return */ - private PALRepositoryModel matchPalModel(ModelModel arisModel, String wsId) { - // 查询当前资产库中建模类型是EPC的所有流程文件属性 - PALRepositoryPropertyDao dao = new PALRepositoryPropertyDao(); - List propertyModels = dao.queryByWsId(wsId); - propertyModels = propertyModels.stream().filter(item -> Constant.METHOD_ARIS_URL.equals(item.getPropertyId())).collect(Collectors.toList()); - String modelPath = "\\伊利集团业务流程管理平台" + arisModel.getModelPath(); - boolean flag = false; - PALRepositoryModel repositoryModel = null; - // printMsg("MODEL PATH "+modelPath); - for (PALRepositoryPropertyModel propertyModel : propertyModels) { - if (propertyModel.getPropertyValue().equals(modelPath)) { - // printMsg("ARIS路径 "+propertyModel.getPropertyValue()); - repositoryModel = new PALRepository().getInstance(propertyModel.getPlId()); - if (arisModel.getName().trim().equals(repositoryModel.getName())) { - printMsg("匹配到的MODEL PATH " + modelPath + "\\" + arisModel.getName()); - flag = true; - break; - } else { - repositoryModel = null; - } - } - } - if (!flag) { - // 未匹配出结果,记录日志 todo - printMsg("未匹配出结果MODEL PATH " + modelPath + "\\" + arisModel.getName()); - } - return repositoryModel; - } - - /** - * 创建PAL形状 - * - * @param palModel - * @param arisModel - * @param modelObjOccMap - * @param objDefMap - * @return - */ - private JSONObject createShapeElement(String wsId, Map idRelationMap, PALRepositoryModel palModel, ModelModel arisModel, Map> modelObjOccMap, Map objDefMap, Map objOccMap, Map> cxnOccMap, Map palShapeIdRelationArisOccIdMap) { - // aris中该模型所有形状 - List objOccModels = modelObjOccMap.get(arisModel.getId()); - int zindex = 1; - JSONObject elements = new JSONObject(); - Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); - for (ObjOccModel objOccModel : objOccModels) { - ObjDefModel objDefModel = objDefMap.get(objOccModel.getDefId());// 形状定义 - if (objDefMappingMap.containsKey(objDefModel.getTypeNum() + "-" + objOccModel.getSymbolNum())) { - ObjDefMappingModel objDefMappingModel = objDefMappingMap.get(objDefModel.getTypeNum() + "-" + objOccModel.getSymbolNum());// Aris与PAL形状映射关系 - String shapeMethodId = objDefMappingModel.getShapeMethod(); - String shapeType = objDefMappingModel.getShapeType(); - // 伊利导入形状定制 - String symbolNum = objDefMappingModel.getSymbolNum(); - String typeNum = objDefMappingModel.getTypeNum(); - String arisShapeName = objDefMap.get(objOccModel.getDefId()).getName(); - String method = shapeMethodId; - String shapeName = shapeType; - // fun -// if ("OT_FUNC".equals(symbolNum) && "ST_FUNC".equals(typeNum)) { - if ("ST_FUNC".equals(symbolNum) && "OT_FUNC".equals(typeNum)) { - if (arisShapeName.contains("审批") || arisShapeName.contains("审核")) { - shapeName = "method_service_node"; - } else { - shapeName = "method_service_node4"; - } -// } else if ("OT_FUNC".equals(symbolNum) && "ST_SYS_FUNC_ACT".equals(typeNum)) {// sys_fun - } else if ("ST_SYS_FUNC_ACT".equals(symbolNum) && "OT_FUNC".equals(typeNum)) {// sys_fun - if (arisShapeName.contains("审批") || arisShapeName.contains("审核")) { - shapeName = "method_approval_node"; - } else { - shapeName = "method_approval_node3"; - } - } - - JSONObject shape = ShapeUtil.getProcessShapeDefinitionByName(shapeMethodId, shapeName); - String shapeId = UUIDGener.getObjectId(); - palShapeIdRelationArisOccIdMap.put(shapeId, objOccModel.getId()); - idRelationMap.put(objOccModel.getId(), shapeId);// 记录形状aris形状id与pal形状id - shape.put("id", shapeId); - // 处理当前图形节点的关联属性【编号】问题 - if (objDefModel.getAttrData().containsKey("AT_PROC_CODE")) { - List attributeModels = CoeDesignerShapeAPIManager.getInstance().getValidAttributeModels(wsId, objDefMappingModel.getShapeMethod(), shapeName, objDefMappingModel.getShapeMethod()); - attributeModels = attributeModels.stream().filter(item -> Constant.METHOD_NUMBER.equals(item.getKey())).collect(Collectors.toList()); - if (attributeModels.size() == 0) { - throw new AWSException("请打开建模管理应用,查看当前【过程链】建模分类下是否存在【编号/" + Constant.METHOD_NUMBER + "】建模属性"); - } - PALMethodAttributeModel attributeModel = attributeModels.get(0); - JSONObject attrNumberObj = new JSONObject(); - attrNumberObj.put("value", objDefModel.getAttrData().getString("AT_PROC_CODE")); - attrNumberObj.put("key", attributeModel.getKey()); - attrNumberObj.put("isRequired", attributeModel.getIsRequired()); - attrNumberObj.put("ref", attributeModel.getRef()); - attrNumberObj.put("readonly", attributeModel.getReadonly()); - attrNumberObj.put("scope", attributeModel.getScope()); - attrNumberObj.put("name", attributeModel.getTitle()); - attrNumberObj.put("id", attributeModel.getKey()); - attrNumberObj.put("textarea", attributeModel.getType()); - attrNumberObj.put("groupPath", attributeModel.getGroupPath()); - attrNumberObj.put("desc", attributeModel.getDesc()); - - JSONArray dataAttributes = shape.getJSONArray("dataAttributes"); - if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { - for (Object attribute : dataAttributes) { - JSONObject obj = (JSONObject) attribute; - if (obj.containsKey("attributesJsonArray")) { - obj.getJSONArray("attributesJsonArray").add(attrNumberObj); - break; - } - } - } - } - - -// 处理活动节点描述 --by shang - if (objDefModel.getAttrData().containsKey("AT_DESC")) { - List attributeModels = CoeDesignerShapeAPIManager.getInstance().getValidAttributeModels(wsId, objDefMappingModel.getShapeMethod(), "process", objDefMappingModel.getShapeMethod()); - attributeModels = attributeModels.stream().filter(item -> Constant.METHOD_DESC.equals(item.getKey())).collect(Collectors.toList()); - if (attributeModels.size() == 0) { - throw new AWSException("请打开建模管理应用,查看当前【过程链】建模分类下是否存在【活动描述/" + Constant.METHOD_DESC + "】建模属性"); - } - PALMethodAttributeModel attributeModel = attributeModels.get(0); - JSONObject attrDescObj = new JSONObject(); - attrDescObj.put("value", objDefModel.getAttrData().getString("AT_DESC")); - attrDescObj.put("key", attributeModel.getKey()); - attrDescObj.put("isRequired", attributeModel.getIsRequired()); - attrDescObj.put("ref", attributeModel.getRef()); - attrDescObj.put("readonly", attributeModel.getReadonly()); - attrDescObj.put("scope", attributeModel.getScope()); - attrDescObj.put("name", attributeModel.getTitle()); - attrDescObj.put("id", attributeModel.getKey()); - attrDescObj.put("textarea", attributeModel.getType()); - attrDescObj.put("groupPath", attributeModel.getGroupPath()); - attrDescObj.put("desc", attributeModel.getDesc()); - - JSONArray dataAttributes = shape.getJSONArray("dataAttributes"); - if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { - for (Object attribute : dataAttributes) { - JSONObject obj = (JSONObject) attribute; - if (obj.containsKey("attributesJsonArray")) { - - // 处理图形上默认勾选的属性,没有值的属性置空 --by shang -// List allValidAndUseShapeAttributeModels = CoeDesignerShapeAPIManager.getInstance().getAllValidAndUseShapeAttributeModels(wsId, objDefMappingModel.getShapeMethod()); - List usedAttributeModels = CoeDesignerShapeAPIManager.getInstance().getValidAndUseAttributeModels(wsId, objDefMappingModel.getShapeMethod(), shapeName, objDefMappingModel.getShapeMethod()); - usedAttributeModels.forEach(item -> { - attrDescObj.put("id", item.getKey()); - attrDescObj.put("value",""); - }); - obj.getJSONArray("attributesJsonArray").add(attrDescObj); - - break; - } - } - } - } - - - // 定义位置、大小 - if (shape == null) { - // pal形状不存在,记录日志 todo - printMsg("pal没有对应形状定义"); - continue; - } - if (shape.containsKey("attribute") && shape.getJSONObject("attribute").containsKey("editable") && !shape.getJSONObject("attribute").getBooleanValue("editable")) {// 不可编辑名称 - - } else {// 重命名名称 - String name = objDefMap.get(objOccModel.getDefId()).getName();// 形状名称 - shape.put("text", name); - } - - JSONObject props = shape.getJSONObject("props");// 位置大小 - props.put("zindex", zindex++); - props.put("x", objOccModel.getX()); - props.put("y", objOccModel.getY()); - props.put("w", objOccModel.getW()); - props.put("h", objOccModel.getH()); - elements.put(shapeId, shape); - } else { - // pal缺少对应的形状 - printMsg("pal缺少对应的形状:" + objDefModel.getName()); - System.out.println(objDefModel.getTypeNum() + "-" + objDefModel.getSymbolNum()); - System.out.println(objDefMappingMap.containsKey(objDefModel.getTypeNum() + "-" + objDefModel.getSymbolNum())); - } - } - // 形状连线处理 - for (ObjOccModel occ : objOccModels) { - if (cxnOccMap.containsKey(occ.getId())) { - List cxnOccModels = cxnOccMap.get(occ.getId()); - for (CxnOccModel cxn : cxnOccModels) { - if (idRelationMap.containsKey(cxn.getId()) && idRelationMap.containsKey(cxn.getToId())) { - List positionModels = cxn.getPositionList(); - JSONObject linkerObj = ModelMappingAPIManager.getInstance().getLinkerDef(); - String linkerId = UUIDGener.getObjectId(); - linkerObj.put("id", linkerId); - JSONObject props = linkerObj.getJSONObject("props"); - props.put("zindex", zindex++);// 层次 - linkerObj.put("props", props); - linkerObj.put("points", getLinkerPoints(positionModels)); - JSONObject from = linkerObj.getJSONObject("from"); - from.put("id", idRelationMap.get(cxn.getId())); - from.put("angle", getLinkerAngle(positionModels, "from")); - from.put("x", positionModels.get(0).getX()); - from.put("y", positionModels.get(0).getY()); - linkerObj.put("from", from); - JSONObject to = linkerObj.getJSONObject("to"); - to.put("id", idRelationMap.get(cxn.getToId())); - to.put("angle", getLinkerAngle(positionModels, "to")); - to.put("x", positionModels.get(positionModels.size() - 1).getX()); - to.put("y", positionModels.get(positionModels.size() - 1).getY()); - linkerObj.put("to", to); - elements.put(linkerId, linkerObj); - } else { - // 不包含的连线 - } - } - } - } - return elements; - } - - /** - * 在现有输出的图形结构上转化输入 输出活动属性,并将图上输入输出及连线删除 - */ - private void handleShapeInputOutAttr(PALRepositoryModel palModel, JSONObject elements) { - // 存放待删除图形的KEY - List removeKey = new ArrayList<>(); - - Map> nextShapeMap = new HashMap<>();// 记录当前形状的下一个(多个)形状 - Map> prevShapeMap = new HashMap<>();// 记录当前形状的上一个(多个)形状 - for (String key : elements.keySet()) { - JSONObject shapeObj = elements.getJSONObject(key); - if ("linker".equals(shapeObj.getString("name"))) { - // 输入 - String shapeId = shapeObj.getString("id"); - // 查找入线 - String fromId = shapeObj.getJSONObject("from").getString("id"); - String toId = shapeObj.getJSONObject("to").getString("id"); - // 记录from->to Map - if (!nextShapeMap.containsKey(fromId)) { - nextShapeMap.put(fromId, new HashSet<>()); - } - nextShapeMap.get(fromId).add(toId); - - if (!prevShapeMap.containsKey(toId)) { - prevShapeMap.put(toId, new HashSet<>()); - } - prevShapeMap.get(toId).add(fromId); - } - } - - Map> shapeInputMap = new HashMap<>();// 记录形状的所有输出 - Map> shapeOutMap = new HashMap<>();// 记录形状的所有输入 - for (String key : elements.keySet()) { - JSONObject shapeObj = elements.getJSONObject(key); - if (!"linker".equals(shapeObj.getString("name"))) { - // 输入 - String shapeId = shapeObj.getString("id"); - // 查找入线(输入) - if (prevShapeMap.containsKey(shapeId)) { - for (Map.Entry> entry : prevShapeMap.entrySet()) { - if (key.equals(entry.getKey())) { - Set prevShapeIds = entry.getValue(); - for (String prevShapeId : prevShapeIds) { - JSONObject prevShape = elements.getJSONObject(prevShapeId); - if ("document".equals(prevShape.getString("name"))) { - if (!shapeInputMap.containsKey(shapeId)) { - shapeInputMap.put(shapeId, new HashSet<>()); - } - shapeInputMap.get(shapeId).add(prevShape.getString("text")); - } - } - } - } - } - // 查找出线 - if (nextShapeMap.containsKey(shapeId)) { - for (Map.Entry> entry : nextShapeMap.entrySet()) { - if (key.equals(entry.getKey())) { - Set nextShapeIds = entry.getValue(); - for (String nextShapeId : nextShapeIds) { - JSONObject nextShape = elements.getJSONObject(nextShapeId); - if ("document".equals(nextShape.getString("name"))) { - if (!shapeOutMap.containsKey(shapeId)) { - shapeOutMap.put(shapeId, new HashSet<>()); - } - shapeOutMap.get(shapeId).add(nextShape.getString("text")); - } - } - } - } - } - } - } - - - for (String key : elements.keySet()) { - JSONObject shapeObj = elements.getJSONObject(key); - if ("linker".equals(shapeObj.getString("name"))) { - JSONObject from = elements.getJSONObject(shapeObj.getJSONObject("from").getString("id")); - if ("document".equals(from.getString("name"))) { - removeKey.add(key); - removeKey.add(from.getString("id")); - } - JSONObject to = elements.getJSONObject(shapeObj.getJSONObject("to").getString("id")); - if ("document".equals(to.getString("name"))) { - removeKey.add(key); - removeKey.add(to.getString("id")); - } - } - } - // 删除画布上的输入输出和其连线 - removeKey.stream().forEach(key -> elements.remove(key)); - - Map attrMap = new HashMap<>(); - JSONObject attrs1 = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), palModel.getMethodId(), palModel.getMethodId(), "method_service_node"); - attrMap.put("method_service_node", attrs1); - JSONObject attrs2 = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), palModel.getMethodId(), palModel.getMethodId(), "method_service_node4"); - attrMap.put("method_service_node4", attrs2); - JSONObject attrs3 = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), palModel.getMethodId(), palModel.getMethodId(), "method_approval_node"); - attrMap.put("method_approval_node", attrs3); - JSONObject attrs4 = ShapeUtil.getProcessUseShapeMethodAttrByShapeName(palModel.getWsId(), palModel.getMethodId(), palModel.getMethodId(), "method_approval_node3"); - attrMap.put("method_approval_node3", attrs4); - - for (String key : elements.keySet()) { - JSONObject shapeObj = elements.getJSONObject(key); - if (!"linker".equals(shapeObj.getString("name"))) { - if (attrMap.containsKey(shapeObj.getString("name"))) { - JSONObject attrs = attrMap.get(shapeObj.getString("name")); - if (shapeInputMap.containsKey(key)) {// 有输入属性 - // 输入属性 - if (attrs != null && attrs.size() > 0 && attrs.containsKey(Constant.METHOD_INPUT)) { - JSONObject attrObj = JSONObject.parseObject(attrs.getJSONObject(Constant.METHOD_INPUT).toString()); - List contentList = new ArrayList<>(shapeInputMap.get(key)); - Collections.sort(contentList); - attrObj.put("value", StringUtils.join(contentList, ",")); - JSONArray dataAttributes = shapeObj.getJSONArray("dataAttributes"); - if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { - for (Object attribute : dataAttributes) { - JSONObject obj = (JSONObject) attribute; - if (obj.containsKey("attributesJsonArray")) { - JSONArray attributesJsonArray = obj.getJSONArray("attributesJsonArray"); - attributesJsonArray.add(attrObj); - printMsg("流程" + palModel.getName() + "的节点" + shapeObj.getString("text") + "输入属性内容" + attrObj.getString("value")); - } - } - } - } else { - printMsg("流程" + palModel.getName() + "的节点" + shapeObj.getString("text") + "没有配置输入属性"); - } - } - if (shapeOutMap.containsKey(key)) {// 有输出属性 - // 输出属性 - if (attrs != null && attrs.size() > 0 && attrs.containsKey(Constant.METHOD_OUTPUT)) { - JSONObject attrObj = JSONObject.parseObject(attrs.getJSONObject(Constant.METHOD_OUTPUT).toString()); - List contentList = new ArrayList<>(shapeOutMap.get(key)); - Collections.sort(contentList); - attrObj.put("value", StringUtils.join(contentList, ",")); - JSONArray dataAttributes = shapeObj.getJSONArray("dataAttributes"); - if (!dataAttributes.isEmpty() && dataAttributes.size() > 0) { - for (Object attribute : dataAttributes) { - JSONObject obj = (JSONObject) attribute; - if (obj.containsKey("attributesJsonArray")) { - JSONArray attributesJsonArray = obj.getJSONArray("attributesJsonArray"); - attributesJsonArray.add(attrObj); - printMsg("流程" + palModel.getName() + "的节点" + shapeObj.getString("text") + "输出属性内容" + attrObj.getString("value")); - } - } - } - } else { - printMsg("流程" + palModel.getName() + "的节点" + shapeObj.getString("text") + "没有配置输出属性"); - } - } - - } - } - } - } - - /** - * 处理流程属性前后置流程 - * - * @param wsId - * @param currentModelNoShape - * @param idRelationMap - * @param repositoryModelId - * @param elements - * @param arisModel - * @param modelObjOccMap - * @param objDefMap - */ - private void handleProcessAttrLeadOrRearProcess(String wsId, List currentModelNoShape, Map idRelationMap, String repositoryModelId, JSONObject elements, ModelModel arisModel, - Map> modelObjOccMap, Map objDefMap) { - // 如果当前流程下无图形信息 直接返回 - List objOccModels = modelObjOccMap.get(arisModel.getId()); - if (objOccModels == null || objOccModels.size() == 0) { - currentModelNoShape.add(arisModel); - return; - } - // 获取ARIS图形定义与PAL图形定义关系 - Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); - ObjDefMappingModel objDefMappingModel = objDefMappingMap.get("OT_FUNC-ST_PRCS_IF"); - List attributeModels = PALRepositoryAPIManager.getInstance().getValidAttributeModels(wsId, objDefMappingModel.getShapeMethod()); -// List leadProcess = attributeModels.stream().filter(item -> "lead_process".equals(item.getKey())).collect(Collectors.toList()); -// --by shang - List leadProcess = attributeModels.stream().filter(item -> Constant.METHOD_PRE_PROCESS.equals(item.getKey())).collect(Collectors.toList()); - PALMethodAttributeModel leadAttrModel = leadProcess.get(0); - List rearProcess = attributeModels.stream().filter(item -> Constant.METHOD_NEXT_PROCESS.equals(item.getKey())).collect(Collectors.toList()); - PALMethodAttributeModel rearAttrModel = rearProcess.get(0); - // 存放待删除图形的KEY - List removeKey = new ArrayList<>(); - // 流程关联属性结果集 - List relationList = new ArrayList<>(); - for (ObjOccModel objOccModel : objOccModels) { - ObjDefModel objDefModel = objDefMap.get(objOccModel.getDefId());// 形状定义 - // 根据ARIS图形定义信息判断当前模型下的所有形状里是否有系统形状 - if (objDefModel.getTypeNum().equals(objDefMappingModel.getTypeNum()) && objDefModel.getSymbolNum().equals(objDefMappingModel.getSymbolNum())) { - // 如果有输入输出形状 取出关联的PAL模型ID - String shapeId = idRelationMap.get(objOccModel.getId()); - JSONObject leadOrRearObj = elements.getJSONObject(shapeId); - for (String key : elements.keySet()) { - JSONObject tempShapeObj = elements.getJSONObject(key); - if ("linker".equals(tempShapeObj.getString("name"))) { - if (tempShapeObj.getJSONObject("from").getString("id").equals(shapeId)) { - // lead_process - PALRepositoryPropertyDao propertyDao = new PALRepositoryPropertyDao(); - PALRepositoryPropertyModel propertyModel = new PALRepositoryPropertyModel(); - propertyModel.setId(UUIDGener.getUUID()); - propertyModel.setPlId(repositoryModelId); - propertyModel.setPropertyId(leadAttrModel.getKey()); - propertyModel.setPropertyName(leadAttrModel.getNewTitle()); - JSONObject propValue = new JSONObject(); - propValue.put("fileId", repositoryModelId); - propValue.put("shapeId", ""); - propValue.put("shapeText", ""); - propValue.put("attrId", leadAttrModel.getKey()); - propValue.put("relationFileId", new JSONArray()); - propValue.put("relationShapeId", ""); - propValue.put("relationShapeText", ""); - propValue.put("groupPath", leadAttrModel.getGroupPath()); - List repositoryModels = PALRepositoryQueryAPIManager.getInstance().getPalRepositoryModelsByWsIdAndMethodId(wsId, "process.epc"); - repositoryModels = repositoryModels.stream().filter(model -> leadOrRearObj.getString("text").equals(model.getName())).collect(Collectors.toList()); - if (repositoryModels.size() > 0) { - propValue.getJSONArray("relationFileId").add(repositoryModels.get(0).getId()); - } - propertyModel.setPropertyValue(propValue.toString()); - propertyModel.setOrderIndex(0); - propertyDao.insert(propertyModel); - removeKey.add(key); - removeKey.add(shapeId); - break; - } else if (tempShapeObj.getJSONObject("to").getString("id").equals(shapeId)) { - // rear_process - PALRepositoryPropertyDao propertyDao = new PALRepositoryPropertyDao(); - PALRepositoryPropertyModel propertyModel = new PALRepositoryPropertyModel(); - propertyModel.setId(UUIDGener.getUUID()); - propertyModel.setPlId(repositoryModelId); - propertyModel.setPropertyId(rearAttrModel.getKey()); - propertyModel.setPropertyName(rearAttrModel.getNewTitle()); - JSONObject propValue = new JSONObject(); - propValue.put("fileId", repositoryModelId); - propValue.put("shapeId", ""); - propValue.put("shapeText", ""); - propValue.put("attrId", rearAttrModel.getKey()); - propValue.put("relationFileId", new JSONArray()); - propValue.put("relationShapeId", ""); - propValue.put("relationShapeText", ""); - propValue.put("groupPath", ""); - List repositoryModels = PALRepositoryQueryAPIManager.getInstance().getPalRepositoryModelsByWsIdAndMethodId(wsId, "process.epc"); - repositoryModels = repositoryModels.stream().filter(model -> leadOrRearObj.getString("text").equals(model.getName())).collect(Collectors.toList()); - if (repositoryModels.size() > 0) { - propValue.getJSONArray("relationFileId").add(repositoryModels.get(0).getId()); - } - propertyModel.setPropertyValue(propValue.toString()); - propertyModel.setOrderIndex(0); - propertyDao.insert(propertyModel); - removeKey.add(key); - removeKey.add(shapeId); - break; - } else { - continue; - } - } - } - } - } - removeKey.stream().forEach(key -> elements.remove(key)); - } - - /** - * 处理流程关联属性IT系统 - * @param wsId - * @param idRelationMap - * @param repositoryModelId - * @param elements - * @param arisModel - * @param modelObjOccMap - * @param objDefMap - * @param objDefLinkerMap - * @param itShapeMap - */ - private void handleProcessAttrItSystemRelation(String wsId, Map idRelationMap, String repositoryModelId, JSONObject elements, ModelModel arisModel, - Map> modelObjOccMap, - Map objDefMap, Map> objDefLinkerMap, Map itShapeMap) { - // 获取ARIS图形定义与PAL图形定义关系 - Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); - ObjDefMappingModel objDefMappingModel = objDefMappingMap.get("OT_APPL_SYS_TYPE-ST_APPL_SYS_TYPE"); - // 获取当前ARIS模型下所有的图形信息 - List objOccModels = modelObjOccMap.get(arisModel.getId()); - Map> shapeRelationItMap = new HashMap<>();// 记录PAL形状关联的IT系统文本 - for (ObjOccModel objOccModel: objOccModels) { - String objDefId = objOccModel.getDefId(); - // 获取定义形状通过连线进行连接的所有定义形状 - Set toObjDefIds = objDefLinkerMap.get(objDefId); - if (toObjDefIds == null || toObjDefIds.size() == 0) { - continue; - } - // 取出所有IT系统 - Set shapeRelationItObjDefNames = new HashSet<>();// 记录当前形状的IT系统(s) - for (String toObjDefId: toObjDefIds) { - ObjDefModel objDefModel = objDefMap.get(toObjDefId); - if (objDefModel.getSymbolNum().equals(objDefMappingModel.getSymbolNum()) && objDefModel.getTypeNum().equals(objDefMappingModel.getTypeNum())) { - // 是IT系统 - shapeRelationItObjDefNames.add(objDefModel.getName()); - } - } - if (shapeRelationItObjDefNames.size() > 0) { - shapeRelationItMap.put(idRelationMap.get(objOccModel.getId()), shapeRelationItObjDefNames); - } - } - List relationList = new ArrayList<>(); - for (Map.Entry> entry: shapeRelationItMap.entrySet()) { - String shapeId = entry.getKey(); - Set itShapeNames = entry.getValue(); - for (String itShapeName: itShapeNames) { - if (itShapeMap.containsKey(itShapeName)) { - DesignerShapeRelationModel m = new DesignerShapeRelationModel(); - m.setId(UUIDGener.getUUID()); - m.setFileId(repositoryModelId); - m.setShapeId(shapeId); - m.setShapeText(elements.getJSONObject(shapeId).getString("text")); - m.setRelationFileId(itShapeMap.get(itShapeName).getString("plId")); - m.setRelationShapeId(itShapeMap.get(itShapeName).getString("shapeId")); - m.setRelationShapeText(itShapeMap.get(itShapeName).getString("shapeName")); - m.setAttrId(Constant.METHOD_INFO_SYSTEM); - relationList.add(m); - } else { - // todo warn - printMsg("流程【" + arisModel.getName() + "】中的活动节点【" + elements.getJSONObject(shapeId).getString("text") + "】未找到IT系统【" + itShapeName + "】"); - } - } - } - // 保存关联关系 - if (relationList.size() > 0) { - DesignerShapeRelationDao relationDao = new DesignerShapeRelationDao(); - relationList.stream().forEach(item -> printMsg("流程【" + arisModel.getName() + "】中的活动节点【" + item.getShapeText() + "】关联当前流程下IT系统【" + item.getRelationShapeText() + "】")); - relationDao.barchInsert(relationList); - } - } - - /** - * 处理关联属性【角色】与流程关联 - * @param wsId - * @param repositoryModelId - * @param arisFunIdRelationPalRoleMap - * @param palShapeIdRelationArisOccIdMap - * @param elements - * @param arisModel - * @param modelObjOccMap - * @param objDefMap - * @param roleMdoelId - * @param palRoleIdRelationNameMap - * @throws AWSException - */ - private void handleProcessAttrRoleRelation(String wsId, String repositoryModelId, Map arisFunIdRelationPalRoleMap, Map palShapeIdRelationArisOccIdMap, JSONObject elements, ModelModel arisModel, - Map> modelObjOccMap, Map objDefMap, String roleMdoelId, Map palRoleIdRelationNameMap) throws AWSException { - // 获取ARIS图形定义与PAL图形定义关系 - Map objDefMappingMap = ModelMappingAPIManager.getInstance().getObjDefMappingMap(); - ObjDefMappingModel objDefMappingModel = objDefMappingMap.get("OT_PERS_TYPE-ST_EMPL_TYPE"); - // 获取当前ARIS模型下所有的图形信息 - List objOccModels = modelObjOccMap.get(arisModel.getId()); - // 存放待删除图形的KEY - List removeKey = new ArrayList<>(); - // 流程关联属性结果集 - List relationList = new ArrayList<>(); - - Map map = new HashMap<>(); - for (Map.Entry entry : palShapeIdRelationArisOccIdMap.entrySet()) { - String shapeId = entry.getKey(); - String arisShapeId = entry.getValue(); - if (arisFunIdRelationPalRoleMap.containsKey(arisShapeId)) { - String roleShapeId = arisFunIdRelationPalRoleMap.get(arisShapeId); - DesignerShapeRelationModel m = new DesignerShapeRelationModel(); - m.setId(UUIDGener.getUUID()); - m.setFileId(repositoryModelId); - m.setShapeId(shapeId); - m.setShapeText(elements.getJSONObject(shapeId).getString("text")); - m.setRelationFileId(roleMdoelId); - m.setRelationShapeId(roleShapeId); - m.setRelationShapeText(palRoleIdRelationNameMap.get(roleShapeId)); - m.setAttrId(Constant.METHOD_ROLE); - relationList.add(m); - } - } - - Set roleIdSet = new HashSet<>(); - for (String key : elements.keySet()) { - JSONObject tempShapeObj = elements.getJSONObject(key); - if ("role".equals(tempShapeObj.getString("name"))) { - roleIdSet.add(key); - } - } - for (String key : elements.keySet()) { - JSONObject tempShapeObj = elements.getJSONObject(key); - if ("linker".equals(tempShapeObj.getString("name"))) { - String text = ""; - if (roleIdSet.contains(tempShapeObj.getJSONObject("from").getString("id"))) { - text = elements.getJSONObject(tempShapeObj.getJSONObject("from").getString("id")).getString("text"); - // 删除图形与连线 - removeKey.add(key); - removeKey.add(tempShapeObj.getJSONObject("from").getString("id")); - } else if (roleIdSet.contains(tempShapeObj.getJSONObject("to").getString("id"))) { - text = elements.getJSONObject(tempShapeObj.getJSONObject("to").getString("id")).getString("text"); - // 删除图形与连线 - removeKey.add(key); - removeKey.add(tempShapeObj.getJSONObject("to").getString("id")); - } - printMsg("流程" + arisModel.getName() + "删除角色形状" + text + "和其连线"); - } - } - - // 删除没有与活动进行连线相连的角色形状(角色图中已包含该角色图标) - for (String key : elements.keySet()) { - JSONObject tempShapeObj = elements.getJSONObject(key); - if ("role".equals(tempShapeObj.getString("name")) && !removeKey.contains(tempShapeObj.getString("id"))) { - removeKey.add(key); - printMsg("流程" + arisModel.getName() + "删除角色形状" + tempShapeObj.getString("text") + ",该角色无连线连接到活动"); - } - } - - // 保存关联关系 - if (relationList.size() > 0) { - DesignerShapeRelationDao relationDao = new DesignerShapeRelationDao(); - relationList.stream().forEach(item -> printMsg("流程【" + arisModel.getName() + "】中的活动节点【" + item.getShapeText() + "】关联当前流程下角色【" + item.getRelationShapeText() + "】")); - relationDao.barchInsert(relationList); - } - removeKey.stream().forEach(key -> elements.remove(key)); - } - - /** - * 设置画布大小 - * - * @param elements - */ - private void setDiagramHeightWidth(JSONObject definition, JSONObject elements) { - // 获取最大宽高,给100长度富余 - JSONObject maxHW = getMaxPositionXY(elements); - int maxX = maxHW.getInteger("maxX") + 150; - int maxH = maxHW.getInteger("maxY") + 150; - JSONObject page = definition.getJSONObject("page"); - int pageW = page.getInteger("width"); - int pageH = page.getInteger("height"); - page.put("width", pageW > maxX ? pageW : maxX); - page.put("height", pageH > maxH ? pageH : maxH); - definition.put("page", page); - } - - private JSONObject getMaxPositionXY(JSONObject elements) { - int maxX = -99999; - int maxY = -99999; - Iterator it = elements.keySet().iterator(); - while (it.hasNext()) { - String key = it.next(); - JSONObject shape = elements.getJSONObject(key); - String shapeName = shape.getString("name"); - if (!"linker".equals(shapeName)) { - JSONObject props = shape.getJSONObject("props"); - int x = props.getInteger("x"); - int y = props.getInteger("y"); - maxX = maxX < x ? x : maxX; - maxY = maxY < y ? y : maxY; - } - } - JSONObject result = new JSONObject(); - result.put("maxX", maxX); - result.put("maxY", maxY); - return result; + private boolean isEmptyJsonOject(JSONObject o) { + return o == null || o.isEmpty(); } - /** - * 创建具有合理位置的节点数据 - * - * @param elements - * @param shapeRowCount - * @return - */ - private JSONArray getMethodElementsJSONArray(JSONArray elements, int shapeRowCount) { - JSONArray result = new JSONArray(); - int zindex = 0; - int initX = 0; - int initY = 0; - int pageEdge = 100; - int count = 0; - initX += pageEdge; - initY += pageEdge; - for (int i = 0; i < elements.size(); i++) { - JSONObject shape = elements.getJSONObject(i); - count++; - if (count % (shapeRowCount + 1) == 0) { - count = 1; - initY += 130; - // 换行 - initX = 0; - initX = pageEdge + initX; - } - zindex++; - if (shape.containsKey("dataAttributes")) { - JSONArray dataAttributes = JSONArray.parseArray(shape.getString("dataAttributes")); - for (int index = 0; index < dataAttributes.size(); index++) { - dataAttributes.getJSONObject(index).put("id", UUIDGener.getObjectId()); - } - shape.put("dataAttributes", dataAttributes); - } - int totalWidth = 240;// 每个节点总宽度,空白+节点+空白 - int totalHeight = 200;// 每个节点总高度,空白+节点+空白 - int x = 0; - int y = 0; - int w = validateJson(shape.getJSONObject("props").getInteger("w")); - int h = validateJson(shape.getJSONObject("props").getInteger("h")); - int leftBlankWidth = (totalWidth - w) / 2; - int topBlankHeight = (totalHeight - h) / 2; - x = initX + leftBlankWidth; - initX = x + w + leftBlankWidth; - y = initY + topBlankHeight; -// y = pageEdge + initY; -// if (y < 0) { -// y = 100; -// } - JSONObject props = shape.getJSONObject("props"); - props.put("x", x); - props.put("y", y); - props.put("zindex", zindex); - shape.put("props", props); - result.add(shape); - } - return result; - } - - /** - * 获取连线的折点(不包括起始端) - * - * @param positionModels - * @return - */ - private Object getLinkerPoints(List positionModels) { - JSONArray result = new JSONArray(); - if (positionModels.size() > 2) { - for (int i = 1; i < positionModels.size() - 1; i++) { - JSONObject obj = new JSONObject(); - obj.put("x", positionModels.get(i).getX()); - obj.put("y", positionModels.get(i).getY()); - result.add(obj); - } - } - return result; - } - - /** - * 获取连线angle - * - * @param positionModels - * @param type - * @return - */ - private double getLinkerAngle(List positionModels, String type) { - if (positionModels.size() < 2) { - System.out.println("出错了"); - return 0; - } else if (positionModels.size() == 2) { - if (positionModels.get(0).getX() == positionModels.get(1).getX()) { - if ("from".equals(type)) { - return (positionModels.get(0).getY() - positionModels.get(1).getY() > 0) ? Constant.ANGLE_DOWN : Constant.ANGLE_UP; - } else { - return (positionModels.get(0).getY() - positionModels.get(1).getY() > 0) ? Constant.ANGLE_UP : Constant.ANGLE_DOWN; - } - } else { - if ("from".equals(type)) { - return (positionModels.get(0).getX() - positionModels.get(1).getX() > 0) ? Constant.ANGLE_RIGHT : Constant.ANGLE_LEFT; - } else { - return (positionModels.get(0).getX() - positionModels.get(1).getX() > 0) ? Constant.ANGLE_LEFT : Constant.ANGLE_RIGHT; - } - } - } else { - List list = new ArrayList<>(); - if ("from".equals(type)) { - list.add(new PositionModel(positionModels.get(0).getX(), positionModels.get(0).getY())); - list.add(new PositionModel(positionModels.get(1).getX(), positionModels.get(1).getY())); - } else { - list.add(new PositionModel(positionModels.get(positionModels.size() - 2).getX(), positionModels.get(positionModels.size() - 2).getY())); - list.add(new PositionModel(positionModels.get(positionModels.size() - 1).getX(), positionModels.get(positionModels.size() - 1).getY())); - } - return getLinkerAngle(list, type); - } - } - - private int validateJson(Integer index) { - return index == null ? 0 : index; - } - - - - private void printMsg(String msg) { - SDK.getLogAPI().consoleInfo(msg); - } - } + diff --git a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/cache/DataMigrationCache.java b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/cache/DataMigrationCache.java new file mode 100644 index 00000000..0400f8eb --- /dev/null +++ b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/cache/DataMigrationCache.java @@ -0,0 +1,26 @@ +package com.actionsoft.apps.coe.pal.datamigration.cache; + +import com.actionsoft.apps.resource.plugin.profile.CachePluginProfile; +import com.actionsoft.bpms.commons.cache.Cache; +import com.actionsoft.bpms.commons.cache.CacheManager; + +/** + * 存储导入数据 + * @author sunlh + * + */ +public class DataMigrationCache extends Cache{ + + public DataMigrationCache(CachePluginProfile configuration) { + super(configuration); + } + + @Override + protected void load() { + } + + public static DataMigrationCache getCache() { + return CacheManager.getCache(DataMigrationCache.class); + } + +} diff --git a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/constant/Constant.java b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/constant/Constant.java index 5a202f84..162925a4 100644 --- a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/constant/Constant.java +++ b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/constant/Constant.java @@ -61,9 +61,31 @@ public class Constant { // 日志常量记录 - public static final String LOG_SUCCESS = "成功"; - public static final String LOG_WARNING = "警告"; - public static final String LOG_ERROR = "错误"; + public static final String LOG_SUCCESS = "【成功】"; + public static final String LOG_WARNING = "【警告】"; + public static final String LOG_ERROR = "【错误】"; + + // 日志表resultType字段常量codeß + public static final int LOG_RESULT_TYPE_RUN = 0;// 进行中 + public static final int LOG_RESULT_TYPE_SUCCESS = 1;// 完成 + public static final int LOG_RESULT_TYPE_ERROR = 2;// 失败 + + public static final String IMPORT_STOP_MSG = "导入停止"; + + public static final String PROCESS_EPC = "process.epc"; + + public static final String ORG_ROLE = "org.role"; + + public static final String ITSYSTEM_NORMAIL = "itsystem.normal"; + + public static final String METHOD_APPROVAL_NODE = "method_approval_node";// 线上审批 + + public static final String METHOD_SERVICE_NODE = "method_service_node";// 线下审批 + + public static final String METHOD_APPROVAL_NODE3 = "method_approval_node3";// 系统任务 + public static final String METHOD_SERVICE_NODE4 = "method_service_node4";// 人工任务 + + diff --git a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/plugin/Plugins.java b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/plugin/Plugins.java index f54775f6..d81734b2 100755 --- a/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/plugin/Plugins.java +++ b/com.actionsoft.apps.coe.pal.datamigration/src/com/actionsoft/apps/coe/pal/datamigration/plugin/Plugins.java @@ -1,5 +1,7 @@ package com.actionsoft.apps.coe.pal.datamigration.plugin; +import com.actionsoft.apps.coe.pal.datamigration.aris.constant.ArisConstant; +import com.actionsoft.apps.coe.pal.datamigration.cache.DataMigrationCache; import com.actionsoft.apps.coe.pal.datamigration.web.DataMigrationWeb; import com.actionsoft.apps.coe.pal.pal.repository.upfile.CoeFileProcessor; import com.actionsoft.apps.listener.PluginListener; @@ -21,8 +23,11 @@ public class Plugins implements PluginListener { public List register(AppContext context) { List list = new ArrayList(); + // 注册缓存 + list.add(new CachePluginProfile(DataMigrationCache.class)); list.add(new DCPluginProfile("migration", CoeFileProcessor.class.getName(), "存放数据迁移文件", false, false)); + list.add(new DCPluginProfile(ArisConstant.REPOSITORY_NAME, CoeFileProcessor.class.getName(), "存在arisXML数据迁移日志", false, false)); // PAL应用扩展点 Map params0 = new HashMap();