001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.tools.seleniumbuilder;
016    
017    import com.liferay.portal.freemarker.FreeMarkerUtil;
018    import com.liferay.portal.kernel.io.unsync.UnsyncBufferedReader;
019    import com.liferay.portal.kernel.io.unsync.UnsyncStringReader;
020    import com.liferay.portal.kernel.util.ArrayUtil;
021    import com.liferay.portal.kernel.util.CharPool;
022    import com.liferay.portal.kernel.util.FileUtil;
023    import com.liferay.portal.kernel.util.ListUtil;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.kernel.util.TextFormatter;
028    import com.liferay.portal.kernel.util.Validator;
029    import com.liferay.portal.kernel.xml.Attribute;
030    import com.liferay.portal.kernel.xml.Document;
031    import com.liferay.portal.kernel.xml.DocumentException;
032    import com.liferay.portal.kernel.xml.Element;
033    import com.liferay.portal.kernel.xml.SAXReaderUtil;
034    import com.liferay.portal.tools.servicebuilder.ServiceBuilder;
035    
036    import java.io.ByteArrayInputStream;
037    import java.io.File;
038    import java.io.InputStream;
039    
040    import java.util.ArrayList;
041    import java.util.HashMap;
042    import java.util.HashSet;
043    import java.util.List;
044    import java.util.Map;
045    import java.util.Properties;
046    import java.util.Set;
047    import java.util.TreeSet;
048    import java.util.regex.Matcher;
049    import java.util.regex.Pattern;
050    
051    import javax.xml.xpath.XPath;
052    import javax.xml.xpath.XPathFactory;
053    
054    import org.apache.commons.lang.StringEscapeUtils;
055    
056    /**
057     * @author Michael Hashimoto
058     */
059    public class SeleniumBuilderFileUtil {
060    
061            public SeleniumBuilderFileUtil(String baseDirName, String projectDirName) {
062                    _baseDirName = baseDirName;
063    
064                    Properties properties = new Properties();
065    
066                    try {
067                            String content = FileUtil.read(projectDirName + "/test.properties");
068    
069                            InputStream inputStream = new ByteArrayInputStream(
070                                    content.getBytes());
071    
072                            properties.load(inputStream);
073                    }
074                    catch (Exception e) {
075                            e.printStackTrace();
076                    }
077    
078                    _componentNames = ListUtil.fromArray(
079                            StringUtil.split(properties.getProperty("component.names")));
080                    _testcaseAvailablePropertyNames = ListUtil.fromArray(
081                            StringUtil.split(
082                                    properties.getProperty("testcase.available.property.names")));
083                    _testrayAvailableComponentNames = ListUtil.fromArray(
084                            StringUtil.split(
085                                    properties.getProperty("testray.available.component.names")));
086            }
087    
088            public String escapeHtml(String input) {
089                    return StringEscapeUtils.escapeHtml(input);
090            }
091    
092            public String escapeJava(String input) {
093                    return StringEscapeUtils.escapeJava(input);
094            }
095    
096            public List<Element> getAllChildElements(
097                    Element element, String elementName) {
098    
099                    List<Element> allChildElements = new ArrayList<Element>();
100    
101                    List<Element> childElements = element.elements();
102    
103                    if (childElements.isEmpty()) {
104                            return allChildElements;
105                    }
106    
107                    for (Element childElement : childElements) {
108                            String childElementName = childElement.getName();
109    
110                            if (childElementName.equals(elementName)) {
111                                    allChildElements.add(childElement);
112                            }
113    
114                            allChildElements.addAll(
115                                    getAllChildElements(childElement, elementName));
116                    }
117    
118                    return allChildElements;
119            }
120    
121            public String getBaseDirName() {
122                    return _baseDirName;
123            }
124    
125            public Set<String> getChildElementAttributeValues(
126                    Element element, String attributeName) {
127    
128                    Set<String> childElementAttributeValues = new TreeSet<String>();
129    
130                    List<Element> childElements = element.elements();
131    
132                    if (childElements.isEmpty()) {
133                            return childElementAttributeValues;
134                    }
135    
136                    for (Element childElement : childElements) {
137                            String childElementName = childElement.attributeValue(
138                                    attributeName);
139    
140                            if (childElementName != null) {
141                                    int x = childElementName.lastIndexOf(StringPool.POUND);
142    
143                                    if (x != -1) {
144                                            childElementAttributeValues.add(
145                                                    childElementName.substring(0, x));
146                                    }
147                            }
148    
149                            childElementAttributeValues.addAll(
150                                    getChildElementAttributeValues(childElement, attributeName));
151                    }
152    
153                    return childElementAttributeValues;
154            }
155    
156            public Set<String> getChildElementLineNumbers(Element element) {
157                    Set<String> childElementLineNumbers = new TreeSet<String>();
158    
159                    List<Element> childElements = element.elements();
160    
161                    if (childElements.isEmpty()) {
162                            return childElementLineNumbers;
163                    }
164    
165                    for (Element childElement : childElements) {
166                            String childElementLineNumber = childElement.attributeValue(
167                                    "line-number");
168    
169                            if (childElementLineNumber != null) {
170                                    childElementLineNumbers.add(childElementLineNumber);
171                            }
172    
173                            childElementLineNumbers.addAll(
174                                    getChildElementLineNumbers(childElement));
175                    }
176    
177                    return childElementLineNumbers;
178            }
179    
180            public String getClassName(String fileName) {
181                    String classSuffix = getClassSuffix(fileName);
182    
183                    return getClassName(fileName, classSuffix);
184            }
185    
186            public String getClassName(String fileName, String classSuffix) {
187                    return
188                            getPackageName(fileName) + "." +
189                                    getSimpleClassName(fileName, classSuffix);
190            }
191    
192            public String getClassSimpleClassName(String className) {
193                    int x = className.lastIndexOf(CharPool.PERIOD);
194    
195                    return className.substring(x + 1);
196            }
197    
198            public String getClassSuffix(String fileName) {
199                    int x = fileName.indexOf(CharPool.PERIOD);
200    
201                    String classSuffix = StringUtil.upperCaseFirstLetter(
202                            fileName.substring(x + 1));
203    
204                    if (classSuffix.equals("Testcase")) {
205                            classSuffix = "TestCase";
206                    }
207    
208                    return classSuffix;
209            }
210    
211            public List<String> getComponentNames() {
212                    return _componentNames;
213            }
214    
215            public String getHTMLFileName(String fileName) {
216                    String javaFileName = getJavaFileName(fileName);
217    
218                    return StringUtil.replace(javaFileName, ".java", ".html");
219            }
220    
221            public String getJavaFileName(String fileName) {
222                    String classSuffix = getClassSuffix(fileName);
223    
224                    return getJavaFileName(fileName, classSuffix);
225            }
226    
227            public String getJavaFileName(String fileName, String classSuffix) {
228                    return
229                            getPackagePath(fileName) + "/" +
230                                    getSimpleClassName(fileName, classSuffix) + ".java";
231            }
232    
233            public int getLocatorCount(Element rootElement) {
234                    String xml = rootElement.asXML();
235    
236                    for (int i = 1;; i++) {
237                            if (xml.contains("${locator" + i + "}")) {
238                                    continue;
239                            }
240    
241                            if (i > 1) {
242                                    i--;
243                            }
244    
245                            return i;
246                    }
247            }
248    
249            public String getName(String fileName) {
250                    int x = fileName.lastIndexOf(StringPool.SLASH);
251                    int y = fileName.lastIndexOf(CharPool.PERIOD);
252    
253                    return fileName.substring(x + 1, y);
254            }
255    
256            public String getNormalizedContent(String fileName) throws Exception {
257                    String content = readFile(fileName);
258    
259                    if (fileName.endsWith(".path")) {
260                            int x = content.indexOf("<tbody>");
261                            int y = content.indexOf("</tbody>");
262    
263                            if ((x == -1) || (y == -1)) {
264                                    throwValidationException(1002, fileName, "tbody");
265                            }
266    
267                            String pathTbody = content.substring(x, y + 8);
268    
269                            Map<String, Object> context = new HashMap<String, Object>();
270    
271                            context.put("pathName", getName(fileName));
272                            context.put("pathTbody", pathTbody);
273    
274                            String newContent = processTemplate("path_xml.ftl", context);
275    
276                            if (!content.equals(newContent)) {
277                                    content = newContent;
278    
279                                    writeFile(getBaseDirName(), fileName, newContent, false);
280                            }
281                    }
282    
283                    StringBundler sb = new StringBundler();
284    
285                    int lineNumber = 1;
286    
287                    UnsyncBufferedReader unsyncBufferedReader = new UnsyncBufferedReader(
288                            new UnsyncStringReader(content));
289    
290                    String line = null;
291    
292                    while ((line = unsyncBufferedReader.readLine()) != null) {
293                            Matcher matcher = _tagPattern.matcher(line);
294    
295                            if (matcher.find()) {
296                                    for (String reservedTag : _reservedTags) {
297                                            if (line.contains("<" + reservedTag)) {
298                                                    line = StringUtil.replace(
299                                                            line, matcher.group(),
300                                                            matcher.group() + " line-number=\"" + lineNumber +
301                                                                    "\"");
302    
303                                                    break;
304                                            }
305                                    }
306                            }
307    
308                            sb.append(line);
309    
310                            lineNumber++;
311                    }
312    
313                    content = sb.toString();
314    
315                    if (content != null) {
316                            content = content.trim();
317                            content = StringUtil.replace(content, "\n", "");
318                            content = StringUtil.replace(content, "\r\n", "");
319                            content = StringUtil.replace(content, "\t", " ");
320                            content = content.replaceAll(" +", " ");
321                    }
322    
323                    return content;
324            }
325    
326            public String getObjectName(String name) {
327                    return StringUtil.upperCaseFirstLetter(name);
328            }
329    
330            public String getPackageName(String fileName) {
331                    String packagePath = getPackagePath(fileName);
332    
333                    return StringUtil.replace(
334                            packagePath, StringPool.SLASH, StringPool.PERIOD);
335            }
336    
337            public String getPackagePath(String fileName) {
338                    int x = fileName.lastIndexOf(StringPool.SLASH);
339    
340                    return fileName.substring(0, x);
341            }
342    
343            public String getReturnType(String name) {
344                    if (name.startsWith("Is")) {
345                            return "boolean";
346                    }
347    
348                    return "void";
349            }
350    
351            public Element getRootElement(String fileName) throws Exception {
352                    String content = getNormalizedContent(fileName);
353    
354                    try {
355                            Document document = SAXReaderUtil.read(content, true);
356    
357                            Element rootElement = document.getRootElement();
358    
359                            validate(fileName, rootElement);
360    
361                            return rootElement;
362                    }
363                    catch (DocumentException de) {
364                            throwValidationException(1007, fileName, de);
365                    }
366    
367                    return null;
368            }
369    
370            public String getSimpleClassName(String fileName) {
371                    String classSuffix = getClassSuffix(fileName);
372    
373                    return getSimpleClassName(fileName, classSuffix);
374            }
375    
376            public String getSimpleClassName(String fileName, String classSuffix) {
377                    return getName(fileName) + classSuffix;
378            }
379    
380            public String getVariableName(String name) {
381                    return TextFormatter.format(name, TextFormatter.I);
382            }
383    
384            public String normalizeFileName(String fileName) {
385                    return StringUtil.replace(
386                            fileName, StringPool.BACK_SLASH, StringPool.SLASH);
387            }
388    
389            public String readFile(String fileName) throws Exception {
390                    return FileUtil.read(getBaseDirName() + "/" + fileName);
391            }
392    
393            public void writeFile(String fileName, String content, boolean format)
394                    throws Exception {
395    
396                    writeFile(getBaseDirName() + "-generated", fileName, content, format);
397            }
398    
399            public void writeFile(
400                            String baseDirName, String fileName, String content, boolean format)
401                    throws Exception {
402    
403                    File file = new File(baseDirName + "/" + fileName);
404    
405                    if (format) {
406                            ServiceBuilder.writeFile(file, content);
407                    }
408                    else {
409                            System.out.println("Writing " + file);
410    
411                            FileUtil.write(file, content);
412                    }
413            }
414    
415            protected String processTemplate(String name, Map<String, Object> context)
416                    throws Exception {
417    
418                    return StringUtil.strip(
419                            FreeMarkerUtil.process(_TPL_ROOT + name, context), '\r');
420            }
421    
422            protected void throwValidationException(int errorCode, String fileName) {
423                    throwValidationException(
424                            errorCode, fileName, null, null, null, null, null);
425            }
426    
427            protected void throwValidationException(
428                    int errorCode, String fileName, Element element) {
429    
430                    throwValidationException(
431                            errorCode, fileName, element, null, null, null, null);
432            }
433    
434            protected void throwValidationException(
435                    int errorCode, String fileName, Element element, String string1) {
436    
437                    throwValidationException(
438                            errorCode, fileName, element, null, string1, null, null);
439            }
440    
441            protected void throwValidationException(
442                    int errorCode, String fileName, Element element, String string1,
443                    String string2) {
444    
445                    throwValidationException(
446                            errorCode, fileName, element, null, string1, string2, null);
447            }
448    
449            protected void throwValidationException(
450                    int errorCode, String fileName, Element element, String[] array) {
451    
452                    throwValidationException(
453                            errorCode, fileName, element, array, null, null, null);
454            }
455    
456            protected void throwValidationException(
457                    int errorCode, String fileName, Element element, String[] array,
458                    String string1) {
459    
460                    throwValidationException(
461                            errorCode, fileName, element, array, string1, null, null);
462            }
463    
464            protected void throwValidationException(
465                    int errorCode, String fileName, Element element, String[] array,
466                    String string1, String string2, Exception e) {
467    
468                    String prefix = "Error " + errorCode + ": ";
469                    String suffix = fileName;
470    
471                    if (element != null) {
472                            suffix += ":" + element.attributeValue("line-number");
473                    }
474    
475                    if (errorCode == 1000) {
476                            throw new IllegalArgumentException(
477                                    prefix + "Invalid root element in " + suffix);
478                    }
479                    else if (errorCode == 1001) {
480                            throw new IllegalArgumentException(
481                                    prefix + "Missing (" + StringUtil.merge(array, "|") +
482                                            ") child element in " + suffix);
483                    }
484                    else if (errorCode == 1002) {
485                            throw new IllegalArgumentException(
486                                    prefix + "Invalid " + string1 + " element in " + suffix);
487                    }
488                    else if (errorCode == 1003) {
489                            throw new IllegalArgumentException(
490                                    prefix + "Missing " + string1 + " attribute in " + suffix);
491                    }
492                    else if (errorCode == 1004) {
493                            throw new IllegalArgumentException(
494                                    prefix + "Missing (" + StringUtil.merge(array, "|") +
495                                            ") attribute in " + suffix);
496                    }
497                    else if (errorCode == 1005) {
498                            throw new IllegalArgumentException(
499                                    prefix + "Invalid " + string1 + " attribute in " + suffix);
500                    }
501                    else if (errorCode == 1006) {
502                            throw new IllegalArgumentException(
503                                    prefix + "Invalid " + string1 + " attribute value in " +
504                                            suffix);
505                    }
506                    else if (errorCode == 1007) {
507                            throw new IllegalArgumentException(
508                                    prefix + "Poorly formed XML in " + suffix, e);
509                    }
510                    else if (errorCode == 1008) {
511                            throw new IllegalArgumentException(
512                                    prefix + "Duplicate file name " + string1 + " at " + suffix);
513                    }
514                    else if (errorCode == 1009) {
515                            throw new IllegalArgumentException(
516                                    prefix + "Duplicate command name " + string1 + " at " + suffix);
517                    }
518                    else if (errorCode == 1010) {
519                            throw new IllegalArgumentException(
520                                    prefix + "Invalid locator-key " + string1 + " at " + suffix);
521                    }
522                    else if (errorCode == 1011) {
523                            throw new IllegalArgumentException(
524                                    prefix + "Invalid " + string1 + " name " + string2 + " at " +
525                                            suffix);
526                    }
527                    else if (errorCode == 1012) {
528                            throw new IllegalArgumentException(
529                                    prefix + "Invalid " + string1 + " command " + string2 + " at " +
530                                            suffix);
531                    }
532                    else if (errorCode == 1013) {
533                            throw new IllegalArgumentException(
534                                    prefix + "Invalid method " + string1 + " at " + suffix);
535                    }
536                    else if (errorCode == 1014) {
537                            throw new IllegalArgumentException(
538                                    prefix + "Invalid path " + string1 + " at " + suffix);
539                    }
540                    else if (errorCode == 1015) {
541                            throw new IllegalArgumentException(
542                                    prefix + "Poorly formed test case command " + string1 + " at " +
543                                            suffix);
544                    }
545                    else if (errorCode == 1016) {
546                            throw new IllegalArgumentException(
547                                    prefix + "Invalid " + string1 + " attribute value " + string2 +
548                                            " in " + suffix);
549                    }
550                    else if (errorCode == 1017) {
551                            throw new IllegalArgumentException(
552                                    prefix + "Description '" + string1 +
553                                            "' must end with a '.' in " + suffix);
554                    }
555                    else if (errorCode == 1018) {
556                            throw new IllegalArgumentException(
557                                    prefix + "Missing (" + StringUtil.merge(array, "|") +
558                                            ") in attribute " + string1 + " at " + suffix);
559                    }
560                    else if (errorCode == 2000) {
561                            throw new IllegalArgumentException(
562                                    prefix + "Too many child elements in the " + string1 +
563                                            " element in " + suffix);
564                    }
565                    else if (errorCode == 2001) {
566                            throw new IllegalArgumentException(
567                                    prefix + "Action command " + string1 +
568                                            " does not match a function name at " + suffix);
569                    }
570                    else if (errorCode == 2002) {
571                            throw new IllegalArgumentException(
572                                    prefix + "Missing matching " + string1 + ".path for " + suffix);
573                    }
574                    else if (errorCode == 2003) {
575                            throw new IllegalArgumentException(
576                                    prefix + "Illegal XPath " + string1 + " in " + suffix);
577                    }
578                    else if (errorCode == 2004) {
579                            throw new IllegalArgumentException(
580                                    prefix + "Description '" + string1 +
581                                            "' must title convention in " + suffix);
582                    }
583                    else if (errorCode == 3001) {
584                            throw new IllegalArgumentException(
585                                    prefix + "The property '" + string1 +
586                                            "' has an invalid component name '" + string2 + "' in " +
587                                                    suffix);
588                    }
589                    else if (errorCode == 3002) {
590                            throw new IllegalArgumentException(
591                                    prefix + "Missing property '" + string1 + "' for " + suffix);
592                    }
593                    else if (errorCode == 3003) {
594                            throw new IllegalArgumentException(
595                                    prefix + "Invalid property " + string1 + " at " + suffix);
596                    }
597                    else {
598                            throw new IllegalArgumentException(prefix + suffix);
599                    }
600            }
601    
602            protected void throwValidationException(
603                    int errorCode, String fileName, Exception e) {
604    
605                    throwValidationException(
606                            errorCode, fileName, null, null, null, null, e);
607            }
608    
609            protected void throwValidationException(
610                    int errorCode, String fileName, String string1) {
611    
612                    throwValidationException(
613                            errorCode, fileName, null, null, string1, null, null);
614            }
615    
616            protected void validate(String fileName, Element rootElement)
617                    throws Exception {
618    
619                    if (fileName.endsWith(".action")) {
620                            validateActionDocument(fileName, rootElement);
621                    }
622                    else if (fileName.endsWith(".function")) {
623                            validateFunctionDocument(fileName, rootElement);
624                    }
625                    else if (fileName.endsWith(".macro")) {
626                            validateMacroDocument(fileName, rootElement);
627                    }
628                    else if (fileName.endsWith(".path")) {
629                            validatePathDocument(fileName, rootElement);
630                    }
631                    else if (fileName.endsWith(".testcase")) {
632                            validateTestCaseDocument(fileName, rootElement);
633                    }
634            }
635    
636            protected void validateActionCommandElement(
637                    String fileName, Element commandElement,
638                    String[] allowedBlockChildElementNames,
639                    String[] allowedExecuteAttributeNames,
640                    String[] allowedExecuteChildElementNames) {
641    
642                    List<Element> elements = commandElement.elements();
643    
644                    if (elements.isEmpty()) {
645                            throwValidationException(
646                                    1001, fileName, commandElement,
647                                    new String[] {"case", "default"});
648                    }
649    
650                    for (Element element : elements) {
651                            List<Element> descriptionElements = element.elements("description");
652    
653                            String elementName = element.getName();
654    
655                            if (descriptionElements.size() > 1) {
656                                    throwValidationException(
657                                            2000, fileName, descriptionElements.get(1), elementName);
658                            }
659    
660                            List<Element> executeChildElements = element.elements("execute");
661    
662                            if (executeChildElements.size() > 1) {
663                                    throwValidationException(
664                                            2000, fileName, executeChildElements.get(1), elementName);
665                            }
666    
667                            if (elementName.equals("case")) {
668                                    List<Attribute> attributes = element.attributes();
669    
670                                    boolean hasNeededAttributeName = false;
671    
672                                    for (Attribute attribute : attributes) {
673                                            String attributeName = attribute.getName();
674    
675                                            if (attributeName.equals("comparator")) {
676                                                    String attributeValue = attribute.getValue();
677    
678                                                    if (!attributeValue.equals("contains") &&
679                                                            !attributeValue.equals("endsWith") &&
680                                                            !attributeValue.equals("equals") &&
681                                                            !attributeValue.equals("startsWith")) {
682    
683                                                            throwValidationException(
684                                                                    1006, fileName, element, attributeName);
685                                                    }
686                                            }
687                                            else if (attributeName.equals("locator1") ||
688                                                             attributeName.equals("locator2") ||
689                                                             attributeName.equals("locator-key1") ||
690                                                             attributeName.equals("locator-key2") ||
691                                                             attributeName.equals("value1") ||
692                                                             attributeName.equals("value2")) {
693    
694                                                    String attributeValue = attribute.getValue();
695    
696                                                    if (Validator.isNull(attributeValue)) {
697                                                            throwValidationException(
698                                                                    1006, fileName, element, attributeName);
699                                                    }
700    
701                                                    hasNeededAttributeName = true;
702                                            }
703    
704                                            if (!attributeName.equals("comparator") &&
705                                                    !attributeName.equals("line-number") &&
706                                                    !attributeName.equals("locator1") &&
707                                                    !attributeName.equals("locator2") &&
708                                                    !attributeName.equals("locator-key1") &&
709                                                    !attributeName.equals("locator-key2") &&
710                                                    !attributeName.equals("value1") &&
711                                                    !attributeName.equals("value2")) {
712    
713                                                    throwValidationException(
714                                                            1005, fileName, element, attributeName);
715                                            }
716    
717                                            if (attributeName.equals("locator") ||
718                                                    attributeName.equals("locator-key") ||
719                                                    attributeName.equals("value")) {
720    
721                                                    throwValidationException(
722                                                            1005, fileName, element, attributeName);
723                                            }
724                                    }
725    
726                                    if (!hasNeededAttributeName) {
727                                            throwValidationException(
728                                                    1004, fileName, element,
729                                                    new String[] {"locator1", "locator-key1", "value1"});
730                                    }
731    
732                                    validateBlockElement(
733                                            fileName, element, new String[] {"execute"},
734                                            new String[] {"function"}, new String[0], new String[0]);
735                            }
736                            else if (elementName.equals("default")) {
737                                    List<Attribute> attributes = element.attributes();
738    
739                                    if (attributes.size() != 1) {
740                                            Attribute attribute = attributes.get(1);
741    
742                                            String attributeName = attribute.getName();
743    
744                                            throwValidationException(
745                                                    1005, fileName, element, attributeName);
746                                    }
747    
748                                    validateBlockElement(
749                                            fileName, element, new String[] {"description", "execute"},
750                                            new String[] {"function"}, new String[0], new String[0]);
751                            }
752                            else {
753                                    throwValidationException(1002, fileName, element, elementName);
754                            }
755                    }
756            }
757    
758            protected void validateActionDocument(
759                    String fileName, Element rootElement) {
760    
761                    if (!Validator.equals(rootElement.getName(), "definition")) {
762                            throwValidationException(1000, fileName, rootElement);
763                    }
764    
765                    List<Element> elements = rootElement.elements();
766    
767                    if (elements.isEmpty()) {
768                            throwValidationException(
769                                    1001, fileName, rootElement, new String[] {"command"});
770                    }
771    
772                    for (Element element : elements) {
773                            String elementName = element.getName();
774    
775                            if (elementName.equals("command")) {
776                                    String attributeValue = element.attributeValue("name");
777    
778                                    if (attributeValue == null) {
779                                            throwValidationException(1003, fileName, element, "name");
780                                    }
781                                    else if (Validator.isNull(attributeValue)) {
782                                            throwValidationException(1006, fileName, element, "name");
783                                    }
784    
785                                    validateActionCommandElement(
786                                            fileName, element, new String[] {"execute"},
787                                            new String[] {"function"}, new String[0]);
788                            }
789                            else {
790                                    throwValidationException(1002, fileName, element, elementName);
791                            }
792                    }
793            }
794    
795            protected void validateBlockElement(
796                    String fileName, Element commandElement,
797                    String[] allowedBlockChildElementNames,
798                    String[] allowedExecuteAttributeNames,
799                    String[] allowedExecuteChildElementNames,
800                    String[] allowedIfConditionElementNames) {
801    
802                    List<Element> elements = commandElement.elements();
803    
804                    if (elements.isEmpty()) {
805                            throwValidationException(
806                                    1001, fileName, commandElement, allowedBlockChildElementNames);
807                    }
808    
809                    for (Element element : elements) {
810                            String elementName = element.getName();
811    
812                            if (!ArrayUtil.contains(
813                                            allowedBlockChildElementNames, elementName)) {
814    
815                                    throwValidationException(1002, fileName, element, elementName);
816                            }
817    
818                            if (elementName.equals("description")) {
819                                    validateSimpleElement(
820                                            fileName, element, new String[] {"message"});
821    
822                                    String message = element.attributeValue("message");
823    
824                                    if (!message.endsWith(".")) {
825                                            throwValidationException(
826                                                    1017, fileName, commandElement, message);
827                                    }
828                            }
829                            else if (elementName.equals("echo") || elementName.equals("fail")) {
830                                    validateSimpleElement(
831                                            fileName, element, new String[] {"message"});
832                            }
833                            else if (elementName.equals("execute")) {
834                                    validateExecuteElement(
835                                            fileName, element, allowedExecuteAttributeNames, ".+",
836                                            allowedExecuteChildElementNames);
837                            }
838                            else if (elementName.equals("for")) {
839                                    validateForElement(
840                                            fileName, element, new String[] {"list", "param"},
841                                            allowedBlockChildElementNames, allowedExecuteAttributeNames,
842                                            allowedExecuteChildElementNames,
843                                            allowedIfConditionElementNames);
844                            }
845                            else if (elementName.equals("if") || elementName.equals("while")) {
846                                    validateIfElement(
847                                            fileName, element, allowedBlockChildElementNames,
848                                            allowedExecuteAttributeNames,
849                                            allowedExecuteChildElementNames,
850                                            allowedIfConditionElementNames);
851                            }
852                            else if (elementName.equals("property")) {
853                                    validatePropertyElement(fileName, element);
854                            }
855                            else if (elementName.equals("take-screenshot")) {
856                                    validateSimpleElement(fileName, element, new String[0]);
857                            }
858                            else if (elementName.equals("var")) {
859                                    validateVarElement(fileName, element);
860                            }
861                            else {
862                                    throwValidationException(1002, fileName, element, elementName);
863                            }
864                    }
865            }
866    
867            protected void validateExecuteElement(
868                    String fileName, Element executeElement,
869                    String[] allowedExecuteAttributeNames,
870                    String allowedExecuteAttributeValuesRegex,
871                    String[] allowedExecuteChildElementNames) {
872    
873                    boolean hasAllowedAttributeName = false;
874    
875                    List<Attribute> attributes = executeElement.attributes();
876    
877                    for (Attribute attribute : attributes) {
878                            String attributeName = attribute.getName();
879    
880                            if (ArrayUtil.contains(
881                                            allowedExecuteAttributeNames, attributeName)) {
882    
883                                    hasAllowedAttributeName = true;
884    
885                                    break;
886                            }
887                    }
888    
889                    if (!hasAllowedAttributeName) {
890                            throwValidationException(
891                                    1004, fileName, executeElement, allowedExecuteAttributeNames);
892                    }
893    
894                    String action = executeElement.attributeValue("action");
895                    String function = executeElement.attributeValue("function");
896                    String macro = executeElement.attributeValue("macro");
897                    String selenium = executeElement.attributeValue("selenium");
898                    String testCase = executeElement.attributeValue("test-case");
899                    String testCaseCommand = executeElement.attributeValue(
900                            "test-case-command");
901                    String testClass = executeElement.attributeValue("test-class");
902    
903                    if (action != null) {
904                            if (Validator.isNull(action) ||
905                                    !action.matches(allowedExecuteAttributeValuesRegex)) {
906    
907                                    throwValidationException(
908                                            1006, fileName, executeElement, "action");
909                            }
910    
911                            for (Attribute attribute : attributes) {
912                                    String attributeName = attribute.getName();
913    
914                                    if (!attributeName.equals("action") &&
915                                            !attributeName.equals("line-number") &&
916                                            !attributeName.equals("locator1") &&
917                                            !attributeName.equals("locator2") &&
918                                            !attributeName.equals("locator-key1") &&
919                                            !attributeName.equals("locator-key2") &&
920                                            !attributeName.equals("value1") &&
921                                            !attributeName.equals("value2")) {
922    
923                                            throwValidationException(
924                                                    1005, fileName, executeElement, attributeName);
925                                    }
926    
927                                    if (attributeName.equals("locator") ||
928                                            attributeName.equals("locator-key") ||
929                                            attributeName.equals("value")) {
930    
931                                            throwValidationException(
932                                                    1005, fileName, executeElement, attributeName);
933                                    }
934    
935                                    String attributeValue = attribute.getValue();
936    
937                                    if (attributeName.equals("value1") &&
938                                            attributeValue.contains("move-file")) {
939    
940                                            if (!attributeValue.contains("-Dfile") ||
941                                                    !attributeValue.contains("-Dtofile")) {
942    
943                                                    throwValidationException(
944                                                            1018, fileName, executeElement,
945                                                            new String[] {"-Dfile", "-Dtofile"}, "value1");
946                                            }
947                                    }
948    
949                                    if (attributeName.equals("value1") &&
950                                            attributeValue.contains("replace-file")) {
951    
952                                            if (!attributeValue.contains("-Dfile") ||
953                                                    !attributeValue.contains("-Dtoken") ||
954                                                    !attributeValue.contains("-Dvalue")) {
955    
956                                                    throwValidationException(
957                                                            1018, fileName, executeElement,
958                                                            new String[] {"-Dfile", "-Dtoken", "-Dvalue"},
959                                                            "value1");
960                                            }
961                                    }
962                            }
963                    }
964                    else if (function != null) {
965                            if (Validator.isNull(function) ||
966                                    !function.matches(allowedExecuteAttributeValuesRegex)) {
967    
968                                    throwValidationException(
969                                            1006, fileName, executeElement, "function");
970                            }
971    
972                            for (Attribute attribute : attributes) {
973                                    String attributeName = attribute.getName();
974    
975                                    if (!attributeName.equals("function") &&
976                                            !attributeName.equals("ignore-javascript-error") &&
977                                            !attributeName.equals("line-number") &&
978                                            !attributeName.startsWith("locator") &&
979                                            !attributeName.startsWith("value")) {
980    
981                                            throwValidationException(
982                                                    1005, fileName, executeElement, attributeName);
983                                    }
984    
985                                    if (attributeName.equals("locator") ||
986                                            attributeName.equals("value")) {
987    
988                                            throwValidationException(
989                                                    1005, fileName, executeElement, attributeName);
990                                    }
991                            }
992                    }
993                    else if (macro != null) {
994                            if (Validator.isNull(macro) ||
995                                    !macro.matches(allowedExecuteAttributeValuesRegex)) {
996    
997                                    throwValidationException(
998                                            1006, fileName, executeElement, "macro");
999                            }
1000    
1001                            for (Attribute attribute : attributes) {
1002                                    String attributeName = attribute.getName();
1003    
1004                                    if (!attributeName.equals("macro") &&
1005                                            !attributeName.equals("line-number")) {
1006    
1007                                            throwValidationException(
1008                                                    1005, fileName, executeElement, attributeName);
1009                                    }
1010                            }
1011                    }
1012                    else if (selenium != null) {
1013                            if (Validator.isNull(selenium) ||
1014                                    !selenium.matches(allowedExecuteAttributeValuesRegex)) {
1015    
1016                                    throwValidationException(
1017                                            1006, fileName, executeElement, "selenium");
1018                            }
1019    
1020                            for (Attribute attribute : attributes) {
1021                                    String attributeName = attribute.getName();
1022    
1023                                    if (!attributeName.equals("argument1") &&
1024                                            !attributeName.equals("argument2") &&
1025                                            !attributeName.equals("line-number") &&
1026                                            !attributeName.equals("selenium")) {
1027    
1028                                            throwValidationException(
1029                                                    1005, fileName, executeElement, attributeName);
1030                                    }
1031                            }
1032                    }
1033                    else if (testCase != null) {
1034                            if (Validator.isNull(testCase) ||
1035                                    !testCase.matches(allowedExecuteAttributeValuesRegex)) {
1036    
1037                                    throwValidationException(
1038                                            1006, fileName, executeElement, "test-case");
1039                            }
1040    
1041                            if (testCase.contains("#")) {
1042                                    int x = testCase.lastIndexOf("#");
1043    
1044                                    if (x == -1) {
1045                                            throwValidationException(
1046                                                    1015, fileName, executeElement, testCaseCommand);
1047                                    }
1048    
1049                                    String testCaseName = testCase.substring(0, x);
1050    
1051                                    String testCaseCommandName = testCase.substring(x + 1);
1052    
1053                                    if (Validator.isNull(testCaseCommandName) ||
1054                                            Validator.isNull(testCaseName) ||
1055                                            !testCaseName.equals("super")) {
1056    
1057                                            throwValidationException(
1058                                                    1015, fileName, executeElement, testCase);
1059                                    }
1060                            }
1061                            else {
1062                                    throwValidationException(
1063                                            1015, fileName, executeElement, testCase);
1064                            }
1065    
1066                            for (Attribute attribute : attributes) {
1067                                    String attributeName = attribute.getName();
1068    
1069                                    if (!attributeName.equals("line-number") &&
1070                                            !attributeName.equals("test-case")) {
1071    
1072                                            throwValidationException(
1073                                                    1005, fileName, executeElement, attributeName);
1074                                    }
1075                            }
1076                    }
1077                    else if (testCaseCommand != null) {
1078                            if (Validator.isNull(testCaseCommand) ||
1079                                    !testCaseCommand.matches(allowedExecuteAttributeValuesRegex)) {
1080    
1081                                    throwValidationException(
1082                                            1006, fileName, executeElement, "test-case-command");
1083                            }
1084    
1085                            if (testCaseCommand.contains("#")) {
1086                                    int x = testCaseCommand.lastIndexOf("#");
1087    
1088                                    String testCaseName = testCaseCommand.substring(0, x);
1089    
1090                                    String testCaseCommandName = testCaseCommand.substring(x + 1);
1091    
1092                                    if (Validator.isNull(testCaseCommandName) ||
1093                                            Validator.isNull(testCaseName)) {
1094    
1095                                            throwValidationException(
1096                                                    1015, fileName, executeElement, testCaseCommand);
1097                                    }
1098                            }
1099                            else {
1100                                    throwValidationException(
1101                                            1015, fileName, executeElement, testCaseCommand);
1102                            }
1103    
1104                            for (Attribute attribute : attributes) {
1105                                    String attributeName = attribute.getName();
1106    
1107                                    if (!attributeName.equals("line-number") &&
1108                                            !attributeName.equals("test-case-command")) {
1109    
1110                                            throwValidationException(
1111                                                    1005, fileName, executeElement, attributeName);
1112                                    }
1113                            }
1114                    }
1115                    else if (testClass != null) {
1116                            if (Validator.isNull(testClass) ||
1117                                    !testClass.matches(allowedExecuteAttributeValuesRegex)) {
1118    
1119                                    throwValidationException(
1120                                            1006, fileName, executeElement, "test-class");
1121                            }
1122    
1123                            for (Attribute attribute : attributes) {
1124                                    String attributeName = attribute.getName();
1125    
1126                                    if (!attributeName.equals("line-number") &&
1127                                            !attributeName.equals("test-class")) {
1128    
1129                                            throwValidationException(
1130                                                    1005, fileName, executeElement, attributeName);
1131                                    }
1132                            }
1133                    }
1134                    else {
1135                            throwValidationException(0, fileName);
1136                    }
1137    
1138                    List<Element> elements = executeElement.elements();
1139    
1140                    if (allowedExecuteChildElementNames.length == 0) {
1141                            if (!elements.isEmpty()) {
1142                                    Element element = elements.get(0);
1143    
1144                                    String elementName = element.getName();
1145    
1146                                    throwValidationException(1002, fileName, element, elementName);
1147                            }
1148                    }
1149                    else {
1150                            String executeElementName = executeElement.getName();
1151    
1152                            for (Element element : elements) {
1153                                    String elementName = element.getName();
1154    
1155                                    if (executeElementName.equals("condition")) {
1156                                            throwValidationException(
1157                                                    1002, fileName, element, elementName);
1158                                    }
1159    
1160                                    if (elementName.equals("var")) {
1161                                            validateVarElement(fileName, element);
1162                                    }
1163                                    else {
1164                                            throwValidationException(
1165                                                    1002, fileName, element, elementName);
1166                                    }
1167                            }
1168                    }
1169            }
1170    
1171            protected void validateForElement(
1172                    String fileName, Element forElement, String[] neededAttributes,
1173                    String[] allowedBlockChildElementNames,
1174                    String[] allowedExecuteAttributeNames,
1175                    String[] allowedExecuteChildElementNames,
1176                    String[] allowedIfConditionElementNames) {
1177    
1178                    Map<String, Boolean> hasNeededAttributes =
1179                            new HashMap<String, Boolean>();
1180    
1181                    for (String neededAttribute : neededAttributes) {
1182                            hasNeededAttributes.put(neededAttribute, false);
1183                    }
1184    
1185                    List<Attribute> attributes = forElement.attributes();
1186    
1187                    for (Attribute attribute : attributes) {
1188                            String attributeName = attribute.getName();
1189                            String attributeValue = attribute.getValue();
1190    
1191                            if (!_allowedNullAttributes.contains(attributeName) &&
1192                                    Validator.isNull(attributeValue)) {
1193    
1194                                    throwValidationException(
1195                                            1006, fileName, forElement, attributeName);
1196                            }
1197    
1198                            if (hasNeededAttributes.containsKey(attributeName)) {
1199                                    hasNeededAttributes.put(attributeName, true);
1200                            }
1201    
1202                            if (!attributeName.equals("line-number") &&
1203                                    !hasNeededAttributes.containsKey(attributeName)) {
1204    
1205                                    throwValidationException(
1206                                            1005, fileName, forElement, attributeName);
1207                            }
1208                    }
1209    
1210                    for (String neededAttribute : neededAttributes) {
1211                            if (!hasNeededAttributes.get(neededAttribute)) {
1212                                    throwValidationException(
1213                                            1004, fileName, forElement, neededAttributes);
1214                            }
1215                    }
1216    
1217                    validateBlockElement(
1218                            fileName, forElement, allowedBlockChildElementNames,
1219                            allowedExecuteAttributeNames, allowedExecuteChildElementNames,
1220                            allowedIfConditionElementNames);
1221            }
1222    
1223            protected void validateFunctionDocument(
1224                    String fileName, Element rootElement) {
1225    
1226                    if (!Validator.equals(rootElement.getName(), "definition")) {
1227                            throwValidationException(1000, fileName, rootElement);
1228                    }
1229    
1230                    List<Element> elements = rootElement.elements();
1231    
1232                    if (elements.isEmpty()) {
1233                            throwValidationException(
1234                                    1001, fileName, rootElement, new String[] {"command"});
1235                    }
1236    
1237                    for (Element element : elements) {
1238                            String elementName = element.getName();
1239    
1240                            if (elementName.equals("command")) {
1241                                    String attributeValue = element.attributeValue("name");
1242    
1243                                    if (attributeValue == null) {
1244                                            throwValidationException(1003, fileName, element, "name");
1245                                    }
1246                                    else if (Validator.isNull(attributeValue)) {
1247                                            throwValidationException(1006, fileName, element, "name");
1248                                    }
1249    
1250                                    validateBlockElement(
1251                                            fileName, element, new String[] {"execute", "if"},
1252                                            new String[] {"function", "selenium"}, new String[0],
1253                                            new String[] {"condition"});
1254                            }
1255                            else {
1256                                    throwValidationException(1002, fileName, element, elementName);
1257                            }
1258                    }
1259            }
1260    
1261            protected void validateIfElement(
1262                    String fileName, Element ifElement,
1263                    String[] allowedBlockChildElementNames,
1264                    String[] allowedExecuteAttributeNames,
1265                    String[] allowedExecuteChildElementNames,
1266                    String[] allowedIfConditionElementNames) {
1267    
1268                    List<Element> elements = ifElement.elements();
1269    
1270                    Set<String> elementNames = new HashSet<String>();
1271    
1272                    boolean hasAllowedIfConditionElementNames = false;
1273    
1274                    for (Element element : elements) {
1275                            String elementName = element.getName();
1276    
1277                            elementNames.add(elementName);
1278    
1279                            if (ArrayUtil.contains(
1280                                            allowedIfConditionElementNames, elementName)) {
1281    
1282                                    hasAllowedIfConditionElementNames = true;
1283                            }
1284    
1285                            String ifElementName = ifElement.getName();
1286    
1287                            if (elementName.equals("and") || elementName.equals("not") ||
1288                                    elementName.equals("or")) {
1289    
1290                                    validateIfElement(
1291                                            fileName, element, allowedBlockChildElementNames,
1292                                            allowedExecuteAttributeNames,
1293                                            allowedExecuteChildElementNames,
1294                                            allowedIfConditionElementNames);
1295                            }
1296                            else if (elementName.equals("condition")) {
1297                                    validateExecuteElement(
1298                                            fileName, element, allowedExecuteAttributeNames,
1299                                            ".*(is|Is).+", allowedExecuteChildElementNames);
1300                            }
1301                            else if (elementName.equals("contains")) {
1302                                    validateSimpleElement(
1303                                            fileName, element, new String[] {"string", "substring"});
1304                            }
1305                            else if (elementName.equals("else")) {
1306                                    if (ifElementName.equals("while")) {
1307                                            throwValidationException(
1308                                                    1002, fileName, element, elementName);
1309                                    }
1310    
1311                                    validateBlockElement(
1312                                            fileName, element, allowedBlockChildElementNames,
1313                                            allowedExecuteAttributeNames,
1314                                            allowedExecuteChildElementNames,
1315                                            allowedIfConditionElementNames);
1316                            }
1317                            else if (elementName.equals("elseif")) {
1318                                    if (ifElementName.equals("while")) {
1319                                            throwValidationException(
1320                                                    1002, fileName, element, elementName);
1321                                    }
1322    
1323                                    validateIfElement(
1324                                            fileName, element, allowedBlockChildElementNames,
1325                                            allowedExecuteAttributeNames,
1326                                            allowedExecuteChildElementNames,
1327                                            allowedIfConditionElementNames);
1328                            }
1329                            else if (elementName.equals("equals")) {
1330                                    validateSimpleElement(
1331                                            fileName, element, new String[] {"arg1", "arg2"});
1332                            }
1333                            else if (elementName.equals("isset")) {
1334                                    validateSimpleElement(fileName, element, new String[] {"var"});
1335                            }
1336                            else if (elementName.equals("then")) {
1337                                    validateBlockElement(
1338                                            fileName, element, allowedBlockChildElementNames,
1339                                            allowedExecuteAttributeNames,
1340                                            allowedExecuteChildElementNames,
1341                                            allowedIfConditionElementNames);
1342                            }
1343                            else {
1344                                    throwValidationException(1002, fileName, element, elementName);
1345                            }
1346                    }
1347    
1348                    if (!hasAllowedIfConditionElementNames) {
1349                            throwValidationException(
1350                                    1001, fileName, ifElement, allowedIfConditionElementNames);
1351                    }
1352    
1353                    if (Validator.equals(ifElement.getName(), "and") ||
1354                            Validator.equals(ifElement.getName(), "not") ||
1355                            Validator.equals(ifElement.getName(), "or")) {
1356    
1357                            return;
1358                    }
1359    
1360                    if (!elementNames.contains("then")) {
1361                            throwValidationException(
1362                                    1001, fileName, ifElement, new String[] {"then"});
1363                    }
1364            }
1365    
1366            protected void validateMacroDocument(String fileName, Element rootElement) {
1367                    if (!Validator.equals(rootElement.getName(), "definition")) {
1368                            throwValidationException(1000, fileName, rootElement);
1369                    }
1370    
1371                    List<Element> elements = rootElement.elements();
1372    
1373                    String extendsName = rootElement.attributeValue("extends");
1374    
1375                    if (elements.isEmpty() && (extendsName == null)) {
1376                            throwValidationException(
1377                                    1001, fileName, rootElement, new String[] {"command", "var"});
1378                    }
1379                    else if (extendsName != null) {
1380                            if (Validator.isNull(extendsName)) {
1381                                    throwValidationException(
1382                                            1006, fileName, rootElement, "extends");
1383                            }
1384                    }
1385    
1386                    for (Element element : elements) {
1387                            String elementName = element.getName();
1388    
1389                            if (elementName.equals("command")) {
1390                                    String attributeValue = element.attributeValue("name");
1391    
1392                                    if (attributeValue == null) {
1393                                            throwValidationException(1003, fileName, element, "name");
1394                                    }
1395                                    else if (Validator.isNull(attributeValue)) {
1396                                            throwValidationException(1006, fileName, element, "name");
1397                                    }
1398    
1399                                    validateBlockElement(
1400                                            fileName, element,
1401                                            new String[] {
1402                                                    "description", "echo", "execute", "fail", "for", "if",
1403                                                    "take-screenshot", "var", "while",
1404                                            },
1405                                            new String[] {"action", "function", "macro"},
1406                                            new String[] {"var"},
1407                                            new String[] {
1408                                                    "and", "condition", "contains", "equals", "isset",
1409                                                    "not", "or"
1410                                            });
1411                            }
1412                            else if (elementName.equals("var")) {
1413                                    validateVarElement(fileName, element);
1414                            }
1415                            else {
1416                                    throwValidationException(1002, fileName, element, elementName);
1417                            }
1418                    }
1419            }
1420    
1421            protected void validatePathDocument(String fileName, Element rootElement) {
1422                    Element headElement = rootElement.element("head");
1423    
1424                    Element titleElement = headElement.element("title");
1425    
1426                    String title = titleElement.getText();
1427    
1428                    int x = fileName.lastIndexOf(StringPool.SLASH);
1429                    int y = fileName.lastIndexOf(CharPool.PERIOD);
1430    
1431                    String shortFileName = fileName.substring(x + 1, y);
1432    
1433                    if ((title == null) || !shortFileName.equals(title)) {
1434                            throwValidationException(0, fileName);
1435                    }
1436    
1437                    Element bodyElement = rootElement.element("body");
1438    
1439                    Element tableElement = bodyElement.element("table");
1440    
1441                    Element theadElement = tableElement.element("thead");
1442    
1443                    Element trElement = theadElement.element("tr");
1444    
1445                    Element tdElement = trElement.element("td");
1446    
1447                    String tdText = tdElement.getText();
1448    
1449                    if ((tdText == null) || !shortFileName.equals(tdText)) {
1450                            throwValidationException(0, fileName);
1451                    }
1452    
1453                    Element tbodyElement = tableElement.element("tbody");
1454    
1455                    List<Element> elements = tbodyElement.elements();
1456    
1457                    for (Element element : elements) {
1458                            String elementName = element.getName();
1459    
1460                            if (elementName.equals("tr")) {
1461                                    validatePathTrElement(fileName, element);
1462                            }
1463                            else {
1464                                    throwValidationException(1002, fileName, element, elementName);
1465                            }
1466                    }
1467            }
1468    
1469            protected void validatePathTrElement(String fileName, Element trElement) {
1470                    List<Element> elements = trElement.elements();
1471    
1472                    for (Element element : elements) {
1473                            String elementName = element.getName();
1474    
1475                            if (!elementName.equals("td")) {
1476                                    throwValidationException(1002, fileName, element, elementName);
1477                            }
1478                    }
1479    
1480                    if (elements.size() < 3) {
1481                            throwValidationException(
1482                                    1001, fileName, trElement, new String[] {"td"});
1483                    }
1484    
1485                    if (elements.size() > 3) {
1486                            Element element = elements.get(3);
1487    
1488                            String elementName = element.getName();
1489    
1490                            throwValidationException(1002, fileName, element, elementName);
1491                    }
1492    
1493                    Element locatorElement = elements.get(1);
1494    
1495                    String locator = locatorElement.getText();
1496    
1497                    locator = locator.replace("${","");
1498                    locator = locator.replace("}","");
1499                    locator = locator.replace("/-/","/");
1500    
1501                    if (locator.endsWith("/")) {
1502                            locator = locator.substring(0, locator.length() - 1);
1503                    }
1504    
1505                    if (!locator.equals("") && !locator.startsWith("link=") &&
1506                            !locator.startsWith("title=") && !locator.contains(".png")) {
1507    
1508                            try {
1509                                    XPathFactory xPathFactory = XPathFactory.newInstance();
1510    
1511                                    XPath xPath = xPathFactory.newXPath();
1512    
1513                                    xPath.compile(locator);
1514                            }
1515                            catch (Exception e) {
1516                                    throwValidationException(2003, fileName, locator);
1517                            }
1518                    }
1519    
1520                    Element keyElement = elements.get(0);
1521    
1522                    String key = keyElement.getText();
1523    
1524                    Element descriptionElement = elements.get(2);
1525    
1526                    String description = descriptionElement.getText();
1527    
1528                    if (!key.equals("") && !key.equals("EXTEND_ACTION_PATH") &&
1529                            !key.equals("PAGE_NAME") && !description.equals("")) {
1530    
1531                            if (description.endsWith(".")) {
1532                                    throwValidationException(2004, fileName, description);
1533                            }
1534    
1535                            Matcher statmentMatcher = _pathTrElementStatementPattern.matcher(
1536                                    description);
1537    
1538                            if (!statmentMatcher.find()) {
1539                                    throwValidationException(2004, fileName, description);
1540                            }
1541    
1542                            Matcher wordMatcher1 = _pathTrElementWordPattern1.matcher(
1543                                    description);
1544    
1545                            while (wordMatcher1.find()) {
1546                                    String word = wordMatcher1.group();
1547    
1548                                    if (word.equals("a") || word.equals("and") ||
1549                                            word.equals("as") || word.equals("at") ||
1550                                            word.equals("by") || word.equals("for") ||
1551                                            word.equals("from") || word.equals("in") ||
1552                                            word.equals("of") || word.equals("the") ||
1553                                            word.equals("to")) {
1554    
1555                                            continue;
1556                                    }
1557    
1558                                    Matcher wordMatcher2 = _pathTrElementWordPattern2.matcher(word);
1559    
1560                                    if (!wordMatcher2.find()) {
1561                                            throwValidationException(2004, fileName, description);
1562                                    }
1563                            }
1564                    }
1565            }
1566    
1567            protected void validatePropertyElement(
1568                    String fileName, Element propertyElement) {
1569    
1570                    List<Attribute> attributes = propertyElement.attributes();
1571    
1572                    String propertyName = propertyElement.attributeValue("name");
1573    
1574                    if (!_testcaseAvailablePropertyNames.contains(propertyName)) {
1575                            throwValidationException(
1576                                    3003, fileName, propertyElement, propertyName);
1577                    }
1578    
1579                    if (propertyName.equals("ignore.errors")) {
1580                            String propertyDelimiter = propertyElement.attributeValue(
1581                                    "delimiter");
1582    
1583                            String propertyValue = propertyElement.attributeValue("value");
1584    
1585                            if (propertyDelimiter != null) {
1586                                    if (!propertyValue.contains(propertyDelimiter)) {
1587                                            throwValidationException(
1588                                                    1006, fileName, propertyElement, "delimiter");
1589                                    }
1590                            }
1591    
1592                            if (Validator.isNull(propertyValue)) {
1593                                    throwValidationException(
1594                                            1006, fileName, propertyElement, "value");
1595                            }
1596                    }
1597    
1598                    for (Attribute attribute : attributes) {
1599                            String attributeName = attribute.getName();
1600    
1601                            if (attributeName.equals("delimiter") &&
1602                                    propertyName.equals("ignore.errors")) {
1603    
1604                                    continue;
1605                            }
1606                            else if (attributeName.equals("line-number") ||
1607                                             attributeName.equals("name") ||
1608                                             attributeName.equals("value")) {
1609    
1610                                    continue;
1611                            }
1612                            else {
1613                                    throwValidationException(
1614                                            1005, fileName, propertyElement, attributeName);
1615                            }
1616                    }
1617            }
1618    
1619            protected void validateSimpleElement(
1620                    String fileName, Element element, String[] neededAttributes) {
1621    
1622                    Map<String, Boolean> hasNeededAttributes =
1623                            new HashMap<String, Boolean>();
1624    
1625                    for (String neededAttribute : neededAttributes) {
1626                            hasNeededAttributes.put(neededAttribute, false);
1627                    }
1628    
1629                    List<Attribute> attributes = element.attributes();
1630    
1631                    for (Attribute attribute : attributes) {
1632                            String attributeName = attribute.getName();
1633                            String attributeValue = attribute.getValue();
1634    
1635                            if (!_allowedNullAttributes.contains(attributeName) &&
1636                                    Validator.isNull(attributeValue)) {
1637    
1638                                    throwValidationException(
1639                                            1006, fileName, element, attributeName);
1640                            }
1641    
1642                            if (hasNeededAttributes.containsKey(attributeName)) {
1643                                    hasNeededAttributes.put(attributeName, true);
1644                            }
1645    
1646                            if (!attributeName.equals("line-number") &&
1647                                    !hasNeededAttributes.containsKey(attributeName)) {
1648    
1649                                    throwValidationException(
1650                                            1005, fileName, element, attributeName);
1651                            }
1652                    }
1653    
1654                    for (String neededAttribute : neededAttributes) {
1655                            if (!hasNeededAttributes.get(neededAttribute)) {
1656                                    throwValidationException(
1657                                            1004, fileName, element, neededAttributes);
1658                            }
1659                    }
1660    
1661                    List<Element> childElements = element.elements();
1662    
1663                    if (!childElements.isEmpty()) {
1664                            Element childElement = childElements.get(0);
1665    
1666                            String childElementName = childElement.getName();
1667    
1668                            throwValidationException(
1669                                    1002, fileName, childElement, childElementName);
1670                    }
1671            }
1672    
1673            protected void validateTestCaseDocument(
1674                    String fileName, Element rootElement) {
1675    
1676                    if (!Validator.equals(rootElement.getName(), "definition")) {
1677                            throwValidationException(1000, fileName, rootElement);
1678                    }
1679    
1680                    String extendedTestCase = rootElement.attributeValue("extends");
1681    
1682                    if (extendedTestCase != null) {
1683                            if (Validator.isNull(extendedTestCase)) {
1684                                    throwValidationException(
1685                                            1006, fileName, rootElement, "extends");
1686                            }
1687                    }
1688    
1689                    String componentName = rootElement.attributeValue("component-name");
1690    
1691                    if (componentName == null) {
1692                            throwValidationException(
1693                                    1003, fileName, rootElement, "component-name");
1694                    }
1695    
1696                    if ((componentName != null) &&
1697                            !_componentNames.contains(componentName)) {
1698    
1699                            throwValidationException(
1700                                    1006, fileName, rootElement, "component-name");
1701                    }
1702    
1703                    List<Element> elements = rootElement.elements();
1704    
1705                    if (Validator.isNull(extendedTestCase)) {
1706                            if (elements.isEmpty()) {
1707                                    throwValidationException(
1708                                            1001, fileName, rootElement, new String[] {"command"});
1709                            }
1710                    }
1711    
1712                    for (Element element : elements) {
1713                            String elementName = element.getName();
1714    
1715                            if (elementName.equals("command")) {
1716                                    String attributeValue = element.attributeValue("name");
1717    
1718                                    if (attributeValue == null) {
1719                                            throwValidationException(1003, fileName, element, "name");
1720                                    }
1721                                    else if (Validator.isNull(attributeValue)) {
1722                                            throwValidationException(1006, fileName, element, "name");
1723                                    }
1724    
1725                                    String priorityValue = element.attributeValue("priority");
1726    
1727                                    if (priorityValue == null) {
1728                                            throwValidationException(
1729                                                    1003, fileName, element, "priority");
1730                                    }
1731                                    else if (!(priorityValue.equals("1") ||
1732                                                       priorityValue.equals("2") ||
1733                                                       priorityValue.equals("3") ||
1734                                                       priorityValue.equals("4") ||
1735                                                       priorityValue.equals("5"))) {
1736    
1737                                            throwValidationException(
1738                                                    1006, fileName, element, "priority");
1739                                    }
1740    
1741                                    validateBlockElement(
1742                                            fileName, element,
1743                                            new String[] {
1744                                                    "description", "echo", "execute", "fail", "for", "if",
1745                                                    "property", "take-screenshot", "var", "while"
1746                                            },
1747                                            new String[] {"action", "function", "macro", "test-case"},
1748                                            new String[] {"var"},
1749                                            new String[] {
1750                                                    "and", "condition", "contains", "equals", "isset",
1751                                                    "not", "or"
1752                                            });
1753                            }
1754                            else if (elementName.equals("property")) {
1755                                    validatePropertyElement(fileName, element);
1756                            }
1757                            else if (elementName.equals("set-up") ||
1758                                             elementName.equals("tear-down")) {
1759    
1760                                    List<Attribute> attributes = element.attributes();
1761    
1762                                    for (Attribute attribute : attributes) {
1763                                            String attributeName = attribute.getName();
1764    
1765                                            if (!attributeName.equals("line-number")) {
1766                                                    throwValidationException(
1767                                                            1005, fileName, element, attributeName);
1768                                            }
1769                                    }
1770    
1771                                    validateBlockElement(
1772                                            fileName, element,
1773                                            new String[] {
1774                                                    "description", "echo", "execute", "fail", "if",
1775                                                    "take-screenshot", "var", "while"
1776                                            },
1777                                            new String[] {"action", "function", "macro", "test-case"},
1778                                            new String[] {"var"},
1779                                            new String[] {
1780                                                    "and", "condition", "contains", "equals", "isset",
1781                                                    "not", "or"
1782                                            });
1783                            }
1784                            else if (elementName.equals("var")) {
1785                                    validateVarElement(fileName, element);
1786                            }
1787                            else {
1788                                    throwValidationException(1002, fileName, element, elementName);
1789                            }
1790                    }
1791    
1792                    elements = getAllChildElements(rootElement, "property");
1793    
1794                    for (Element element : elements) {
1795                            String name = element.attributeValue("name");
1796                            String value = element.attributeValue("value");
1797    
1798                            if (name.equals("testray.component.names")) {
1799                                    List<String> testrayComponentNames = ListUtil.fromArray(
1800                                            StringUtil.split(value));
1801    
1802                                    for (String testrayComponentName : testrayComponentNames) {
1803                                            if (!_testrayAvailableComponentNames.contains(
1804                                                            testrayComponentName)) {
1805    
1806                                                    throwValidationException(
1807                                                            3001, fileName, element, name,
1808                                                            testrayComponentName);
1809                                            }
1810                                    }
1811                            }
1812                            else if (name.equals("testray.main.component.name")) {
1813                                    if (!_testrayAvailableComponentNames.contains(value)) {
1814                                            throwValidationException(
1815                                                    3001, fileName, element, name, value);
1816                                    }
1817                            }
1818                    }
1819    
1820                    elements = rootElement.elements("property");
1821    
1822                    boolean rootTestrayMainComponentNameFound = false;
1823    
1824                    for (Element element : elements) {
1825                            String name = element.attributeValue("name");
1826    
1827                            if (name.equals("testray.main.component.name")) {
1828                                    rootTestrayMainComponentNameFound = true;
1829    
1830                                    break;
1831                            }
1832                    }
1833    
1834                    if (!rootTestrayMainComponentNameFound) {
1835                            elements = rootElement.elements("command");
1836    
1837                            for (Element element : elements) {
1838                                    List<Element> propertyElements = getAllChildElements(
1839                                            element, "property");
1840    
1841                                    boolean commandTestrayMainComponentNameFound = false;
1842    
1843                                    for (Element propertyElement : propertyElements) {
1844                                            String propertyName = propertyElement.attributeValue(
1845                                                    "name");
1846    
1847                                            if (propertyName.equals("testray.main.component.name")) {
1848                                                    commandTestrayMainComponentNameFound = true;
1849    
1850                                                    break;
1851                                            }
1852                                    }
1853    
1854                                    if (!commandTestrayMainComponentNameFound) {
1855                                            throwValidationException(
1856                                                    3002, fileName, element, "testray.main.component.name");
1857                                    }
1858                            }
1859                    }
1860            }
1861    
1862            protected void validateVarElement(String fileName, Element element) {
1863                    List<Attribute> attributes = element.attributes();
1864    
1865                    Map<String, String> attributeMap = new HashMap<String, String>();
1866    
1867                    for (Attribute attribute : attributes) {
1868                            String attributeName = attribute.getName();
1869                            String attributeValue = attribute.getValue();
1870    
1871                            if (!attributeName.equals("value") &&
1872                                    Validator.isNull(attributeValue)) {
1873    
1874                                    throwValidationException(
1875                                            1006, fileName, element, attributeName);
1876                            }
1877    
1878                            if (!_allowedVarAttributes.contains(attributeName)) {
1879                                    throwValidationException(
1880                                            1005, fileName, element, attributeName);
1881                            }
1882    
1883                            attributeMap.put(attributeName, attributeValue);
1884                    }
1885    
1886                    if (!attributeMap.containsKey("name")) {
1887                            throwValidationException(
1888                                    1004, fileName, element, new String[] {"name"});
1889                    }
1890                    else {
1891                            String nameValue = attributeMap.get("name");
1892    
1893                            if (Validator.isNull(nameValue)) {
1894                                    throwValidationException(1006, fileName, element, "name");
1895                            }
1896                    }
1897    
1898                    if (attributeMap.containsKey("locator")) {
1899                            String[] disallowedAttributes = {"locator-key", "path", "value"};
1900    
1901                            for (String disallowedAttribute : disallowedAttributes) {
1902                                    if (attributeMap.containsKey(disallowedAttribute)) {
1903                                            throwValidationException(
1904                                                    1005, fileName, element, disallowedAttribute);
1905                                    }
1906                            }
1907                    }
1908                    else if (attributeMap.containsKey("locator-key") &&
1909                                     attributeMap.containsKey("path")) {
1910    
1911                            if (attributeMap.containsKey("value")) {
1912                                    throwValidationException(1005, fileName, element, "value");
1913                            }
1914                    }
1915                    else if (attributeMap.containsKey("locator-key")) {
1916                            throwValidationException(
1917                                    1004, fileName, element, new String [] {"path"});
1918                    }
1919                    else if (attributeMap.containsKey("path")) {
1920                            throwValidationException(
1921                                    1004, fileName, element, new String [] {"locator-key"});
1922                    }
1923    
1924                    String varText = element.getText();
1925    
1926                    if (attributeMap.containsKey("locator") ||
1927                            attributeMap.containsKey("locator-key") ||
1928                            attributeMap.containsKey("path")) {
1929    
1930                            if (!Validator.isNull(varText)) {
1931                                    throwValidationException(1005, fileName, element, "value");
1932                            }
1933                    }
1934    
1935                    if (attributeMap.containsKey("method")) {
1936                            String methodValue = attributeMap.get("method");
1937    
1938                            if (!methodValue.startsWith("MathUtil") &&
1939                                    !methodValue.startsWith("selenium") &&
1940                                    !methodValue.startsWith("StringUtil")) {
1941    
1942                                    throwValidationException(1005, fileName, element, "method");
1943                            }
1944    
1945                            if (!methodValue.contains("#")) {
1946                                    throwValidationException(1005, fileName, element, "method");
1947                            }
1948                    }
1949    
1950                    if (!attributeMap.containsKey("property-value") &&
1951                            !attributeMap.containsKey("value") && Validator.isNull(varText)) {
1952    
1953                            if (!attributeMap.containsKey("group") &&
1954                                    !attributeMap.containsKey("input") &&
1955                                    !attributeMap.containsKey("locator") &&
1956                                    !attributeMap.containsKey("locator-key") &&
1957                                    !attributeMap.containsKey("method") &&
1958                                    !attributeMap.containsKey("path") &&
1959                                    !attributeMap.containsKey("pattern")) {
1960    
1961                                    throwValidationException(
1962                                            1004, fileName, element, new String [] {"value"});
1963                            }
1964                    }
1965                    else {
1966                            String varValue = attributeMap.get("value");
1967    
1968                            if (Validator.isNull(varValue)) {
1969                                    varValue = varText;
1970                            }
1971    
1972                            Matcher matcher = _varElementPattern.matcher(varValue);
1973    
1974                            while (matcher.find()) {
1975                                    String statement = matcher.group(1);
1976    
1977                                    Matcher statementMatcher = _varElementStatementPattern.matcher(
1978                                            statement);
1979    
1980                                    if (statementMatcher.find()) {
1981                                            String operand = statementMatcher.group(1);
1982    
1983                                            String method = statementMatcher.group(2);
1984    
1985                                            if (operand.equals("") || method.equals("")) {
1986                                                    throwValidationException(
1987                                                            1006, fileName, element, "value");
1988                                            }
1989    
1990                                            if (!_methodNames.contains(method)) {
1991                                                    throwValidationException(
1992                                                            1013, fileName, element, method);
1993                                            }
1994                                    }
1995                            }
1996                    }
1997    
1998                    List<Element> childElements = element.elements();
1999    
2000                    if (!childElements.isEmpty()) {
2001                            Element childElement = childElements.get(0);
2002    
2003                            String childElementName = childElement.getName();
2004    
2005                            throwValidationException(
2006                                    1002, fileName, childElement, childElementName);
2007                    }
2008            }
2009    
2010            private static final String _TPL_ROOT =
2011                    "com/liferay/portal/tools/seleniumbuilder/dependencies/";
2012    
2013            private static List<String> _allowedNullAttributes = ListUtil.fromArray(
2014                    new String[] {
2015                            "arg1", "arg2", "delimiter", "message", "string", "substring",
2016                            "value"
2017                    });
2018            private static List<String> _allowedVarAttributes = ListUtil.fromArray(
2019                    new String[] {
2020                            "attribute", "group", "input", "line-number", "locator",
2021                            "locator-key", "method", "name", "path", "pattern",
2022                            "property-value", "value"
2023                    });
2024            private static List<String> _componentNames;
2025            private static List<String> _methodNames = ListUtil.fromArray(
2026                    new String[] {
2027                            "getFirstNumber", "getIPAddress", "increment", "length",
2028                            "lowercase", "replace", "uppercase"
2029                    });
2030            private static List<String> _reservedTags = ListUtil.fromArray(
2031                    new String[] {
2032                            "and", "case", "command", "condition", "contains", "default",
2033                            "definition", "delimiter", "description", "echo", "else", "elseif",
2034                            "equals", "execute", "fail", "for", "if", "isset", "not", "or",
2035                            "property", "set-up", "take-screenshot", "td", "tear-down", "then",
2036                            "tr", "while", "var"
2037                    });
2038            private static List<String> _testcaseAvailablePropertyNames;
2039            private static List<String> _testrayAvailableComponentNames;
2040    
2041            private String _baseDirName;
2042            private Pattern _pathTrElementStatementPattern = Pattern.compile(
2043                    "[A-Z0-9].*");
2044            private Pattern _pathTrElementWordPattern1 = Pattern.compile(
2045                    "[A-Za-z0-9\\-]+");
2046            private Pattern _pathTrElementWordPattern2 = Pattern.compile(
2047                    "[A-Z0-9][A-Za-z0-9\\-]*");
2048            private Pattern _tagPattern = Pattern.compile("<[a-z\\-]+");
2049            private Pattern _varElementPattern = Pattern.compile("\\$\\{([^\\}]*?)\\}");
2050            private Pattern _varElementStatementPattern = Pattern.compile(
2051                    "(.*)\\?(.*)\\(([^\\)]*?)\\)");
2052    
2053    }