2015-06-02 17 views
5

Tôi đang giới thiệu Spring Statemachine vào một dự án hiện có, với hy vọng hợp nhất và làm rõ logic kinh doanh của chúng tôi. Chúng ta có các thực thể JPA khác nhau với các trạng thái kết nối và tôi đang gặp một số vấn đề với việc thiết lập trạng thái tồn tại trạng thái hiện tại của một máy trạng thái hiện có.Duy trì và khôi phục trạng thái hiện tại trong Spring Statemachine

Tôi đang sử dụng StateMachineFactory để tạo một thể hiện StateMachine mới cho mỗi cá thể thực thể. Tôi đang lưu trữ trạng thái hiện tại của StateMachine trong một trường riêng biệt cho Hibernate để tồn tại và lý tưởng là cần phải đồng bộ hóa giá trị của trường persisted với StateMachine. Câu hỏi của tôi là về việc làm thế nào để đạt được điều này trong Spring Statemachine.

@Entity 
@EntityListeners(MyEntityListener.class) 
public class MyEntity { 

    @Column 
    private MyState internalState; // Using AttributeConverter 

    @Transient 
    private StateMachine<MyState, Event> stateMachine; 

} 
public class MyEntityListener { 

    @PostLoad 
    public void postLoad(MyEntity entity) { 
     // TODO Set StateMachine's current state to entity's internal state 
    ); 

} 
  1. Một cách tiếp cận có thể để xác định chuyển địa phương để di chuyển các trạng thái ban đầu vào tình trạng tiếp tục tồn tại. Sau đó tôi có thể thực hiện kiểm tra có điều kiện để tìm một sự kiện gắn liền với một chuyển đổi cục bộ, điều này sẽ chuyển trạng thái nguồn vào trạng thái đích. Điều này có vẻ hơi lộn xộn với tôi và tôi muốn giữ cấu hình máy của tiểu bang của tôi càng sạch càng tốt. Tôi không thể thấy làm thế nào tôi có thể thiết lập trạng thái hiện tại của StateMachine thông qua một API công cộng mà không cần chuyển qua một quá trình chuyển đổi và một cách tiếp cận khác mà tôi khám phá là bao bọc thể hiện StateMachine để lộ phương thức sau đây (vì nó thuận tiện mặc định). phạm vi):

package org.springframework.statemachine.support; 

public abstract class AbstractStateMachine<S, E> extends StateMachineObjectSupport<S, E> implements StateMachine<S, E>, StateMachineAccess<S, E> { 

    void setCurrentState(State<S, E> state, Message<E> message, Transition<S, E> transition, boolean exit, StateMachine<S, E> stateMachine) 

} 
package org.springframework.statemachine.support; 

public class MyStateMachineWrapper<S, E> { 

    private AbstractStateMachine<S, E> stateMachine; 

    public MyStateMachineWrapper(StateMachine<S, E> stateMachine) { 
     if (stateMachine instanceof AbstractStateMachine) { 
      this.stateMachine = (AbstractStateMachine<S, E>)stateMachine; 
     } else { 
      throw new IllegalArgumentException("Provided StateMachine is not a valid type"); 
     } 
    } 

    public void setCurrentState(S status) { 
     stateMachine.setCurrentState(findState(status), null, null, false, stateMachine); 
    } 

    private State<S, E> findState(S status) { 
     for (State<S, E> state : stateMachine.getStates()) { 
      if (state.getId() == status) { 
       return state; 
      } 
     } 

     throw new IllegalArgumentException("Specified status does not equate to valid State"); 
    } 
} 

sau đó tôi có thể ném đoạn mã sau vào MyEntityListener.postLoad:

MyStateMachineWrapper<MyState, Event> myStateMachineWrapper = new MyStateMachineWrapper<>(entity.getStateMachine()); 
myStateMachineWrapper.setCurrentState(entity.getInternalState()); 

Phương pháp trên dường như hoạt động tốt nhưng tôi không thể tưởng tượng được đây là cách nó được hình dung để hoạt động. Chắc chắn có một phương pháp sạch hơn để đạt được điều này hoặc có lẽ dự án không đủ trưởng thành và chưa bao gồm chức năng này?

Cảm ơn mọi ý kiến ​​và ý kiến.

Trả lời

2

Tôi đã xóa tùy chọn # 2 ở trên, thay đổi lớp trình bao bọc thành lớp utils. Để rõ ràng, cách tiếp cận này tận dụng phương thức setCurrentState có một accessor mặc định và vì vậy điều này có thể kết thúc là một giải pháp giòn.

package org.springframework.statemachine.support; 

public abstract class MyStateMachineUtils extends StateMachineUtils { 

    public static <S, E> void setCurrentState(StateMachine<S, E> stateMachine, S state) { 
     if (stateMachine instanceof AbstractStateMachine) { 
      setCurrentState((AbstractStateMachine<S, E>)stateMachine, state); 
     } else { 
      throw new IllegalArgumentException("Provided StateMachine is not a valid type"); 
     } 
    } 

    public static <S, E> void setCurrentState(AbstractStateMachine<S, E> stateMachine, S state) { 
     stateMachine.setCurrentState(findState(stateMachine, state), null, null, false, stateMachine); 
    } 

    private static <S, E> State<S, E> findState(AbstractStateMachine<S, E> stateMachine, S stateId) { 
     for (State<S, E> state : stateMachine.getStates()) { 
      if (state.getId() == stateId) { 
       return state; 
      } 
     } 

     throw new IllegalArgumentException("Specified State ID is not valid"); 
    } 
} 

này sau đó có thể được sử dụng khá độc đáo như vậy:

MyStateMachineUtils.setCurrentState(entity.getStateMachine(), entity.getInternalState()); 
+0

Những gì bạn đang cố gắng làm chưa thể bởi vì chúng ta đang thiếu một số tính năng bên trong. https://github.com/spring-projects/spring-statemachine/issues/34 và https://github.com/spring-projects/spring-statemachine/issues/35 liên quan trực tiếp đến các tính năng này. Đồng bộ hóa máy nhà nước không chỉ cần thiết lập trạng thái hiện tại. Chúng tôi đang cố gắng để thực hiện SPI của một máy nhà nước phân phối có thể sử dụng để đồng bộ hóa và duy trì trạng thái hiện tại của nó và mọi thứ khác những gì nó cần để hoạt động đúng. Tôi hiện đang lên kế hoạch để bắt đầu công việc này ngay bây giờ mà cột mốc thứ hai đã hết. –

+1

Cảm ơn bạn đã làm rõ điều đó. Vì không có cách tiếp cận chính xác nào, tôi sẽ kiểm tra kỹ cách giải quyết ở trên vì trường hợp sử dụng của chúng tôi khá hạn chế ngay bây giờ và hy vọng chúng tôi có thể thực hiện mà không cần thay đổi sắp tới của bạn. – Alan

+0

Alan, entity.getStateMachine() cho null, đó là bình thường, vì nó là thoáng qua. Làm thế nào để làm việc này nếu bạn vượt qua null trong MyStateMachineUtils.setCurrentState (entity.getStateMachine(), entity.getInternalState()); – Petar

Các vấn đề liên quan