2017-05-02 7 views
1

팀, 스프링 웹 플로우를 1.x에서 2.4로 업그레이드 중입니다.spring webflow 2.x - 단일 스냅 샷을 사용하기 위해 alwaysGenerateNewNextKey를 false로 설정하는 방법

SWF 1.x에서는 전체 세션에 대해 하나의 flowExecutionKey 만 사용했으며 뒤로 탐색을 비활성화했습니다.

는 SWF 2.4에서 우리는,

우리는 아래와 같이 0으로 최대 - 실행 - 스냅 샷을 구성하여 스냅 샷을 비활성화 할 수 있었다, 같은 동작을하는
<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry"> 
    <webflow:flow-execution-repository max-executions="1" max-execution-snapshots="0"/> 
</webflow:flow-executor> 

그러나 탐색에

를 원했다 스냅 샷 ID는,

AbstractFlowExecutionRepository

때 진정한마다 탐색을위한 새로운 snapshotId을 생성하는 데 도움이 필드 아래에있다, 우리는이 문제를 조사 할 때, 문제의 원인이되는 (like e1s1, e1s2 ...)을 계속 증가

alwaysGenerateNewNextKey 기본적으로 true입니다.

SWF 1.x에는 RepositoryType.SINGLEKEY을 통해 false로 설정할 수있는 옵션이 있지만 SWF 2.4에서는이 값을 false로 설정할 수있는 방법이 없습니다. 여기가 지금 "alwaysGenerateNewNextKey"

답변

0

내가이 못생긴 것을 알고 덮어 쓸 수있는 방법이지만, 경우

당신이 할 수있는 일입니다 도와주세요 : 그 이름을

FlowExecutorFactoryBeanFlowElementAttribute의 자신의 복사본을 만듭니다 MyFlowExecutorFactoryBeanMyFlowElementAttribute (MyFlowExecutorFactoryBean에서 FlowElementAttribute에서 MyFlowElementAttribute으로 변경 참조).

<bean id="flowExecutor" class="com.example.MyFlowExecutorFactoryBean "> 
    <property name="flowDefinitionLocator" ref="flowRegistry" /> 
    <property name="flowExecutionListenerLoader"> 
    <bean class="org.springframework.webflow.config.FlowExecutionListenerLoaderFactoryBean"> 
     <property name="listeners"> 
     <map> 
      <entry key-ref="yourFirstListener" value="*" /> 
      <entry key-ref="yourSecondListener" value="*" /> 
     </map> 
     </property> 
    </bean> 
    </property> 
</bean> 

I의 천국 '

public class MyFlowExecutorFactoryBean implements FactoryBean<FlowExecutor>, ApplicationContextAware, BeanClassLoaderAware, InitializingBean { 

    private static final String ALWAYS_REDIRECT_ON_PAUSE = "alwaysRedirectOnPause"; 

    private static final String REDIRECT_IN_SAME_STATE = "redirectInSameState"; 

    private FlowDefinitionLocator flowDefinitionLocator; 

    private Integer maxFlowExecutions; 

    private Integer maxFlowExecutionSnapshots; 

    private Set<MyFlowElementAttribute> flowExecutionAttributes; 

    private FlowExecutionListenerLoader flowExecutionListenerLoader; 

    private ConversationManager conversationManager; 

    private ConversionService conversionService; 

    private FlowExecutor flowExecutor; 

    private MvcEnvironment environment; 

    private ClassLoader classLoader; 

    /** 
    * Sets the flow definition locator that will locate flow definitions needed for execution. Typically also a 
    * {@link FlowDefinitionRegistry}. Required. 
    * @param flowDefinitionLocator the flow definition locator (registry) 
    */ 
    public void setFlowDefinitionLocator(FlowDefinitionLocator flowDefinitionLocator) { 
     this.flowDefinitionLocator = flowDefinitionLocator; 
    } 

    /** 
    * Set the maximum number of allowed flow executions allowed per user. 
    */ 
    public void setMaxFlowExecutions(int maxFlowExecutions) { 
     this.maxFlowExecutions = maxFlowExecutions; 
    } 

    /** 
    * Set the maximum number of history snapshots allowed per flow execution. 
    */ 
    public void setMaxFlowExecutionSnapshots(int maxFlowExecutionSnapshots) { 
     this.maxFlowExecutionSnapshots = maxFlowExecutionSnapshots; 
    } 

