Статьи

Динамический поезд ADF: добавление поездов останавливается программно

Я собираюсь показать, как программно «на лету» добавлять остановки поездов в поезда АПД. В моем случае у меня есть приложение для бронирования билетов. Это ограниченный поток задач с моделью поезда. На первой остановке пользователи поезда вводят количество пассажиров, а на следующих остановках вводят информацию о некоторых пассажирах. Количество остановок с информацией о пассажирах должно изменяться динамически в зависимости от значения, представленного на первой остановке поезда. Итак, результат описанного поведения должен выглядеть так:

Ограниченный поток задач имеет следующую структуру:

Действие StartView — это фрагмент страницы, где мы вводим количество пассажиров, а действие DynamicView предоставляет фрагмент страницы для ввода информации о пассажире. На данный момент у нас есть только одно действие для информации о пассажирах, и я добавлю дополнительные действия, если количество пассажиров больше одного.
InputNumberSpinbox во фрагменте страницы StartView передает свое значение свойству passengerNumber некоторого базового компонента PageFlowScope, а действие для кнопки « Отправить» — это метод того же компонента:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
public class MainTrain {
 //Extra added train stops
 private List<ActivityId> dynamicStops = new ArrayList<ActivityId>();
  
 //Value of inputNumberSpinbox
 private int passengersNumber = 1;
  
 public String buttonPress(){
 //The number of extra added train stops is greater than needed
 if (passengersNumber <= dynamicStops.size())
 clearExtraStops();
 else //The number of extra added train stops is less than needed
 if (passengersNumber-1 > dynamicStops.size())
 addDynamicStops();
 return null;
 }

Таким образом, нажимая на кнопку « Отправить» , мы либо добавляем некоторые остановки поезда, либо очищаем дополнительные остановки в зависимости от значения inputNumberSpinbox . Мы сохраняем все добавленные динамические остановки в списке dynamicStops . Давайте посмотрим на метод clearExtraStops () :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
private void clearExtraStops() {
for (int i = dynamicStops.size(); i >= passengersNumber; i--) {
//Get ActivityId to be removed
ActivityId removeActivityId = dynamicStops.get(i-1);
 
//Get current train model and remove train stop
TrainModel trainModel = TrainUtils.findCurrentTrainModel();
trainModel.getTrainStops().remove(removeActivityId);
 
//Remove activity from task flow definition
getTaskFlowDefinition().getActivities().remove(removeActivityId);
dynamicStops.remove(i-1);
}
}

Метод удаляет две вещи: остановка поезда из модели поезда и действие из определения потока задач. Метод addDynamicStops () будет гораздо интереснее:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
private void addDynamicStops() {
 for (int i = dynamicStops.size(); i < passengersNumber - 1; i++) {
 //Creating new ActivityId
 ActivityId activityId =
 new ActivityId(getTaskFlowId(), new StringBuilder("DynamicView").append(i).toString());
 
 //The main trick of the post.
 //We consider DynamicView activity as a base for new train stop and new activity
  
 //Get base activity (DynamicView) and its train stop
 Activity baseActivity = getBaseDynamicActivity();
 TrainStopContainer stopContainer = (TrainStopContainer)baseActivity.getMetadataObject();
 TrainStop baseTrainStop = stopContainer.getTrainStop();
 
 //Create new Activity based on DynamicView but with new ActivityId
 ActivityImpl activityImpl = new ActivityImpl(baseActivity, activityId);
 //Add created activity to the task flow definition
 getTaskFlowDefinition().getActivities().put(activityId, activityImpl);
 
 //Create new train stop based on the DynamicView's train stop
 TrainStopModel trainStopModel = new TrainStopModel(
 new TrainStopImpl(baseTrainStop, i+2), activityId);
 //Add created train stop to the train stop model
 TrainModel trainModel = TrainUtils.findCurrentTrainModel();
 trainModel.getTrainStops().put(activityId, trainStopModel);
 //Add created activity to our list
 dynamicStops.add(activityId);
 }
}
  
private Activity getBaseDynamicActivity() {
 ActivityId baseActivityId = new ActivityId(getTaskFlowId(), "DynamicView");
 MetadataService metadataService = MetadataService.getInstance();
 return metadataService.getActivity(baseActivityId);
}
 
private TaskFlowDefinition getTaskFlowDefinition() {
 MetadataService metadataService = MetadataService.getInstance();
 return metadataService.getTaskFlowDefinition(getTaskFlowId());
}
 
 
private TaskFlowId getTaskFlowId() {
 ControllerContext controllerContext = ControllerContext.getInstance();
 ViewPortContext currentViewPortCtx = controllerContext.getCurrentViewPort();
 TaskFlowContext taskFlowCtx = currentViewPortCtx.getTaskFlowContext();
 return taskFlowCtx.getTaskFlowId();
}

Итак, основной трюк этого поста заключается в создании новых действий и остановок поездов на основе существующих для DynamicView . Чтобы реализовать идею, я создал два класса: ActivityImpl и TrainStopImpl . Классы — это не что иное, как прокси-классы, реализующие интерфейсы Activity и TrainStop соответственно. Они делегируют реализацию интерфейса базовым экземплярам, ​​за исключением некоторых конкретных методов, таких как getters for Id и DisplayName:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class TrainStopImpl implements TrainStop {
 //Base instance
 private TrainStop baseTrainStop;
  
 private int mpassNo;
 private static final String PASSANGER_FORM = "Passenger's data: ";
  
 public TrainStopImpl(TrainStop trainStop, int passNo) {
 baseTrainStop = trainStop;
 mpassNo = passNo;
 }
 
 //Specific implementation
 public String getDisplayName() {
 return new StringBuilder(PASSANGER_FORM).append(mpassNo).toString();
 }
 
 public String getOutcome() {
 return baseTrainStop.getOutcome();
 }
 
 public String getSequential() {
 return baseTrainStop.getSequential();
 }
 
...
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
public class ActivityImpl implements Activity {
 private Activity baseActivity;
 private ActivityId mid;
  
 public ActivityImpl(Activity activity, ActivityId id) {
 baseActivity = activity;
 mid = id;
 }
 
 //Specific implementation
 public ActivityId getId() {
 return mid;
 }
 
 public String getType() {
 return baseActivity.getType();
 }
 
 public Object getMetadataObject() {
 return baseActivity.getMetadataObject();
 }
...

И еще одна картинка для этого поста, просто чтобы показать, что он работает:

Вот и все! Вы можете скачать пример приложения для JDeveloper 11.1.1.2.0.

Справка: динамический поезд ADF. Добавление остановки поезда программно от нашего партнера JCG Евгения Федоренко в блоге ADF Practice .