ChamberRecipeListAction.java
package com.mycim.webapp.actions.equipment.recipe;
import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.utils.lang.BooleanUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.CollectionUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.lang.math.NumberUtils;
import com.mycim.framework.utils.lang.time.DateUtils;
import com.mycim.valueobject.MessageIdList;
import com.mycim.valueobject.ObjectList;
import com.mycim.valueobject.SystemConstant;
import com.mycim.valueobject.bas.Relation;
import com.mycim.valueobject.consts.LinkTypeList;
import com.mycim.valueobject.consts.TransactionNames;
import com.mycim.valueobject.ems.Entity;
import com.mycim.valueobject.prp.Recipe;
import com.mycim.valueobject.prp.RecipeStatus;
import com.mycim.valueobject.prp.RecipeVersion;
import com.mycim.webapp.Constants;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.actions.EmsSetupAction;
import com.mycim.webapp.forms.EntityInfoForm;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
/**
* 设备定义-腔室设备
*
* @author pinyan.song
* @version 6.0.0
* @date 2019-9-8 21:51
**/
public class ChamberRecipeListAction extends EmsSetupAction {
private static final String SUB_RECIPE_SEPARATOR = "-";
private static final String PARALLEL_MODE = "PARALLEL";
private static final String SERIAL_MODE = "SERIAL";
private static final String FLAG = "1";
@Override
public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
EntityInfoForm theform = (EntityInfoForm) form;
Entity theEntity = getEntity(theform, request);
String searchId = StringUtils.trimToUpperCase(theform.getSearchRecipeId());
String chamberMode=theEntity.getChamberMode();
List<Map<String, Object>> recipeList =recipeService
.getRecipesByEquipmentForShow(theEntity.getInstanceRrn(), searchId, chamberMode);
//当chamber mode = Parallel的机台 EQP setup 界面的 reciplist 界面按照 recipeID 正序排序
if (StringUtils.equalsIgnoreCase(chamberMode, SystemConstant.Str.PARALLEL)){
if(CollectionUtils.isNotEmpty(recipeList)){
Collections.sort(recipeList, (o1, o2) -> {
String id1=MapUtils.getString(o1,"recipeId");
String id2=MapUtils.getString(o2,"recipeId");
if (StringUtils.isNotEmpty(id1) && StringUtils.isNotEmpty(id2)){
return id1.compareTo(id2);
}
return 0;
});
}
}
request.setAttribute("recipeList",recipeList);
request.setAttribute("recipeHistoryList",
recipeService.getDeleteRelationHistoryByEntityForRecipe(theEntity.getInstanceRrn()));
request.setAttribute("hasEditPermisstion", securityService
.hasRelationEditPermission(LocalContext.getFacilityRrn(), LocalContext.getUserRrn(),
theEntity.getMaintenanceEngineerRrn()));
theform.setSearchRecipeId(searchId);
theform.setChamberMode(theEntity.getChamberMode());
theform.setTransId(Constants.MODIFY_KEY);
theform.setRecipeId("");
return mapping.getInputForward();
}
public ActionForward batchUpdateMembers(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
EntityInfoForm theform = (EntityInfoForm) form;
Entity entity = getEntity(theform, request);
String[] selectUpdateRecipeRrns = request.getParameterValues("selectUpdateStatus");
String status = request.getParameter("changeStatus");
String comments = WebUtils.getParameter("reason", request);
Assert.isFalse(selectUpdateRecipeRrns == null || selectUpdateRecipeRrns.length == 0,
Errors.create().key(MessageIdList.RECIPE_MISSING_RECIPE).content("No recipe selected!").build());
List<Long> recipeRrns = new ArrayList<>();
for (String selectUpdateRecipeRrn : selectUpdateRecipeRrns) {
long recipeRrn = NumberUtils.toLong(selectUpdateRecipeRrn);
checkRecipeIsInUse(entity.getInstanceRrn(), recipeRrn);
recipeRrns.add(recipeRrn);
}
/* 串行模式也能多个ON
if (CollectionUtils.isNotEmpty(recipeRrns)) {
if (RecipeStatus.isAvailable(status) && SERIAL_MODE.equals(entity.getChamberMode())) {
checkOnStatusSubRecipeInSerialMode(entity.getInstanceRrn(), recipeRrns);
}
}
*/
Relation relation = new Relation();
relation.setLinkType(LinkTypeList.ENTITY_TO_RECIPE);
relation.setFromRrn(entity.getInstanceRrn());
relation.setLastUpdatedUser(LocalContext.getUserRrn());
recipeService.updateRecipesStatus(LocalContext.getUserId(), RecipeStatus.getContrary(status), status, relation,
recipeRrns, comments);
WebUtils.setSuccessMsg(request);
return init(mapping, theform, request, response);
}
public ActionForward history(ActionMapping mapping, ActionForm form, HttpServletRequest request) {
EntityInfoForm theform = (EntityInfoForm) form;
if (StringUtils.isNotBlank(request.getParameter("flag"))) {
request.setAttribute("flag", FLAG);
}
return mapping.findForward(Constants.HISTORY_KEY);
}
public ActionForward deleteMembers(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
EntityInfoForm theform = (EntityInfoForm) form;
Entity entity = getEntity(theform, request);
long recipeRrn = WebUtils.getParameterLong(Constants.ITEM_KEY, request);
checkRecipeIsInUse(entity.getInstanceRrn(), recipeRrn);
Relation relation = baseService.getRelation(entity.getInstanceRrn(), recipeRrn, LinkTypeList.ENTITY_TO_RECIPE);
relation.setLastUpdatedUser(LocalContext.getUserRrn());
relation.setTransPerformedby(LocalContext.getUserId());
relation.setTransId(TransactionNames.DELETE_KEY);
emsService.deleteRelation4RecipeToEntity(relation,theform.getReason());
WebUtils.setSuccessMsg(request);
return init(mapping, theform, request, response);
}
public ActionForward deleteHistory(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
EntityInfoForm theform = (EntityInfoForm) form;
Entity entity = getEntity(theform, request);
long transRrn = WebUtils.getParameterLong("transRrn", request);
int transSequence = WebUtils.getParameterInt("transSequence", request);
baseService.updateDeleteRelationHistory(transRrn, transSequence);
WebUtils.setSuccessMsg(request);
return init(mapping, theform, request, response);
}
public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
EntityInfoForm theform = (EntityInfoForm) form;
Entity entity = getEntity(theform, request);
String recipeId = StringUtils.trimToUpperCase(theform.getRecipeId());
Assert.isFalse(StringUtils.isBlank(recipeId),
Errors.create().key(MessageIdList.RECIPE_INVALID_ID).content("Recipe cannot be empty!").build());
long equipmentRrn = entity.getInstanceRrn();
String chamberMode = entity.getChamberMode();
boolean isDefaultAvailableStatus = true;
boolean isSingleChamber = true;
Recipe recipe;
long parentRecipeRrn;
List<Long> addRecipeRrns = new ArrayList<>();
String parentRecipeId = StringUtils.substringBeforeLast(recipeId, SUB_RECIPE_SEPARATOR);
String chamberId = StringUtils.substringAfterLast(recipeId, SUB_RECIPE_SEPARATOR);
checkInputRecipeIdCanBeCreated(equipmentRrn, chamberId);
recipe = recipeService.getRecipe(parentRecipeId, LocalContext.getFacilityRrn());
Assert.isFalse(recipe == null || recipe.getInstanceRrn() <= 0,
Errors.create().key(MessageIdList.RECIPE_MISSING).content("The Recipe {} does not " + "exist!")
.args(parentRecipeId).build());
parentRecipeRrn = recipe.getInstanceRrn();
addRecipeRrns.add(parentRecipeRrn);
if (StringUtils.equalsIgnoreCase(chamberMode, SERIAL_MODE) || StringUtils.isEmpty(chamberMode)) {
isDefaultAvailableStatus = false;
isSingleChamber = chamberId.length() == 1;
addRecipeRrns.add(createSubRecipeWithIsExisted(recipe, recipeId));
} else {
Assert.isFalse(chamberId.length() != 1, Errors.create().key(MessageIdList.EQUIPMENT_IS_PARALLEL_ONLY_ONE)
.content(
"This Equipment is parallel mode, please only" + " " +
"input one chamber's recipe.").build());
addRecipeRrns.addAll(buildAddRecipeRrnsForParallelMode(equipmentRrn, recipe, chamberId));
}
// int maxSize = baseService.getRelationsUseFromRrn(equipmentRrn, LinkTypeList.ENTITY_TO_RECIPE).size();
int maxSeqNumber = 0;
//在串联模式下,防止生成sequence number重复的问题
if (StringUtils.equalsIgnoreCase(chamberMode, SERIAL_MODE)) {
maxSeqNumber = baseService.getMaxSeqOfRelation(new Relation(equipmentRrn,null,LinkTypeList.ENTITY_TO_RECIPE));
}else{
maxSeqNumber = baseService.getRelationsUseFromRrn(equipmentRrn, LinkTypeList.ENTITY_TO_RECIPE).size();
}
String currentTimestampString = DateUtils.formatDate(new Date());
String status;
List<Relation> addRelations = new ArrayList<>();
for (Long recipeRrn : addRecipeRrns) {
if (!isExistedInRelation(equipmentRrn, recipeRrn)) {
Relation relation = new Relation(equipmentRrn, recipeRrn, LinkTypeList.ENTITY_TO_RECIPE);
relation.setSequenceNumber(++maxSeqNumber);
boolean isParentRecipe = recipeRrn == parentRecipeRrn;
boolean isAvailableStatus = isParentRecipe || isDefaultAvailableStatus;
status = StringUtils.trimToUpperCase(BooleanUtils.toStringOnOff(isAvailableStatus));
String parentRecipeRrnStr = isParentRecipe ? null : StringUtils.toString(parentRecipeRrn);
String isSingleChamberStr = isParentRecipe ? null : StringUtils
.upperCase(BooleanUtils.toStringYesNo(isSingleChamber));
relation.setStatus(status);
relation.setAttributedata1(status);
relation.setAttributedata2(StringUtils.toString(LocalContext.getUserRrn()));
relation.setAttributedata3(currentTimestampString);
relation.setAttributedata4(parentRecipeRrnStr);
relation.setAttributedata5(recipe.getAttributeData2());
relation.setAttributedata6(isSingleChamberStr);
relation.setAttributedata7(chamberMode);
relation.setTransPerformedby(LocalContext.getUserId());
relation.setTransId(TransactionNames.CREATE_KEY);
addRelations.add(relation);
}
}
Assert.isFalse(CollectionUtils.isEmpty(addRelations), Errors.create().key(MessageIdList.RECIPE_HAS_EQP_RELATION)
.content(
"Recipe has a relationship with " + "this" +
" equipment!").build());
if (CollectionUtils.isNotEmpty(addRelations)) {
// baseService.insertRelation(addRelations);
emsService.insertRelation4RecipeToEntity(addRelations,theform.getReason());
}
WebUtils.setSuccessMsg(request);
return init(mapping, theform, request, response);
}
public ActionForward updateRelationSequence(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
EntityInfoForm theform = (EntityInfoForm) form;
Entity entity = getEntity(theform, request);
Long recipeRrn = WebUtils.getParameterLong("recipeRrn", request);
Long replaceRecipeRrn = WebUtils.getParameterLong("replaceRecipeRrn", request);
int seq = WebUtils.getParameterInt("seq", request);
int replaceSeq = WebUtils.getParameterInt("replaceSeq", request);
Assert.isFalse(replaceRecipeRrn == null || replaceRecipeRrn.longValue() == 0,
Errors.create().content("The relation sequence is already the minimum or maximum!").build());
Relation relation1 = baseService.getRelation(entity.getInstanceRrn(), recipeRrn, LinkTypeList.ENTITY_TO_RECIPE);
Relation relation2 = baseService
.getRelation(entity.getInstanceRrn(), replaceRecipeRrn, LinkTypeList.ENTITY_TO_RECIPE);
Assert.isFalse(relation1 == null || relation2 == null,
Errors.create().key(MessageIdList.RECIPE_NOT_EXIST).content("Recipe relation is not existed!")
.build());
String comments =
"Exchange serial NO: " + getInstanceId(recipeRrn) + " from " + seq + " to " + replaceSeq + ";" +
getInstanceId(replaceRecipeRrn) + " from " + replaceSeq + " to " + seq;
emsService.exchangeRelationSequence(relation1, relation2, comments);
WebUtils.setSuccessMsg(request);
return init(mapping, theform, request, response);
}
private void checkOnStatusSubRecipeInSerialMode(long equipmentRrn, List<Long> recipeRrns) {
Map<Long, Integer> selectedMap = new HashMap<>();
for (Long selectedRecipeRrn : recipeRrns) {
Relation relation = baseService.getRelation(equipmentRrn, selectedRecipeRrn);
if (relation == null) {
continue;
}
Long parentRecipeRrn = NumberUtils.toLong(relation.getAttributedata4(), 0L);
if (parentRecipeRrn > 0) {
int onStatusSize = recipeService.getOpenRecipesByEquipmentForSerialMode(equipmentRrn, parentRecipeRrn)
.size();
Integer selectedSize = MapUtils.getIntValue(selectedMap, parentRecipeRrn) + 1;
selectedMap.put(parentRecipeRrn, selectedSize);
Assert.isFalse(selectedSize > 1 || onStatusSize >= 1,
Errors.create().key(MessageIdList.EQUIPMENT_SERIAL_MODE_ONLY_ONE_SUB_RECIPE)
.content("recipe串行改ON").build());
}
}
}
private void checkRecipeIsInUse(long entityRrn, Long recipeRrn) {
Assert.isFalse(wipQueryService.checkLotStatus(recipeRrn, entityRrn),
Errors.create().key(MessageIdList.RECIPE_CANT_OPERATION_HAS_RUN_LOT).content(
"a lot runing on the" + " " + "EQP by the " + "recipe,this " + "operation cannot " +
"be performed!").build());
}
private boolean isExistedInRelation(long equipmentRrn, Long recipeRrn) {
return baseService.getRelation(new Relation(equipmentRrn, recipeRrn, LinkTypeList.ENTITY_TO_RECIPE)) != null;
}
private List<Long> buildAddRecipeRrnsForParallelMode(long equipmentRrn, Recipe parentRecipe, String chamberId) {
List<Long> addRecipeRrns = new ArrayList<>();
Set<String> willCreateChamberIds = new HashSet<>();
willCreateChamberIds.add(chamberId);
buildCreatedSingleChamberId(willCreateChamberIds, equipmentRrn, parentRecipe.getInstanceId());
for (String combinationId : getAvailableSubRecipeChamberIds(willCreateChamberIds)) {
if (!combinationId.contains(chamberId)) {
continue;
}
long subRecipeRrn = createSubRecipeWithIsExistedByChamberId(parentRecipe, combinationId);
if (combinationId.length() == 1) {
addRecipeRrns.add(subRecipeRrn);
}
}
return addRecipeRrns;
}
private long createSubRecipeWithIsExistedByChamberId(Recipe parentRecipe, String combinationId) {
return createSubRecipeWithIsExisted(parentRecipe, StringUtils
.trimToUpperCase(parentRecipe.getInstanceId() + SUB_RECIPE_SEPARATOR + combinationId));
}
private List<String> getAvailableSubRecipeChamberIds(Collection<String> chamberTypes) {
if (CollectionUtils.isEmpty(chamberTypes)) {
return Collections.emptyList();
} else {
List<String> list = buildNoRepeatChamberTypes(chamberTypes);
return StringUtils.combinationStrings(list.toArray(new String[0]));
}
}
private List<String> buildNoRepeatChamberTypes(Collection<String> chamberTypes) {
Set<String> set = new HashSet<>();
for (String string : chamberTypes) {
if (StringUtils.isNotEmpty(string)) {
set.add(string);
}
}
List<String> list = new ArrayList<>(set);
Collections.sort(list);
return list;
}
private void buildCreatedSingleChamberId(Set<String> willCreateChamberIds, long equipmentRrn,
String parentRecipeId) {
String queryRecipeId = parentRecipeId + "-*";
for (Map<String, Object> map : recipeService
.getRecipesByEquipmentForParallelMode(equipmentRrn, queryRecipeId)) {
willCreateChamberIds
.add(StringUtils.substringAfterLast((MapUtils.getString(map, "recipeId")), SUB_RECIPE_SEPARATOR));
}
}
private Long createSubRecipeWithIsExisted(Recipe parentRecipe, String subRecipeId) {
long subRecipeRrn = getInstanceRrn(subRecipeId, LocalContext.getFacilityRrn(), ObjectList.RECIPE_KEY);
if (subRecipeRrn <= 0) {
subRecipeRrn = createSubRecipeWithActiveVersion(parentRecipe, subRecipeId);
}
checkSubRecipeVersionInfo(subRecipeId, subRecipeRrn);
Relation relation = new Relation(parentRecipe.getInstanceRrn(), subRecipeRrn,
LinkTypeList.RECIPEFAMILY_TO_RECIPE);
if (baseService.getRelation(relation) == null) {
relation.setTransId(TransactionNames.CREATE_KEY);
recipeService.insertRelation4RecipeFamilyToRecipe(relation);
}
return subRecipeRrn;
}
private void checkSubRecipeVersionInfo(String subRecipeId, long subRecipeRrn) {
List<String> recipeChambers = getRecipeChambers(subRecipeRrn);
Assert.isFalse(CollectionUtils.isEmpty(recipeChambers),
Errors.create().key(MessageIdList.RECIPE_NOT_CHAMBER_IS_VERSION)
.content("This recipe {} has not any required " + "chamber in active version!")
.args(subRecipeId).build());
String chamberIds = StringUtils.substringAfterLast(subRecipeId, SUB_RECIPE_SEPARATOR);
boolean isSameNum = chamberIds.length() == recipeChambers.size();
for (String requiredChamberId : recipeChambers) {
Assert.isFalse(!isSameNum || !chamberIds.contains(requiredChamberId),
Errors.create().key(MessageIdList.RECIPE_CHAMBER_IN_VERSION).content(
"This recipe {}" + " " + "required " + "chamber in " + "active " + "version is " +
"not mapped " + "subrecipe id!").args(subRecipeId).build());
}
}
private List<String> getRecipeChambers(long subRecipeRrn) {
RecipeVersion subRecipeVersion = recipeService.getNowActiveRecipeVersion(subRecipeRrn);
boolean isAvailableRecipe = subRecipeVersion != null && subRecipeVersion.getInstanceRrn() > 0 &&
subRecipeVersion.getInstanceVersion() > 0;
String[] chambers = null;
if (isAvailableRecipe) {
chambers = StringUtils.split(StringUtils.substringBefore(subRecipeVersion.getChamberTypes(), ";"),
StringUtils.COMMA_SIGN);
}
List<String> result;
if (chambers != null) {
result = Arrays.asList(chambers);
} else {
result = Collections.emptyList();
}
return result;
}
private long createSubRecipeWithActiveVersion(Recipe parentRecipe, String subRecipeId) {
Recipe recipe = new Recipe(StringUtils.trimToUpperCase(subRecipeId), parentRecipe.getNamedSpace(),
ObjectList.RECIPE_KEY);
recipe.setObjectType(ObjectList.RECIPE_KEY);
recipe.setAttributeData1(parentRecipe.getAttributeData1());
recipe.setAttributeData2(parentRecipe.getAttributeData2());
recipe.setAttributeData3(parentRecipe.getAttributeData3());
recipe.setTransPerformedby(LocalContext.getUserId());
recipe.setTransId(TransactionNames.CREATE_KEY);
long subRecipeRrn = recipeService.insertRecipe(setDefaultParam(recipe));
recipe.setInstanceRrn(subRecipeRrn);
recipe = recipeService.getRecipe(recipe.getInstanceRrn());
baseService.updateNamedObjectSystemUesd(recipe.getInstanceRrn(), "1");
createActiveSubRecipeVersion(recipe, StringUtils.substringAfterLast(subRecipeId, SUB_RECIPE_SEPARATOR));
return subRecipeRrn;
}
private void createActiveSubRecipeVersion(Recipe subRecipe, String chamberIds) {
RecipeVersion recipeVersion = new RecipeVersion();
recipeVersion.copyNamedObject(subRecipe);
int newVersionId = subRecipe.getCurrentVersion() == null ? 1 : subRecipe.getCurrentVersion() + 1;
recipeVersion.setInstanceVersion(newVersionId);
recipeVersion.setVersionId(Integer.toString(newVersionId));
recipeVersion.setVersionDesc("Automatic schema generation");
recipeVersion.setChamberTypes(buildChamberTypesForRecipeVersion(chamberIds.toCharArray()));
recipeVersion.setTransId(TransactionNames.CREATE_KEY);
recipeVersion.setTransPerformedby(LocalContext.getUserId());
recipeService.createRecipeVersion(recipeVersion);
recipeVersion = recipeService.getRecipeVersion(recipeVersion);
ecnService.activateEcn(recipeVersion.getEcnRrn());
}
private String buildChamberTypesForRecipeVersion(char[] chamberIds) {
int lastChar = chamberIds.length - 1;
StringBuilder result = new StringBuilder();
for (int i = 0; i < chamberIds.length; i++) {
result.append(chamberIds[i]);
result.append(i == lastChar ? ";" : StringUtils.COMMA_SIGN);
}
return result.toString();
}
private void checkInputRecipeIdCanBeCreated(long equipmentRrn, String chamberId) {
Assert.isFalse(StringUtils.isEmpty(chamberId), Errors.create().key(MessageIdList.RECIPE_ID_IS_ERROR).content(
"Recipe ID must use a Recipe ID with a '-' and " + "cannot end with a '-'!").build());
List<String> canBeCreatedChamberIds = emsService.getChildChamberEquipmentType(equipmentRrn);
Assert.isFalse(CollectionUtils.isEmpty(canBeCreatedChamberIds),
Errors.create().key(MessageIdList.EQUIPMENT_NOT_HAVE_CHAMBER)
.content("This Equipment does not have " + "any chamber!").build());
char[] chars = chamberId.toCharArray();
for (char c : chars) {
Assert.isTrue(canBeCreatedChamberIds.contains(StringUtils.toString(c)),
Errors.create().key(MessageIdList.EQUIPMENT_NOT_HAVE_CHAMBER_2)
.content("This Equipment " + "does not " + "have this " + "chamber: " + "{}!").args(c)
.build());
}
}
private Entity getEntity(EntityInfoForm theform, HttpServletRequest request) {
Entity theEntity = new Entity(theform.getInstanceId(),
getNamedSpace(ObjectList.ENTITY_KEY, LocalContext.getFacilityRrn()),
ObjectList.ENTITY_KEY);
theEntity = (Entity) getInstance(theEntity);
emsService.checkEquipmentRecipeInvalid(theEntity.getInstanceRrn());
if (StringUtils.isNotBlank(WebUtils.getParameter("equipmentReadOnlyFlag", request))) {
request.setAttribute("equipmentReadOnlyFlag", 1);
}
return theEntity;
}
}