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

Last change on this file since 2066 was 1875, checked in by pharms, 11 years ago
  • added support for mouse clicks
  • fixed bug with undiscarded event task instances
File size: 18.2 KB
RevLine 
[1123]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
[1202]17import java.util.ArrayList;
[1123]18import java.util.HashMap;
[1327]19import java.util.HashSet;
[1325]20import java.util.LinkedList;
21import java.util.List;
[1123]22import java.util.Map;
[1327]23import java.util.Set;
[1123]24import java.util.regex.Matcher;
25import java.util.regex.Pattern;
26
[1202]27import de.ugoe.cs.autoquest.eventcore.Event;
[1123]28import de.ugoe.cs.autoquest.eventcore.IEventTarget;
[1202]29import de.ugoe.cs.autoquest.eventcore.IEventType;
[1123]30import de.ugoe.cs.autoquest.eventcore.StringEventType;
[1875]31import de.ugoe.cs.autoquest.eventcore.gui.MouseButtonInteraction;
32import de.ugoe.cs.autoquest.eventcore.gui.MouseClick;
[1333]33import de.ugoe.cs.autoquest.eventcore.gui.Scroll;
[1202]34import de.ugoe.cs.autoquest.eventcore.gui.TextInput;
[1294]35import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
36import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
[1123]37import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration;
[1294]38import de.ugoe.cs.autoquest.tasktrees.treeifc.IIterationInstance;
[1123]39import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional;
[1294]40import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptionalInstance;
[1123]41import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection;
[1294]42import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelectionInstance;
[1123]43import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
[1294]44import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequenceInstance;
[1146]45import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
46import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskBuilder;
47import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskFactory;
48import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
49import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
50import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;
[1123]51import de.ugoe.cs.autoquest.test.DummyGUIElement;
[1202]52import de.ugoe.cs.autoquest.test.DummyTextField;
[1123]53
54/**
55 * TODO comment
56 *
57 * @version $Revision: $ $Date: 01.04.2012$
58 * @author 2012, last modified by $Author: patrick$
59 */
[1146]60public class TaskTreeDecoder {
[1123]61   
62    /** */
[1146]63    private static Pattern taskInstancePattern = Pattern.compile("([^{}]+)\\{|\\}");
[1123]64   
65    /** */
[1146]66    private static Pattern taskInstanceDetailsPattern =
[1202]67        Pattern.compile("\\s*(\\w*)\\s*([\\w\\(\\)\"]*)\\s*(\\(([\\w*\\s*]*)\\))?((\\w*)|(\".*\"))?");
68
[1123]69    /** */
[1146]70    private ITaskFactory taskFactory;
[1123]71   
72    /** */
[1146]73    private ITaskBuilder taskBuilder;
[1123]74   
75    /** */
76    Map<String, IEventTarget> targets = new HashMap<String, IEventTarget>();
77   
[1146]78    /** */
79    Map<String, ITask> tasks = new HashMap<String, ITask>();
80   
[1123]81    /**
82     *
83     */
[1146]84    public TaskTreeDecoder(ITaskFactory taskFactory, ITaskBuilder taskBuilder) {
[1123]85        super();
[1146]86        this.taskFactory = taskFactory;
87        this.taskBuilder = taskBuilder;
[1123]88    }
89
90    /**
91     *
92     */
[1146]93    public ITaskInstanceList decode(String taskTreeSpec) {
94        ITaskInstanceList taskInstanceList = null;
[1123]95
[1146]96        Matcher taskMatcher = taskInstancePattern.matcher(taskTreeSpec);
[1123]97
98        if (taskMatcher.find()) {
[1146]99            taskInstanceList = parseTaskInstanceList(taskMatcher);
[1123]100        }
101       
102        if (taskMatcher.find()) {
103            throw new IllegalArgumentException("too many tasks specified");
104        }
105       
[1327]106        correctTargets(taskInstanceList);
107       
[1333]108        // validate the instance list
109        try {
110            new TaskTreeValidator().validate(taskInstanceList);
111        }
112        catch (java.lang.AssertionError e) {
113            throw new IllegalArgumentException(e.getMessage(), e);
114        }
115       
[1146]116        return taskInstanceList;
[1123]117    }
118
119    /**
120     *
121     */
[1146]122    private ITaskInstanceList parseTaskInstanceList(Matcher taskMatcher) {
[1123]123        if ("}".equals(taskMatcher.group(1))) {
[1146]124            throw new IllegalArgumentException("invalid task instance list specification");
[1123]125        }
126       
127        String taskDetails = taskMatcher.group(1);
128       
[1146]129        Matcher matcher = taskInstanceDetailsPattern.matcher(taskDetails);
[1123]130       
131        if (!matcher.find()) {
132            throw new IllegalArgumentException("could not parse task details");
133        }
134
135        String type = matcher.group(1);
136       
[1146]137        ITaskInstanceList list;
[1123]138       
[1146]139        if ("UserSession".equals(type)) {
140            list = taskFactory.createUserSession();
[1123]141        }
[1146]142        else if ("TaskInstances".equals(type)) {
143            list = taskFactory.createNewTaskInstance(taskFactory.createNewSequence());
[1123]144        }
[1146]145        else {
146            throw new IllegalArgumentException("unknown type of task instance list: " + type);
[1123]147        }
[1146]148       
149        while (taskMatcher.find() && !"}".equals(taskMatcher.group(0))) {
150            ITaskInstance childInstance = parseTaskInstance(taskMatcher);
151           
152            if (!(list instanceof IUserSession)) {
153                taskBuilder.addChild
154                    ((ISequence) ((ITaskInstance) list).getTask(), childInstance.getTask());
155            }
156
157            taskBuilder.addTaskInstance(list, childInstance);
[1123]158        }
[1146]159
160        return list;
161    }
162
163    /**
164     *
165     */
166    private ITaskInstance parseTaskInstance(Matcher taskMatcher) {
167        if ("}".equals(taskMatcher.group(1))) {
168            throw new IllegalArgumentException("invalid task instance specification");
[1123]169        }
[1146]170       
171        String taskDetails = taskMatcher.group(1);
172       
173        Matcher matcher = taskInstanceDetailsPattern.matcher(taskDetails);
174       
175        if (!matcher.find()) {
176            throw new IllegalArgumentException("could not parse task details");
[1123]177        }
[1146]178
179        String type = matcher.group(1);
180        String id = matcher.group(2);
[1123]181       
[1325]182        // determine the children before creating this instance
183        List<ITaskInstance> children = new LinkedList<ITaskInstance>();
184        while (taskMatcher.find() && !"}".equals(taskMatcher.group(0))) {
185            children.add(parseTaskInstance(taskMatcher));
[1146]186        }
187       
[1325]188        // get the model
189        ITask task = getCreateTask(id, type, children);
190       
191        // create the respective instance
[1294]192        ITaskInstance instance;
193       
194        if (task instanceof ISequence) {
195            instance = taskFactory.createNewTaskInstance((ISequence) task);
[1123]196        }
[1294]197        else if (task instanceof ISelection) {
198            instance = taskFactory.createNewTaskInstance((ISelection) task);
199        }
200        else if (task instanceof IIteration) {
201            instance = taskFactory.createNewTaskInstance((IIteration) task);
202        }
203        else if (task instanceof IOptional) {
204            instance = taskFactory.createNewTaskInstance((IOptional) task);
205        }
206        else {
[1327]207            Event event = createUserInteractionEvent(type, id, matcher.group(4));
[1325]208            instance = taskFactory.createNewTaskInstance((IEventTask) task, event);
[1294]209        } 
[1146]210       
[1325]211        // add the children to the instance
212        for (ITaskInstance childInstance : children) {
213            if (instance instanceof ISequenceInstance) {
214                taskBuilder.addChild((ISequenceInstance) instance, childInstance);
[1123]215            }
[1325]216            else if (instance instanceof ISelectionInstance) {
217                if (((ISelectionInstance) instance).getChild() == null) {
218                    taskBuilder.setChild((ISelectionInstance) instance, childInstance);
[1123]219                }
[1325]220                else {
221                    throw new IllegalArgumentException("can not add several children to one " +
222                                                       "selection instance");
[1123]223                }
224            }
[1325]225            else if (instance instanceof IIterationInstance) {
226                taskBuilder.addChild((IIterationInstance) instance, childInstance);
227            }
228            else if (instance instanceof IOptionalInstance) {
229                if (((IOptionalInstance) instance).getChild() == null) {
230                    taskBuilder.setChild((IOptionalInstance) instance, childInstance);
[1123]231                }
[1325]232                else {
233                    throw new IllegalArgumentException("can not add several children to one " +
234                                                       "optional instance");
[1123]235                }
236            }
[1325]237        }
238
239        return instance;
240    }
241
242    /**
243     *
244     */
245    private ITask getCreateTask(String id, String type, List<ITaskInstance> children) {
[1327]246        String effectiveId = id;
247        ITask task = tasks.get(effectiveId);
[1325]248       
249        if (task == null) {
250            if ("Sequence".equals(type)) {
251                task = taskFactory.createNewSequence();
[1123]252            }
[1325]253            else if ("Selection".equals(type)) {
254                task = taskFactory.createNewSelection();
[1294]255            }
[1325]256            else if ("Iteration".equals(type)) {
257                task = taskFactory.createNewIteration();
[1294]258            }
[1325]259            else if ("Optional".equals(type)) {
260                task = taskFactory.createNewOptional();
[1294]261            }
[1325]262            else {
[1327]263                effectiveId = type + " --> " + id;
264                task = tasks.get(effectiveId);
265               
266                if (task == null) {
267                    task = taskFactory.createNewEventTask(effectiveId);
268                }
[1325]269            } 
[1327]270            tasks.put(effectiveId, task);
[1325]271
272            for (ITaskInstance childInstance : children) {
273                if (task instanceof ISequence) {
274                    taskBuilder.addChild((ISequence) task, childInstance.getTask());
275                }
276                else if (task instanceof ISelection) {
277                    taskBuilder.addChild((ISelection) task, childInstance.getTask());
278                }
279                else if (task instanceof IIteration) {
280                    if (((IIteration) task).getMarkedTask() == null) {
281                        taskBuilder.setMarkedTask((IIteration) task, childInstance.getTask());
282                    }
283                    else if (!((IIteration) task).getMarkedTask().equals(childInstance.getTask())) {
284                        throw new IllegalArgumentException
285                            ("can not add more than one child to an iteration");
286                    }
287                }
288                else if (task instanceof IOptional) {
289                    if (((IOptional) task).getMarkedTask() == null) {
290                        taskBuilder.setMarkedTask((IOptional) task, childInstance.getTask());
291                    }
292                    else if (!((IOptional) task).getMarkedTask().equals(childInstance.getTask())) {
293                        throw new IllegalArgumentException
294                            ("can not add more than one child to an optional");
295                    }
296                }
297                else {
298                    throw new IllegalArgumentException("can not add children to something that " +
299                                                       "is no sequence, selection, iteration, or " +
300                                                       "optional");
301                }
[1294]302            }
[1123]303        }
[1325]304        else if ("Selection".equals(type)) {
305            // update the selection with further alternatives, if specified by the current
306            // child instance
307            if (children.size() == 1) {
308                ITask newChildTask = children.get(0).getTask();
309               
310                boolean found = false;
311                for (ITask childTask : ((ISelection) task).getChildren()) {
312                    if (childTask.equals(newChildTask)) {
313                        found = true;
314                        break;
315                    }
316                }
317               
318                if (!found) {
319                    taskBuilder.addChild((ISelection) task, newChildTask);
320                }
321            }
322        }
[1333]323        else if ("Optional".equals(type)) {
324            // update the optional with what is optional if available
325            if (children.size() == 1) {
326                ITask newChildTask = children.get(0).getTask();
327               
328                if (((IOptional) task).getMarkedTask() == null) {
329                    taskBuilder.setMarkedTask((IOptional) task, newChildTask);
330                }
331                else if (!((IOptional) task).getMarkedTask().equals(newChildTask)) {
332                    throw new IllegalArgumentException("all children of the same optional must " +
333                                                       "be of an identical task model.");
334                }
335            }
336        }
[1123]337
[1325]338        return task;
[1123]339    }
340
[1212]341    /**
342     * <p>
343     * </p>
344     *
345     * @param matcher
346     * @return
347     */
[1325]348    private Event createUserInteractionEvent(String type, String targetId, String furtherInfo) {
349        IEventTarget eventTarget = targets.get(targetId);
[1294]350        if (eventTarget == null) {
[1327]351            eventTarget = new DummyGUIElement(targetId);
[1325]352            targets.put(targetId, eventTarget);
[1202]353        }
[1327]354       
[1325]355        IEventType eventType = determineType(type, furtherInfo);
[1294]356       
[1325]357        return new Event(eventType, eventTarget);
[1212]358    }
[1202]359
[1212]360    /**
361     * <p>
362     * </p>
363     *
364     * @param type
365     * @param enteredText
366     * @return
367     */
[1333]368    private IEventType determineType(String type, String additionalInfo) {
[1327]369        if ("TextInput".equals(type)) {
[1333]370            return new TextInput(additionalInfo, new ArrayList<Event>());
[1212]371        }
[1875]372        else if ("MouseClick".equals(type)) {
373            return new MouseClick(MouseButtonInteraction.Button.LEFT, 5, 6);
374        }
[1333]375        else if ("Scroll".equals(type)) {
376            int x = 0;
377            int y = 0;
378            if (additionalInfo != null) {
379                String[] parts = additionalInfo.split(" ");
380                if (parts.length > 0) {
381                    try {
382                        x = Integer.parseInt(parts[0]);
383                    }
384                    catch (NumberFormatException e) {
385                        throw new IllegalArgumentException("could not parse scroll coordinates", e);
386                    }
387                }
388                if (parts.length > 1) {
389                    try {
390                        y = Integer.parseInt(parts[1]);
391                    }
392                    catch (NumberFormatException e) {
393                        throw new IllegalArgumentException("could not parse scroll coordinates", e);
394                    }
395                }
396            }
397            return new Scroll(x, y);
398        }
[1212]399        else {
[1327]400            return new StringEventType(type);
[1212]401        }
402    }
[1202]403
[1212]404    /**
405     *
406     */
[1327]407    private void correctTargets(ITaskInstanceList taskInstanceList) {
408        Set<IEventTarget> textInputTargets = new HashSet<IEventTarget>();
409       
410        for (ITaskInstance instance : taskInstanceList) {
411            getTextInputTargets(instance, textInputTargets);
[1212]412        }
[1327]413       
414        Map<IEventTarget, IEventTarget> replacements = new HashMap<IEventTarget, IEventTarget>();
415       
416        for (IEventTarget oldTarget : textInputTargets) {
417            replacements.put(oldTarget, new DummyTextField(oldTarget.toString()));
[1212]418        }
[1327]419       
420        for (int i = 0; i < taskInstanceList.size(); i++) {
421            taskBuilder.setTaskInstance
422                (taskInstanceList, i, replaceTargets(taskInstanceList.get(i), replacements));
423        }
424       
[1212]425    }
426
[1327]427    /**
428     *
429     */
430    private void getTextInputTargets(ITaskInstance instance, Set<IEventTarget> textInputTargets) {
431        if (instance instanceof ISequenceInstance) {
432            for (ITaskInstance child : (ISequenceInstance) instance) {
433                getTextInputTargets(child, textInputTargets);
434            }
435        }
436        else if (instance instanceof ISelectionInstance) {
437            getTextInputTargets(((ISelectionInstance) instance).getChild(), textInputTargets);
438        }
439        else if (instance instanceof IIterationInstance) {
440            for (ITaskInstance child : (IIterationInstance) instance) {
441                getTextInputTargets(child, textInputTargets);
442            }
443        }
444        else if (instance instanceof IOptionalInstance) {
445            getTextInputTargets(((IOptionalInstance) instance).getChild(), textInputTargets);
446        }
447        else if ((instance instanceof IEventTaskInstance) &&
448                 (((IEventTaskInstance) instance).getEvent().getType() instanceof TextInput))
449        {
450            textInputTargets.add(((IEventTaskInstance) instance).getEvent().getTarget());
451        }
452    }
453
454    /**
455     *
456     */
457    private ITaskInstance replaceTargets(ITaskInstance                   instance,
458                                         Map<IEventTarget, IEventTarget> replacements)
459    {
460        ITaskInstance replacement = instance;
461        if (instance instanceof ITaskInstanceList) {
462            for (int i = 0; i < ((ITaskInstanceList) instance).size(); i++) {
463                taskBuilder.setTaskInstance
464                    ((ITaskInstanceList) instance, i,
465                     replaceTargets(((ITaskInstanceList) instance).get(i), replacements));
466            }
467        }
468        else if (instance instanceof ISelectionInstance) {
469            ISelectionInstance selInst = (ISelectionInstance) instance;
470            taskBuilder.setChild(selInst, replaceTargets(selInst.getChild(), replacements));
471        }
472        else if (instance instanceof IOptionalInstance) {
473            IOptionalInstance optInst = (IOptionalInstance) instance;
[1333]474            if (optInst.getChild() != null) {
475                taskBuilder.setChild(optInst, replaceTargets(optInst.getChild(), replacements));
476            }
[1327]477        }
478        else if ((instance instanceof IEventTaskInstance) &&
479                 (replacements.containsKey(((IEventTaskInstance) instance).getEvent().getTarget())))
480        {
481            Event origEvent = ((IEventTaskInstance) instance).getEvent();
482            replacement = taskFactory.createNewTaskInstance
483                (((IEventTaskInstance) instance).getEventTask(),
484                 new Event(origEvent.getType(), replacements.get(origEvent.getTarget())));
[1875]485           
486            taskBuilder.discardTaskInstance(instance);
[1327]487        }
488       
489        return replacement;
490    }
491
[1123]492}
Note: See TracBrowser for help on using the repository browser.