Skip to content

[Core] CallActivity (SubProcessActivity)

Jinyoung Jang edited this page Sep 20, 2016 · 3 revisions

CallActivity 와 SubProcessActivity

CallActivity 는 BPMN 에서 프로세스를 호출하여 재사용하는 액티비티이며 Old uEngine 에서는 SubProcessActivity 로 알려져 있다. BPMN 에서는 SubActivity 가 메인프로세스 정의 내에 직접 정의되도록 되어있기 때문에 이 둘을 구분하고 있기 때문에 혼동하지 않기로 한다. uEngine5 상에서는 CallActivity 는 아래와 같이 단순히 기존 uEngine 의 SubProcessActivity 를 상속하여 제공하고 있다.


public class CallActivity extends SubProcessActivity{

    public CallActivity() {
        super();
        setName("Call");
    }

}


SubProcessActivity 의 Design-time 지원

FieldDescriptor 정의

uEngine5 버전에서는 metaworks3 기반의 웹기반 프로세스 모델러를 지원하기 때문에 metaworks annotation 을 사용하여 필드 속성을 지원하도록 변경이 필요했다.

[Note] 기존 SubProcessActivity 의 멀티플 인스턴스 기능은 새버전의 org.uengine.kernel.bpmn.SubProcess 로 기능을 다 옮겼기 때문에 멀티플 인스턴스 관련된 프로퍼티들 (forEachRole, forEachVariable ...) 은 모두 Hidden 시킨다.


package org.uengine.kernel;


public class SubProcessActivity extends DefaultActivity {

	public SubProcessActivity(){
		super();
		setName("Call");
		setDescription("");
		setInstanceId("<%=Instance.Name%>");
	}

	String instanceId;
	@Hidden
	public String getInstanceId() {
		return instanceId;
	}
	public void setInstanceId(String string) {
		instanceId = string;
	}

	String alias;
	@Hidden
	public String getAlias() {
		return alias;
	}
	public void setAlias(String alias) {
		this.alias = alias;
	}

	String definitionId;
		@Face(faceClassName = "org.uengine.social.SocialBPMProcessDefinitionSelector")
		@Hidden(on=false)
		public String getDefinitionId() {
			return definitionId;
		}
		public void setDefinitionId(String l) {
			definitionId = l;
		}



	ParameterContext[] variableBindings;
		@Face(faceClass = SubProcessParameterContextArrayFace.class)
		public ParameterContext[] getVariableBindings() {
			return variableBindings;
		}
		public void setVariableBindings(ParameterContext[] contexts) {
			variableBindings = contexts;
		}

	RoleParameterContext[] roleBindings;
	@Face(faceClass = RoleParameterContextArrayFace.class)
		public RoleParameterContext[] getRoleBindings() {
			return roleBindings;
		}
		public void setRoleBindings(RoleParameterContext[] contexts) {
			roleBindings = contexts;
		}





	TextContext multipleInstanceLabel = org.uengine.contexts.TextContext.createInstance();
	@Hidden
	public TextContext getMultipleInstanceLabel() {
		return multipleInstanceLabel;
	}
	public void setMultipleInstanceLabel(TextContext multipleInstanceLabel) {
		this.multipleInstanceLabel = multipleInstanceLabel;
	}

	Role forEachRole;
	@Hidden
	public Role getForEachRole() {
		return forEachRole;
	}
	public void setForEachRole(Role role) {
		forEachRole = role;
	}

	ProcessVariable forEachVariable;
	@Hidden
	public ProcessVariable getForEachVariable() {
		return forEachVariable;
	}
	public void setForEachVariable(ProcessVariable forEachVariable) {
		this.forEachVariable = forEachVariable;
	}

...


}




변수 매핑을 위한 ParameterContext 의 Design-time 지원

ParameterContext (SubProcessParameterContext) 에는 메인프로세스와 서브프로세스 간의 변수를 연결해주어야 하는 두가지 값 - argument, variable 값을 멤버값을 갖는다. 디자인 타임에서는 이를 selectBox 로 선택할 수 있는 편의성의 UI 를 제공해야 한다. 이의 선택을 위하여 SubProcessActivity 에서 선택된 definitionId 를 참고해와서 동적으로 Argument 의 selectBox 로 만들어주고, variable 값도 selectbox 로 가져와야 한다. 이를 위하여 faceClass 두개를 선언하고 있는데, org.uengine.kernel.face.ParameterContextArgumentFace 와 ProcessVariableSelectorFace 이다.

ParameterContext.java


package org.uengine.kernel;

public class ParameterContext implements Serializable , ContextAware{
	
	TextContext argument = org.uengine.contexts.TextContext.createInstance();
	@Face(faceClass = org.uengine.kernel.face.ParameterContextArgumentFace.class)
		public TextContext getArgument() {
			if(argument!=null && argument.getText()==null && getVariable()!=null){
				return getVariable().getDisplayName();
			}
			
			return argument;
		}
		public void setArgument(TextContext string) {
			argument = string;
		}

