source: trunk/autoquest-test-utils/src/main/java/de/ugoe/cs/autoquest/tasktrees/TaskTreeDecoder.java @ 1325

Last change on this file since 1325 was 1325, checked in by pharms, 10 years ago
File size: 13.1 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.tasktrees;
16
17import java.util.ArrayList;
18import java.util.HashMap;
19import java.util.LinkedList;
20import java.util.List;
21import java.util.Map;
22import java.util.regex.Matcher;
23import java.util.regex.Pattern;
24
25import de.ugoe.cs.autoquest.eventcore.Event;
26import de.ugoe.cs.autoquest.eventcore.IEventTarget;
27import de.ugoe.cs.autoquest.eventcore.IEventType;
28import de.ugoe.cs.autoquest.eventcore.StringEventType;
29import de.ugoe.cs.autoquest.eventcore.gui.TextInput;
30import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
31import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
32import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
33import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
34import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
35import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
36import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
37import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
38import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
39import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
40import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
41import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskBuilder;
42import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskFactory;
43import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
44import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
45import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
46import de.ugoe.cs.autoquest.test.DummyGUIElement;
47import de.ugoe.cs.autoquest.test.DummyTextField;
48
49/**
50 * TODO comment
51 *
52 * @version $Revision: $ $Date: 01.04.2012$
53 * @author 2012, last modified by $Author: patrick$
54 */
55public class TaskTreeDecoder {
56   
57    /** */
58    private static Pattern taskInstancePattern = Pattern.compile("([^{}]+)\\{|\\}");
59   
60    /** */
61    private static Pattern taskInstanceDetailsPattern =
62        Pattern.compile("\\s*(\\w*)\\s*([\\w\\(\\)\"]*)\\s*(\\(([\\w*\\s*]*)\\))?((\\w*)|(\".*\"))?");
63
64    /** */
65    private ITaskFactory taskFactory;
66   
67    /** */
68    private ITaskBuilder taskBuilder;
69   
70    /** */
71    Map<String, IEventTarget> targets = new HashMap<String, IEventTarget>();
72   
73    /** */
74    Map<String, ITask> tasks = new HashMap<String, ITask>();
75   
76    /**
77     *
78     */
79    public TaskTreeDecoder(ITaskFactory taskFactory, ITaskBuilder taskBuilder) {
80        super();
81        this.taskFactory = taskFactory;
82        this.taskBuilder = taskBuilder;
83    }
84
85    /**
86     *
87     */
88    public ITaskInstanceList decode(String taskTreeSpec) {
89        ITaskInstanceList taskInstanceList = null;
90
91        Matcher taskMatcher = taskInstancePattern.matcher(taskTreeSpec);
92
93        if (taskMatcher.find()) {
94            taskInstanceList = parseTaskInstanceList(taskMatcher);
95        }
96       
97        if (taskMatcher.find()) {
98            throw new IllegalArgumentException("too many tasks specified");
99        }
100       
101        return taskInstanceList;
102    }
103
104    /**
105     *
106     */
107    private ITaskInstanceList parseTaskInstanceList(Matcher taskMatcher) {
108        if ("}".equals(taskMatcher.group(1))) {
109            throw new IllegalArgumentException("invalid task instance list specification");
110        }
111       
112        String taskDetails = taskMatcher.group(1);
113       
114        Matcher matcher = taskInstanceDetailsPattern.matcher(taskDetails);
115       
116        if (!matcher.find()) {
117            throw new IllegalArgumentException("could not parse task details");
118        }
119
120        String type = matcher.group(1);
121       
122        ITaskInstanceList list;
123       
124        if ("UserSession".equals(type)) {
125            list = taskFactory.createUserSession();
126        }
127        else if ("TaskInstances".equals(type)) {
128            list = taskFactory.createNewTaskInstance(taskFactory.createNewSequence());
129        }
130        else {
131            throw new IllegalArgumentException("unknown type of task instance list: " + type);
132        }
133       
134        while (taskMatcher.find() && !"}".equals(taskMatcher.group(0))) {
135            ITaskInstance childInstance = parseTaskInstance(taskMatcher);
136           
137            if (!(list instanceof IUserSession)) {
138                taskBuilder.addChild
139                    ((ISequence) ((ITaskInstance) list).getTask(), childInstance.getTask());
140            }
141
142            taskBuilder.addTaskInstance(list, childInstance);
143        }
144
145        return list;
146    }
147
148    /**
149     *
150     */
151    private ITaskInstance parseTaskInstance(Matcher taskMatcher) {
152        if ("}".equals(taskMatcher.group(1))) {
153            throw new IllegalArgumentException("invalid task instance specification");
154        }
155       
156        String taskDetails = taskMatcher.group(1);
157       
158        Matcher matcher = taskInstanceDetailsPattern.matcher(taskDetails);
159       
160        if (!matcher.find()) {
161            throw new IllegalArgumentException("could not parse task details");
162        }
163
164        String type = matcher.group(1);
165        String id = matcher.group(2);
166       
167        // determine the children before creating this instance
168        List<ITaskInstance> children = new LinkedList<ITaskInstance>();
169        while (taskMatcher.find() && !"}".equals(taskMatcher.group(0))) {
170            children.add(parseTaskInstance(taskMatcher));
171        }
172       
173        // get the model
174        ITask task = getCreateTask(id, type, children);
175       
176        // create the respective instance
177        ITaskInstance instance;
178       
179        if (task instanceof ISequence) {
180            instance = taskFactory.createNewTaskInstance((ISequence) task);
181        }
182        else if (task instanceof ISelection) {
183            instance = taskFactory.createNewTaskInstance((ISelection) task);
184        }
185        else if (task instanceof IIteration) {
186            instance = taskFactory.createNewTaskInstance((IIteration) task);
187        }
188        else if (task instanceof IOptional) {
189            instance = taskFactory.createNewTaskInstance((IOptional) task);
190        }
191        else {
192            Event event = !task.getInstances().isEmpty() ?
193                ((IEventTaskInstance) task.getInstances().iterator().next()).getEvent() :
194                createUserInteractionEvent(type, id, matcher.group(4));
195               
196            instance = taskFactory.createNewTaskInstance((IEventTask) task, event);
197        } 
198       
199        // add the children to the instance
200        for (ITaskInstance childInstance : children) {
201            if (instance instanceof ISequenceInstance) {
202                taskBuilder.addChild((ISequenceInstance) instance, childInstance);
203            }
204            else if (instance instanceof ISelectionInstance) {
205                if (((ISelectionInstance) instance).getChild() == null) {
206                    taskBuilder.setChild((ISelectionInstance) instance, childInstance);
207                }
208                else {
209                    throw new IllegalArgumentException("can not add several children to one " +
210                                                       "selection instance");
211                }
212            }
213            else if (instance instanceof IIterationInstance) {
214                taskBuilder.addChild((IIterationInstance) instance, childInstance);
215            }
216            else if (instance instanceof IOptionalInstance) {
217                if (((IOptionalInstance) instance).getChild() == null) {
218                    taskBuilder.setChild((IOptionalInstance) instance, childInstance);
219                }
220                else {
221                    throw new IllegalArgumentException("can not add several children to one " +
222                                                       "optional instance");
223                }
224            }
225        }
226
227        // validate the instance
228        try {
229            new TaskTreeValidator().validate(instance);
230        }
231        catch (java.lang.AssertionError e) {
232            throw new IllegalArgumentException(e.getMessage(), e);
233        }
234       
235        return instance;
236    }
237
238    /**
239     * <p>
240     * TODO: comment
241     * </p>
242     *
243     * @param id
244     * @param type
245     * @param children
246     * @return
247     */
248    private ITask getCreateTask(String id, String type, List<ITaskInstance> children) {
249        ITask task = tasks.get(id);
250       
251        if (task == null) {
252            if ("Sequence".equals(type)) {
253                task = taskFactory.createNewSequence();
254            }
255            else if ("Selection".equals(type)) {
256                task = taskFactory.createNewSelection();
257            }
258            else if ("Iteration".equals(type)) {
259                task = taskFactory.createNewIteration();
260            }
261            else if ("Optional".equals(type)) {
262                task = taskFactory.createNewOptional();
263            }
264            else {
265                task = taskFactory.createNewEventTask(type + " --> " + id);
266            } 
267            tasks.put(id, task);
268
269            for (ITaskInstance childInstance : children) {
270                if (task instanceof ISequence) {
271                    taskBuilder.addChild((ISequence) task, childInstance.getTask());
272                }
273                else if (task instanceof ISelection) {
274                    taskBuilder.addChild((ISelection) task, childInstance.getTask());
275                }
276                else if (task instanceof IIteration) {
277                    if (((IIteration) task).getMarkedTask() == null) {
278                        taskBuilder.setMarkedTask((IIteration) task, childInstance.getTask());
279                    }
280                    else if (!((IIteration) task).getMarkedTask().equals(childInstance.getTask())) {
281                        throw new IllegalArgumentException
282                            ("can not add more than one child to an iteration");
283                    }
284                }
285                else if (task instanceof IOptional) {
286                    if (((IOptional) task).getMarkedTask() == null) {
287                        taskBuilder.setMarkedTask((IOptional) task, childInstance.getTask());
288                    }
289                    else if (!((IOptional) task).getMarkedTask().equals(childInstance.getTask())) {
290                        throw new IllegalArgumentException
291                            ("can not add more than one child to an optional");
292                    }
293                }
294                else {
295                    throw new IllegalArgumentException("can not add children to something that " +
296                                                       "is no sequence, selection, iteration, or " +
297                                                       "optional");
298                }
299            }
300        }
301        else if ("Selection".equals(type)) {
302            // update the selection with further alternatives, if specified by the current
303            // child instance
304            if (children.size() == 1) {
305                ITask newChildTask = children.get(0).getTask();
306               
307                boolean found = false;
308                for (ITask childTask : ((ISelection) task).getChildren()) {
309                    if (childTask.equals(newChildTask)) {
310                        found = true;
311                        break;
312                    }
313                }
314               
315                if (!found) {
316                    taskBuilder.addChild((ISelection) task, newChildTask);
317                }
318            }
319        }
320
321        return task;
322    }
323
324    /**
325     * <p>
326     * </p>
327     *
328     * @param matcher
329     * @return
330     */
331    private Event createUserInteractionEvent(String type, String targetId, String furtherInfo) {
332        IEventTarget eventTarget = targets.get(targetId);
333        if (eventTarget == null) {
334            eventTarget = determineTarget(type, targetId, furtherInfo);
335            targets.put(targetId, eventTarget);
336        }
337        IEventType eventType = determineType(type, furtherInfo);
338       
339        return new Event(eventType, eventTarget);
340    }
341
342    /**
343     * <p>
344     * </p>
345     *
346     * @param type
347     * @param id
348     * @param enteredText
349     * @return
350     */
351    private IEventTarget determineTarget(String type, String id, String enteredText) {
352        if ("TextInput".equals(type) && enteredText != null) {
353            return new DummyTextField(enteredText);
354        }
355        else {
356            return new DummyGUIElement(id);
357        }
358    }
359
360    /**
361     * <p>
362     * </p>
363     *
364     * @param type
365     * @param enteredText
366     * @return
367     */
368    private IEventType determineType(String type, String enteredText) {
369        if ("TextInput".equals(type) && enteredText != null) {
370            return new TextInput(enteredText, new ArrayList<Event>());
371        }
372        else {
373            return new StringEventType(type);
374        }
375    }
376
377}
Note: See TracBrowser for help on using the repository browser.