AbstractAction.java
/*
* @ Copyright 2001 FA Software;
* All right reserved. No part of this program may be reproduced or
* transmitted in any form or by any means, electronic or
* mechanical, including photocopying, recording, or by any
* information storage or retrieval system without written
* permission from FA Software, except for inclusion of brief
* quotations in a review.
*/
package com.mycim.webapp.actions;
import com.fa.sesa.exception.Assert;
import com.fa.sesa.exception.Errors;
import com.fa.sesa.i18n.I18nUtils;
import com.fa.sesa.threadlocal.LocalContext;
import com.mycim.framework.context.spring.SpringContext;
import com.mycim.framework.logging.Logger;
import com.mycim.framework.logging.LoggerFactory;
import com.mycim.framework.utils.beans.PropertyUtils;
import com.mycim.framework.utils.lang.ArrayUtils;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.msg.JsonUtils;
import com.mycim.framework.utils.msg.model.Request;
import com.mycim.framework.utils.msg.model.RequestHeader;
import com.mycim.server.base.service.BaseService;
import com.mycim.server.security.service.SecurityService;
import com.mycim.server.system.service.SysService;
import com.mycim.valueobject.*;
import com.mycim.valueobject.bas.NamedObject;
import com.mycim.valueobject.sys.Facility;
import com.mycim.valueobject.sys.ReferenceFileDetail;
import com.mycim.webapp.Constants;
import com.mycim.webapp.ResponseMsgBuilder;
import com.mycim.webapp.WebUtils;
import com.mycim.webapp.forms.RootForm;
import org.apache.struts.action.Action;
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.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.*;
import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.regex.Pattern;
/**
* @author Johnson.Wang
* @version 6.0.0
* @date 2019/8/24
**/
public abstract class AbstractAction extends Action {
protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
protected BaseService baseService = SpringContext.getBean(BaseService.class);
protected SysService sysService = SpringContext.getBean(SysService.class);
protected SecurityService securityService = SpringContext.getBean(SecurityService.class);
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
try {
return perform(mapping, form, request, response);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
request.setAttribute(Constants.MESSAGE_ERROR, ResponseMsgBuilder.buildErrorJsonMsg(e));
return (mapping.findForward(Constants.ERROR_KEY));
}
}
public ActionForward perform(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
Boolean isUpload = Boolean.valueOf(request.getParameter("isUpload"));
if (isAjax(request)) {
// 请求为json消息时
return executeAjax(mapping, form, request, response);
} else if (isUpload) {
// 上传文件
return executeUpload(mapping, form, request, response);
} else {
// 请求为struts时
return executeStruts(mapping, form, request, response);
}
}
/**
* 在struts action中注册初始化查询数据的方法
*
* @return
*/
public String inItMethod() {
return "init";
}
public ActionForward init(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
return WebUtils.NULLActionForward;
}
/**
* 默认的返回方法
*/
public ActionForward cancel(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) throws Exception {
RootForm rootForm = (RootForm) form;
rootForm.setInstanceId("");
return (mapping.findForward(Constants.SETUP_KEY));
}
private void checkUrl(HttpServletRequest request) {
String query = request.getQueryString();
int index = StringUtils.indexOf(query, "?");
Assert.isFalse(index > 0,
Errors.create().key(MessageIdList.SYSTEM_FORBID_REPETITION_SUBMIT).content("禁止重复提交!").build());
}
private ActionForward executeUpload(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
try {
Object result = invokeAction(getMethodName(request), null, mapping, form, request, response);
if (result == null) {
WebUtils.writeJson(response, ResponseMsgBuilder.buildSuccessJsonMsg());
} else if (result instanceof ActionForward) {
return (ActionForward) result;
} else {
WebUtils.writeJson(response, ResponseMsgBuilder.buildSuccessJsonMsg(result));
}
} catch (Exception e) {
LOGGER.error(e.getCause());
String msg = ResponseMsgBuilder.buildErrorJsonMsg(e);
WebUtils.writeJson(response, msg);
}
return WebUtils.NULLActionForward;
}
private ActionForward executeStruts(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
if (form == null) {
return mapping.findForward(Constants.LOGIN_KEY);
}
try {
return (ActionForward) invokeAction(getMethodName(request), null, mapping, form, request, response);
} catch (Exception e) {
LOGGER.error(e.getCause());
try {
LOGGER.error(JsonUtils.toString(form));
} catch (Exception exception) {
LOGGER.error("Failed to serialize form:" + form.getClass().getName());
}
request.setAttribute(Constants.MESSAGE_ERROR, ResponseMsgBuilder.buildErrorJsonMsg(e));
try {
return (ActionForward) invokeAction(inItMethod(), null, mapping, form, request, response);
} catch (Exception se) {
LOGGER.error(e.getCause());
return (mapping.findForward(Constants.ERROR_KEY));
}
}
}
private String getMethodName(HttpServletRequest request) {
String methodName = request.getParameter("action");
methodName = StringUtils.isEmpty(methodName) ? inItMethod() : methodName;
return methodName;
}
/**
* 执行Ajax请求
*
* @return
*/
private ActionForward executeAjax(ActionMapping mapping, ActionForm form, HttpServletRequest request,
HttpServletResponse response) {
String msg = null;
try {
msg = getMsg4Request(request.getInputStream());
Assert.isFalse(StringUtils.isEmpty(msg),
Errors.create().key(MessageIdList.SYSTEM_MISSING_JSON).content("请求中没有json数据!").build());
Request msgReq = JsonUtils.toObject(msg, Request.class);
RequestHeader header = msgReq.getHead();
verificationParameter(header, request);
String methodName = header.getMethod();
try {
Object result = invokeAction(methodName, msg, mapping, form, request, response);
if (result == null) {
WebUtils.writeJson(response, ResponseMsgBuilder.buildSuccessJsonMsg(header));
} else if (result instanceof ActionForward) {
return (ActionForward) result;
} else {
WebUtils.writeJson(response, ResponseMsgBuilder.buildSuccessJsonMsg(result, header));
}
} catch (Exception e) {
LOGGER.error(msg);
LOGGER.error(e.getCause());
msg = ResponseMsgBuilder.buildErrorJsonMsg(e);
WebUtils.writeJson(response, msg);
}
} catch (Exception e) {
LOGGER.error(msg);
LOGGER.error(e);
msg = ResponseMsgBuilder.buildErrorJsonMsg(e);
WebUtils.writeJson(response, msg);
}
return WebUtils.NULLActionForward;
}
/**
* 判断是否在白名单
*
* @param request
* @return 存在: true ,不存在:false
*/
private boolean isWhitelisted(HttpServletRequest request) {
boolean result = false;
String[] excludes = {"login.do", "i18nService.do", "/actuator/health"};
String[] requestPath = StringUtils.split(request.getServletPath(), "/");
result = Arrays.asList(excludes).contains(requestPath[requestPath.length - 1]);
return result;
}
/**
* 校验 msg中head的数据
*
* @param header requestHead
*/
private void verificationParameter(RequestHeader header, HttpServletRequest request) {
String userId = header.getUserId();
long facility = header.getFacility();
String methodName = header.getMethod();
String transactionId = header.getTransactionId();
if (!isWhitelisted(request)) {
Assert.state(StringUtils.isNotEmptyTrim(userId),
Errors.create().key(MessageIdList.SYSTEM_MISSING_USERID).content("缺少请求用户信息!").build());
Assert.state(facility > 0,
Errors.create().key(MessageIdList.SYSTEM_MISSING_FACILITY).content("缺少请求区域信息!").build());
}
Assert.state(StringUtils.isNotEmptyTrim(methodName),
Errors.create().key(MessageIdList.SYSTEM_MISSING_METHOD).content("缺少请求方法!").build());
Assert.state(StringUtils.isNotEmptyTrim(transactionId),
Errors.create().key(MessageIdList.SYSTEM_MISSING_TRANSACTION).content("缺少请求transactionId!")
.build());
}
/**
* 从request中提取json消息
*/
private String getMsg4Request(InputStream inputRequest) throws Exception {
StringBuilder jsonMsg = new StringBuilder();
String readerLine = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputRequest))) {
while (StringUtils.isNotEmpty(readerLine = reader.readLine())) {
jsonMsg.append(readerLine).append("/n");
}
}
return jsonMsg.toString();
}
/**
* 反射action中具体的业务方法
*
* @param methodName 业务方法名
* @param jsonData json数据
* @return 业务处理结果
*/
private Object invokeAction(String methodName, String jsonData, ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
// 检测url 合法
checkUrl(request);
Method method = getMethod(methodName);
Assert.state(method != null, Errors.create().key(MessageIdList.SYSTEM_INVALID_METHOD).content("执行方法无效,{}")
.args(String.valueOf(methodName)).build());
List<Class<?>> types = Arrays.asList(method.getParameterTypes());
Assert.state(types.size() <= (StringUtils.isNotEmpty(jsonData) ? 1 : 0) + 4,
Errors.create().key(MessageIdList.SYSTEM_INVALID_METHOD).content("执行方法无效,{}").build());
List<Object> parameters = new ArrayList<>();
for (Class<?> type : types) {
if (type.isInstance(request)) {
parameters.add(request);
} else if (type.isInstance(response)) {
parameters.add(response);
} else if (type.isInstance(mapping)) {
parameters.add(mapping);
} else if (type.isInstance(form) && StringUtils.isEmpty(jsonData)) {
filterSpecialChar(form);
parameters.add(form);
} else {
Object body = JsonUtils.getValue2Bean(jsonData, type, "body");
filterSpecialChar(body);
parameters.add(body);
}
}
return method.invoke(this, parameters.toArray());
}
final private Function<String,ReferenceFileDetail> queryConfigRegex = (String key1)->{
List<ReferenceFileDetail> referenceFileDetails= Optional.ofNullable( sysService.getRefFileValues("$$SYS_PARAMETER", LocalContext.getFacilityRrn())).orElse(Arrays.asList());
Supplier<ReferenceFileDetail> getDefaultConfig = ()->{//系统缺省配置
ReferenceFileDetail referenceFileDetail = new ReferenceFileDetail();
referenceFileDetail.setKey1Value("JAVA");
//默认正则
referenceFileDetail.setData1Value(SystemConstant.Str.SPECIAL_CHAR);
//英文提示
referenceFileDetail.setData2Value("The characters must be letters or digits or hyphens(-) or underscores(_) or at(@) or slash(/) or dollar($) or percent(%) or comma(.) or brackets(()) or question mark(?)");
//中文提示
referenceFileDetail.setData3Value("字符必须是字母或数字或连字符 (-) 或下划线 (_) 或 at(@) 或斜杠 (/) 或美元 ($) 或百分比 (%) 或英文小数点(.) 或括号(()) 或问号(?)");
return referenceFileDetail;
};
//库中得配置如果查询不到,则使用代码中得缺省配置
return referenceFileDetails.stream().filter(e->StringUtils.equalsIgnoreCase("JAVA",e.getKey1Value())).findFirst().orElseGet(getDefaultConfig);
};
protected void filterSpecialChar(Object bean){
//for循环防止频繁查询
ReferenceFileDetail referenceFileDetail = null;
try {
Class<?> clazz = bean.getClass();
for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
Field[] field = clazz.getDeclaredFields();
//目前属性中字段的各种检查只有instanceId
//找到instanceId 后检查,直接return
//如果后面扩展为一个对象多个字段检查,则需要缓存系统中配置的正则
for (Field f : field) {
PropertyDescriptor pd = null;
try {
pd = new PropertyDescriptor(f.getName(), clazz);
}catch (IntrospectionException e) {
continue;
}
Method readMethod = pd.getReadMethod();
if(readMethod == null){
continue;
}
if(bean instanceof RootForm){
RootForm rootForm = (RootForm)bean;
if(Optional.ofNullable(rootForm.getSkipIdCheck()).orElse(false)){//跳过检查属性
return;
}
}
Object invoke = readMethod.invoke(bean);
SpecialCharValidater annotation = f.getAnnotation(SpecialCharValidater.class);
if(annotation != null && invoke instanceof String && StringUtils.isNotEmpty((String)invoke)){
String regexStr = annotation.value();
//功能模块特殊配置得正则 验证
if(StringUtils.isNotBlank(regexStr)){
Assert.state(Pattern.matches(regexStr,(String)invoke),
Errors.create().key(annotation.msgId())
.content("The characters must be letters or digits or hyphens(-) or underscores(_) or at(@) or slash(/) or dollar($) or percent(%) or comma(.) or brackets(()) or question mark(?)").args(invoke).build());
return;
}
//系统全局配置得缺省正则
if(referenceFileDetail==null){
referenceFileDetail=queryConfigRegex.apply("JAVA");//初始化类表中配置
}
String language = I18nUtils.getCurrentLanguage().name();
String content = StringUtils.equalsIgnoreCase(language,"EN")?referenceFileDetail.getData2Value(): referenceFileDetail.getData3Value();
Assert.state(Pattern.matches(referenceFileDetail.getData1Value(),(String)invoke),
Errors.create().content(content).args(invoke).build());
return;
}
}
}
} catch (InvocationTargetException | IllegalAccessException e) {
LOGGER.error(e);
}
};
/**
* 拿到当前类中的方法
*
* @param methodName 方法名
* @return Method
*/
private Method getMethod(String methodName) {
Method[] methods = this.getClass().getMethods();
if (ArrayUtils.isNotEmpty(methods)) {
for (Method method : methods) {
if (method.getName().equalsIgnoreCase(methodName)) {
return method;
}
}
}
return null;
}
/**
* 判断ajax请求
*
* @return
*/
private boolean isAjax(HttpServletRequest request) {
return (request.getHeader("X-Requested-With") != null &&
"XMLHttpRequest".equals(request.getHeader("X-Requested-With")));
}
/**
* @param optionKeys
* @return
*/
private List buildComboxDatasKey(Collection optionKeys) {
List comboxData = new ArrayList();
for (Object optionKey : optionKeys) {
Map<String, Object> jsonObject = new HashMap<>();
String[] _temp = (String[]) optionKey;
String key = _temp[0];
jsonObject.put("key", key);
jsonObject.put("value", key);
comboxData.add(jsonObject);
}
return comboxData;
}
/**
* @param optionValues
* @return
*/
protected List buildComboxDatas(Collection optionValues) {
List comboxData = new ArrayList();
for (Object optionValue : optionValues) {
Map<String, Object> jsonObject = new HashMap<>();
String[] _temp = (String[]) optionValue;
String key = _temp[0];
String value = _temp[1];
jsonObject.put("key", key);
jsonObject.put("value", value);
comboxData.add(jsonObject);
}
return comboxData;
}
/**
* 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
* 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?
* 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130,
* 192.168.1.100 用户真实IP为: 192.168.1.110
*
* @return
*/
protected String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("X-Real-IP");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Forwarded-For");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
protected void doCopy(RootForm theForm, NamedObject instance) throws Exception {
String origId = theForm.getInstanceId();
instance = getInstance(instance);
// populate the new information thru the new instance id
PropertyUtils.copyProperties(theForm, instance);
// and restore the original Id
theForm.setInstanceId(origId);
}
protected NamedObject getInstance(NamedObject instance) {
return instance;
}
protected long getInstanceRrn(String instanceId, String namedSpace, String object, String objectType) {
if (instanceId != null) {
return baseService.getNamedObjectRrn(instanceId.toUpperCase(), namedSpace, object, objectType);
} else {
return 0;
}
}
protected long getInstanceRrn(String instanceId, String namedSpace, String object, String objectType,
String subType) {
if (instanceId != null) {
return baseService.getNamedObjectRrn(instanceId.toUpperCase(), namedSpace, object, objectType, subType);
} else {
return 0;
}
}
protected String getInstanceDesc(long instanceRrn) {
return baseService.getInstanceDesc(instanceRrn);
}
protected Map<String,String> getInstanceDesc(Set<String> instanceIds,String namedSpace,String object){
return baseService.getInstanceDesc(instanceIds,namedSpace,object);
}
/**
* @param referenceFileId
* @param key1Value
* @param facilityRrn
* @return
*/
protected ReferenceFileDetail getReferenceFileDetail(String referenceFileId, String key1Value, Long facilityRrn) {
return getReferenceFileDetail(referenceFileId, key1Value, " ", facilityRrn);
}
protected List<ReferenceFileDetail> getReferenceFileDetails(String referenceFileId) {
long namedObjectRrn = baseService.getNamedObjectRrn(referenceFileId,
getNamedSpace(ObjectList.REFERENCE_FILE_KEY,
LocalContext.getFacilityRrn()),
ObjectList.REFERENCE_FILE_KEY);
List<ReferenceFileDetail> referenceFileDetails = sysService.getReferenceFileDetails(namedObjectRrn);
return referenceFileDetails;
}
protected ReferenceFileDetail getReferenceFileDetail(String referenceFileId, String key1Value, String key2Value,
Long facilityRrn) {
ReferenceFileDetail referenceFileDetail = new ReferenceFileDetail(referenceFileId,
getNamedSpace(ObjectList.REFERENCE_FILE_KEY,
facilityRrn),
ObjectList.REFERENCE_FILE_KEY);
referenceFileDetail.setKey1Value(key1Value);
referenceFileDetail.setKey2Value(key2Value);
referenceFileDetail = sysService.getReferenceFileDetail(referenceFileDetail);
return referenceFileDetail;
}
protected String getNamedSpace(String type, Long facility) {
return baseService.getNamedSpace(facility, type);
}
protected String getEcnFlag() {
Facility facility = sysService.getFacility(LocalContext.getFacilityRrn());
return facility.getEcnFlag() != null ? facility.getEcnFlag() : "0";
}
protected String getInstanceId(long instanceRrn) {
return baseService.getNamedObjectId(instanceRrn);
}
protected long getInstanceRrn(String instanceId, Long facilityRrn, String object) {
String namedSpace = baseService.getNamedSpace(facilityRrn, object);
return getInstanceRrn(instanceId, namedSpace, object);
}
protected long getInstanceRrn(String instanceId, String namedSpace, String object) {
if (instanceId != null) {
return baseService.getNamedObjectRrn(instanceId.toUpperCase(), namedSpace, object);
} else {
return 0;
}
}
protected void processItemAction(HttpServletRequest request, RootForm theForm) {
if (theForm.getPages() == null) {
theForm.setPages(1);
}
if (request.getParameter(Constants.FIRST_KEY) != null) {
theForm.setPages(1);
} else if (request.getParameter(Constants.PREV_KEY) != null) {
theForm.setPages(theForm.getPages() - 1);
} else if (request.getParameter(Constants.NEXT_KEY) != null) {
theForm.setPages(theForm.getPages() + 1);
} else if (request.getParameter(Constants.LAST_KEY) != null) {
theForm.setPages(-1);
} else {
theForm.setPages(1);
}
}
protected void registerOptionType(Long facilityRrn, Collection types, HttpServletRequest request) {
Map<String, Object> reponseData = new HashMap<>();
for (Object o : types) {
String type = (String) o;
Collection optionValues = getOptionTypeList(facilityRrn, type);
if (optionValues != null) {
List comboxData;
if (StringUtils.equals(type, "PROCESSLOCATION")) {// PROCESSLOCATION显示KEY,value由于使用判断
comboxData = buildComboxDatasKey(optionValues);
} else {
comboxData = buildComboxDatas(optionValues);
}
reponseData.put(type, comboxData);
}
}
put("COMBOXDATAS", JsonUtils.toString(reponseData), request);
}
protected Collection getOptionTypeList(Long facilityRrn, String type) {
OptionTypeList option = new OptionTypeList(type);
String where = option.getWhere();
if (option.getRefFile() != null) {
if (where != null) {
where = " NAMED_SPACE=coalesce((SELECT NAMED_SPACE FROM NAMED_SPACE_DEFINITION WHERE " +
"FACILITY_RRN=" + facilityRrn + " AND OBJECT='REFERENCEFILE'),'MYCIM2') AND " + where;
} else {
where = " NAMED_SPACE=coalesce((SELECT NAMED_SPACE FROM NAMED_SPACE_DEFINITION WHERE " +
"FACILITY_RRN=" + facilityRrn + " AND OBJECT='REFERENCEFILE'),'MYCIM2')";
}
}
Collection optionValues = sysService
.getOption(option.getValue(), option.getText(), option.getTable(), option.getRefFile(), where);
return optionValues;
}
protected void put(String name, Object value, HttpServletRequest request) {
request.setAttribute(name, value);
}
protected String getObjectValue(long instanceRrn, String fieldId) {
String result = sysService.getObjectAttributeValue(instanceRrn, 1, getInstanceRrn(fieldId, getNamedSpace(
ObjectList.FIELD_KEY, LocalContext.getFacilityRrn()), ObjectList.FIELD_KEY));
return StringUtils.trimToEmpty(result);
}
protected <T extends NamedObject> T setDefaultParam(NamedObject namedObject) {
boolean isCreate = Constants.CREATE_KEY.equalsIgnoreCase(namedObject.getTransId()) ||
Constants.ADD_KEY.equalsIgnoreCase(namedObject.getTransId());
namedObject.setCreatedUserRrn(isCreate ? LocalContext.getUserRrn() : null);
namedObject.setFacilityRrn(isCreate ? LocalContext.getFacilityRrn() : 0L);
namedObject.setLastUpdateUserRrn(LocalContext.getUserRrn());
return (T) namedObject;
}
protected <T extends ActionForm> T getForm(ActionForm actionForm){
return (T) actionForm;
}
/**
* 验证特殊字符
* @param inputStr
* @return
*/
protected String validateSpecialChar(String inputStr) {
if (!Pattern.matches(SystemConstant.Str.SPECIAL_CHAR, inputStr)) {
String message = I18nUtils.getMessage(MessageIdList.SYSTEM_ALLOW_SPECIAL_CHAR_WITH_KEY,
"({}) The characters must be letters or digits or hyphens(-) or " +
"underscores(_) or at(@) or slash(/) or dollar($) or percent(%) or comma(.)",
inputStr);
return message;
}
return StringUtils.EMPTY;
}
protected boolean isSpecialRole() {
return Boolean.parseBoolean(LocalContext.get(SystemConstant.Str.SPECIAL_ROLE));
}
}