	ProcessVariable variable;
	@Face(faceClass = ProcessVariableSelectorFace.class)
		public ProcessVariable getVariable() {
			return variable;
		}
		public void setVariable(ProcessVariable variable) {
			this.variable = variable;
		}

	
	String direction;
	@Range(options={"IN-OUT", "IN", "OUT", }, values={ "in-out", "in", "out",})
		public String getDirection() {
			return direction;
		}
		public void setDirection(String i) {
			direction = i;
		}
		
 ....
}


ParameterContextArgumentFace.java

ParameterContextArgumentFace 는 ParameterContext 의 argument 를 입력할 때 셀렉트박스로 UI 를 만들어준다. argument 리스트는 선택된 프로세스 정의에 따라 달라지므로, loadOptions 메서드를 구현해주어 해당 목록을 selectBox 가 열릴때 동적으로 구성하도록 만들어주었다. 참고 : SelectBox 컴포넌트 이 때 아규먼트로 Activity 와 ISession 을 가져오는데, 현재 화면에 설정값으로 열려진 Activity (SubProcessActivity 혹은 SubActivity 중 하나 일 것이다) 를 AutowiredFromClient 해야 하고, ISession을 같이 가져오는 이유는 Codi SNS Framework 에선 payload 에 Session 이 있어야 현재 로그인한 태넌트 정보 (유저정보를 포함한) 의 정보를 얻어와서 어떤 태넌트인지를 식별할 수 있기 때문에 (태넌트를 식별해야지만 정확히 어떤 위치에 프로세스 정의를 읽어야 할지 알 수 있다) 같이 포함하여 Autowire from client 한다.

package org.uengine.kernel.face;

public class ParameterContextArgumentFace extends SelectBox implements Face<TextContext> {


    @Override
    public void setValueToFace(TextContext value) {

        if(value!=null) {
            setSelected(value.getText());
        }
    }

    @Override
    public TextContext createValueFromFace() {

        if(getSelected()==null)
            return null;

        TextContext textContext = TextContext.createInstance();
        textContext.setText(getSelected());

        return textContext;
    }

    @ServiceMethod()
    public void loadOptions(@Payload("selected") String selected, @AutowiredFromClient Activity activity, @AutowiredFromClient ISession session){

        setMetaworksContext(new MetaworksContext());
        getMetaworksContext().setWhen(MetaworksContext.WHEN_EDIT);

        if(activity instanceof SubProcessActivity){
            SubProcessActivity subProcessActivity = (SubProcessActivity) activity;

            String subProcessDefinitionId = subProcessActivity.getDefinitionId();

            if(subProcessDefinitionId==null) return;

            ProcessManagerRemote processManagerRemote = MetaworksRemoteService.getComponent(ProcessManagerRemote.class);
            try {
                ProcessDefinition processDefinition = processManagerRemote.getProcessDefinition(subProcessDefinitionId);

                if(processDefinition.getProcessVariables()!=null){

                    setOptionValues(new ArrayList<String>());
                    setOptionNames(new ArrayList<String>());

                    for(ProcessVariable processVariable : processDefinition.getProcessVariables()){
                        getOptionValues().add(processVariable.getName());
                        getOptionNames().add(processVariable.getDisplayName().getText(session.getLocale()));
                    }

                    setSelected(selected);
                }


            } catch (RemoteException e) {
                throw new RuntimeException("Failed to get process definition object :" + e.getMessage(), e);
            }
        }

    }
}


ProcessVariableSelectorFace.java

ParameterContext 의 variable 선택 (입력 변수) 을 위한 Select Box 는 ProcessVariablePanel 을 AutowiredFromClient 하는 것으로 충분히 목록을 얻어올 수 있다.


public class ProcessVariableSelectorFace extends SelectBox implements Face<ProcessVariable> {

    @AutowiredFromClient
    public ProcessVariablePanel processVariablePanel;

    @Override
    public void setValueToFace(ProcessVariable value) {

        if(processVariablePanel!=null && processVariablePanel.getProcessVariableList() !=null){
            ArrayList<String> options = new ArrayList<String>();

            for(ProcessVariable processVariable : processVariablePanel.getProcessVariableList()){
                options.add(processVariable.getName());
            }
            setOptionNames(options);
            setOptionValues(options);
        }

        if(value!=null){
            if(getOptionNames()==null || getOptionNames().size() == 0){
                ArrayList<String> options = new ArrayList<String>();
                options.add(value.getName());
                setOptionNames(options);
                setOptionValues(options);
            }
            setSelectedValue(value.getName());
            setSelectedText(value.getName()); //sometimes the value can contains "."
        }
    }

    @Override
    public ProcessVariable createValueFromFace() {
        String variableName = getSelectedText();

        return ProcessVariable.forName(variableName);
    }
}


롤 매핑을 위한 RoleParameterContext 의 Design time 지원

변수 매핑과 마찬가지로 Role 매핑을 위한 RoleParameterContext 에도 각 argument 와 role 에 대한 face 를 각각 구현해주었다.