    /** 
    * Sets the system attributes that apply to flow executions launched by the executor created by this factory. 
    * Execution attributes may affect flow execution behavior. 
    * @param flowExecutionAttributes the flow execution system attributes 
    */ 
    public void setFlowExecutionAttributes(Set<MyFlowElementAttribute> flowExecutionAttributes) { 
     this.flowExecutionAttributes = flowExecutionAttributes; 
    } 

    /** 
    * Sets the strategy for loading the listeners that will observe executions of a flow definition. Allows full 
    * control over what listeners should apply to executions of a flow definition launched by the executor created by 
    * this factory. 
    */ 
    public void setFlowExecutionListenerLoader(FlowExecutionListenerLoader flowExecutionListenerLoader) { 
     this.flowExecutionListenerLoader = flowExecutionListenerLoader; 
    } 

    /** 
    * Sets the service type that manages conversations and effectively controls how state is stored physically when a 
    * flow execution is paused. 
    */ 
    public void setConversationManager(ConversationManager conversationManager) { 
     this.conversationManager = conversationManager; 
    } 

    // implementing ApplicationContextAware 

    @Override 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 
     environment = MvcEnvironment.environmentFor(applicationContext); 
    } 

    // implement BeanClassLoaderAware 

    @Override 
    public void setBeanClassLoader(ClassLoader classLoader) { 
     this.classLoader = classLoader; 
    } 

    // implementing InitializingBean 

    @Override 
    public void afterPropertiesSet() throws Exception { 
     Assert.notNull(flowDefinitionLocator, "The flow definition locator property is required"); 
     if (conversionService == null) { 
      conversionService = new DefaultConversionService(); 
     } 
     MutableAttributeMap<Object> executionAttributes = createFlowExecutionAttributes(); 
     FlowExecutionImplFactory executionFactory = createFlowExecutionFactory(executionAttributes); 
     DefaultFlowExecutionRepository executionRepository = createFlowExecutionRepository(executionFactory); 
     executionRepository.setMaxSnapshots(0); 
     executionRepository.setAlwaysGenerateNewNextKey(false); 
     executionFactory.setExecutionKeyFactory(executionRepository); 
     flowExecutor = new FlowExecutorImpl(flowDefinitionLocator, executionFactory, executionRepository); 
    } 

    // implementing FactoryBean 

    @Override 
    public Class<?> getObjectType() { 
     return FlowExecutor.class; 
    } 

    @Override 
    public boolean isSingleton() { 
     return true; 
    } 

    @Override 
    public FlowExecutor getObject() throws Exception { 
     return flowExecutor; 
    } 

    private MutableAttributeMap<Object> createFlowExecutionAttributes() { 
     LocalAttributeMap<Object> executionAttributes = new LocalAttributeMap<Object>(); 
     if (flowExecutionAttributes != null) { 
      for (MyFlowElementAttribute attribute : flowExecutionAttributes) { 
       executionAttributes.put(attribute.getName(), getConvertedValue(attribute)); 
      } 
     } 
     putDefaultFlowExecutionAttributes(executionAttributes); 
     return executionAttributes; 
    } 

    private void putDefaultFlowExecutionAttributes(LocalAttributeMap<Object> executionAttributes) { 
     if (!executionAttributes.contains(ALWAYS_REDIRECT_ON_PAUSE)) { 
      Boolean redirect = environment != MvcEnvironment.PORTLET; 
      executionAttributes.put(ALWAYS_REDIRECT_ON_PAUSE, redirect); 
     } 
     if (!executionAttributes.contains(REDIRECT_IN_SAME_STATE)) { 
      Boolean redirect = environment != MvcEnvironment.PORTLET; 
      executionAttributes.put(REDIRECT_IN_SAME_STATE, redirect); 
     } 
    } 

    private DefaultFlowExecutionRepository createFlowExecutionRepository(FlowExecutionFactory executionFactory) { 
     ConversationManager conversationManager = createConversationManager(); 
     FlowExecutionSnapshotFactory snapshotFactory = createFlowExecutionSnapshotFactory(executionFactory); 
     DefaultFlowExecutionRepository rep = new DefaultFlowExecutionRepository(conversationManager, snapshotFactory); 
     if (maxFlowExecutionSnapshots != null) { 
      rep.setMaxSnapshots(maxFlowExecutionSnapshots); 
     } 
     return rep; 
    } 

    private ConversationManager createConversationManager() { 
     if (conversationManager == null) { 
      conversationManager = new SessionBindingConversationManager(); 
      if (maxFlowExecutions != null) { 
       ((SessionBindingConversationManager) conversationManager).setMaxConversations(maxFlowExecutions); 
      } 
     } 
     return this.conversationManager; 
    } 

    private FlowExecutionSnapshotFactory createFlowExecutionSnapshotFactory(FlowExecutionFactory executionFactory) { 
     if (maxFlowExecutionSnapshots != null && maxFlowExecutionSnapshots == 0) { 
      maxFlowExecutionSnapshots = 1; 
      return new SimpleFlowExecutionSnapshotFactory(executionFactory, flowDefinitionLocator); 
     } else { 
      return new SerializedFlowExecutionSnapshotFactory(executionFactory, flowDefinitionLocator); 
     } 
    } 

    private FlowExecutionImplFactory createFlowExecutionFactory(AttributeMap<Object> executionAttributes) { 
     FlowExecutionImplFactory executionFactory = new FlowExecutionImplFactory(); 
     executionFactory.setExecutionAttributes(executionAttributes); 
     if (flowExecutionListenerLoader != null) { 
      executionFactory.setExecutionListenerLoader(flowExecutionListenerLoader); 
     } 
     return executionFactory; 
    } 

    // utility methods 

    private Object getConvertedValue(MyFlowElementAttribute attribute) { 
     if (attribute.needsTypeConversion()) { 
      Class<?> targetType = fromStringToClass(attribute.getType()); 
      ConversionExecutor converter = conversionService.getConversionExecutor(String.class, targetType); 
      return converter.execute(attribute.getValue()); 
     } else { 
      return attribute.getValue(); 
     } 
    } 

    private Class<?> fromStringToClass(String name) { 
     Class<?> clazz = conversionService.getClassForAlias(name); 
     if (clazz != null) { 
      return clazz; 
     } else { 
      try { 
       return ClassUtils.forName(name, classLoader); 
      } catch (ClassNotFoundException e) { 
       throw new IllegalArgumentException("Unable to load class '" + name + "'"); 
      } 
     } 
    } 

    class MyFlowElementAttribute { 

     /** 
     * The name of the attribute. 
     */ 
     private String name; 

     /** 
     * The value of the attribute before type-conversion. 
     */ 
     private String value; 

     /** 
     * The attribute type, optional, but necessary for type conversion. 
     */ 
     private String type; 

     public MyFlowElementAttribute(String name, String value, String type) { 
      Assert.hasText(name, "The name is required"); 
      Assert.hasText(value, "The value is required"); 
      this.name = name; 
      this.value = value; 
      this.type = type; 
     } 

     public String getName() { 
      return name; 
     } 

     public String getValue() { 
      return value; 
     } 

     public String getType() { 
      return type; 
     } 

     public boolean needsTypeConversion() { 
      return type != null && type.length() > 0; 
     } 
    } 
} 