RoleParameterContext.java


package org.uengine.kernel;

public class RoleParameterContext implements Serializable{

	String argument;
	@Face(faceClass = RoleParameterContextArgumentFace.class)
		public String getArgument() {
			return argument;
		}
		public void setArgument(String string) {
			argument = string;
		}

	Role role;
	@Face(faceClass=RoleSelectorFace.class)
		public Role getRole() {
			return role;
		}	
		public void setRole(Role role) {
			this.role = role;
		}

	String direction;
	@Range(options={"IN-OUT", "IN", "OUT", }, values={ "in-out", "in", "out",})
		public String getDirection() {
			return direction;
		}
		public void setDirection(String direction) {
			this.direction = direction;
		}
		
	boolean split;
		public boolean isSplit() {
			return split;
		}
		public void setSplit(boolean split) {
			this.split = split;
		}
	
}

RoleParameterContextArgumentFace.java

앞서 ParameterContext 의 Argument face 와 유사하지만 변수목록을 갖고 오는 것이 아니라 롤 정의 목록을 가져오는 차이가 있다.


package org.uengine.kernel.face;

public class RoleParameterContextArgumentFace extends SelectBox implements Face<String> {
    @Override
    public void setValueToFace(String value) {
        setSelected(value);
    }

    @Override
    public String createValueFromFace() {
        return getSelected();
    }

    @ServiceMethod(onLoad=true)
    public void onLoad(@Payload("selected") String selected, @AutowiredFromClient Activity activity, @AutowiredFromClient ISession session){

        setMetaworksContext(new MetaworksContext());
        getMetaworksContext().setWhen(MetaworksContext.WHEN_EDIT);

        if(activity instanceof SubProcessActivity){
            SubProcessActivity subProcessActivity = (SubProcessActivity) activity;

            String subProcessDefinitionId = subProcessActivity.getDefinitionId();

            if(subProcessDefinitionId==null) return;

            ProcessManagerRemote processManagerRemote = MetaworksRemoteService.getComponent(ProcessManagerRemote.class);
            try {
                ProcessDefinition processDefinition = processManagerRemote.getProcessDefinition(subProcessDefinitionId);

                if(processDefinition.getRoles()!=null){

                    setOptionValues(new ArrayList<String>());
                    setOptionNames(new ArrayList<String>());

                    for(Role role : processDefinition.getRoles()){
                        getOptionValues().add(role.getName());
                        getOptionNames().add(role.getDisplayName().getText(session.getLocale()));
                    }

                    setSelected(selected);
                }


            } catch (RemoteException e) {
                throw new RuntimeException("Failed to get process definition object :" + e.getMessage(), e);
            }
        }

    }
}


RoleSelectorFace.java

Role Selector 의 경우는 변수와 다르게 별도의 Role정의 Panel이 존재하는 것이 아니라 Canvas 자체에 정의된 스윔래인 정의를 그때그때 얻어야 하기 때문에 Canvas 를 통째로 얻어온 후, Canvas 내용을 파싱하여 Role 정의 리스트를 뽑아내야 하는 수고가 존재한다. 다행이 이를 위한 유틸리티 메서드가 구현되어 있다. 하지만 Canvas 내에 아주 많은 량의 오브젝트가 존재하는 경우 서버에 왔다갔다 하는 오브젝트 사이즈가 매우 무거워 질 수 있기 때문에 가능한 @AutowiredFromClient(beanPath="") 부분에서 오브젝트 사이즈를 줄여서 서버로 보내 주고 있다. (그러나 메타웍스는 이 옵션을 무시하고 통째로 보낼 것이다. 구현 예정이다)

package org.uengine.kernel.face;

public class RoleSelectorFace extends SelectBox implements Face <Role>{

    @AutowiredFromClient(beanPath = "elementViewList[__className=='org.uengine.kernel.Role'].(name, displayName), id")
    public Canvas canvas;


    @Override
    public void setValueToFace(Role value) {


        if(canvas != null){
            List<Role> roleList = MappingTree.parseRoles(canvas);

            if(roleList !=null) {
                ArrayList<String> options = new ArrayList<String>();

                for (Role role : roleList) {
                    options.add(role.getName());
                }

                setOptionNames(options);
                setOptionValues(options);
            }
        }

        if(value != null) {
            if(getOptionNames() == null || getOptionNames().size() == 0){
                ArrayList<String> options = new ArrayList<String>();
                options.add(value.getName());
                setOptionNames(options);
                setOptionValues(options);
            }
            setSelectedValue(value.getName());
        }

        setMetaworksContext(new MetaworksContext());
        getMetaworksContext().setWhen(MetaworksContext.WHEN_EDIT);
    }

    @Override
    public Role createValueFromFace() {
        String roleName = getSelectedText();

        return Role.forName(roleName);
    }

    @ServiceMethod(inContextMenu = true)
    public void loadOptions(@Payload("selected") String selected){
        setValueToFace(Role.forName(selected));
    }
}