이제 webflow 구성에서이를 사용 결과 MyFlowExecutorFactoryBean에서

여기

setAlwaysGenerateNewNextKey(true)처럼 당신이 executionRepository에서 원하는 속성을 설정입니다 완전히 테스트했지만 작동해야합니다.

+0

정말 감사합니다. – Vijay

0

감사합니다,

<bean id="flowExecutionRepository" class="com.custom.module.SingleFlowExecutionRepository"> 
    <constructor-arg index="0" ref="conversationManager"/> 
    <constructor-arg index="1" ref="snapshotFactory"/> 
</bean> 

<bean id="flowExecutor" class="org.springframework.webflow.executor.FlowExecutorImpl"> 
    <constructor-arg index="0" ref="flowRegistry"/> 
    <constructor-arg index="1" ref="executionFactory" name="executionFactory"/> 
    <constructor-arg index="2" ref="flowExecutionRepository" name="executionRepository"/> 
</bean> 

그리고

공용 클래스 SingleFlowExecutionRepository가 {

DefaultFlowExecutionRepository 확장이 가능하다면 그것은 누군가가 도움이되기를 바랍니다 경우

나는 또한 DefaultFlowExecutionRepository 연장으로 문제를 해결 한

검토하시기 바랍니다

public SingleFlowExecutionRepository(ConversationManager conversationManager, 
     FlowExecutionSnapshotFactory snapshotFactory) { 
    super(conversationManager, snapshotFactory);   
    /** 
    * Set to maintain single snapshot for a session. 
    */ 
    super.setAlwaysGenerateNewNextKey(false); 
}