Ignore:
Timestamp:
03/05/15 11:50:56 (10 years ago)
Author:
pharms
Message:
  • added support for mapping document paths and removing their queries
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/autoquest-plugin-html/src/main/java/de/ugoe/cs/autoquest/plugin/html/HTMLLogParser.java

    r1817 r1893  
    1919import java.io.FileNotFoundException; 
    2020import java.io.IOException; 
     21import java.io.UnsupportedEncodingException; 
     22import java.security.MessageDigest; 
     23import java.security.NoSuchAlgorithmException; 
    2124import java.util.HashMap; 
    2225import java.util.LinkedList; 
    2326import java.util.List; 
     27import java.util.ListIterator; 
    2428import java.util.Map; 
    2529import java.util.Properties; 
     
    2731import java.util.regex.Pattern; 
    2832 
     33import org.apache.commons.codec.binary.Base64; 
    2934import org.xml.sax.SAXException; 
    3035 
     
    6974    /** 
    7075     * <p> 
     76     * the mapping between ids and their replacements due to merging while parsing 
     77     * </p> 
     78     */ 
     79    private Map<String, String> idMapping = new HashMap<>(); 
     80     
     81    /** 
     82     * <p> 
    7183     * file containing parameters to influence parsing 
    7284     * </p> 
     
    99111        throws SAXException 
    100112    { 
     113        if (idMapping.containsKey(id)) { 
     114            // the element is already existing. Return, that it was processed 
     115            return true; 
     116        } 
     117         
     118        String parentId = parameters.get("parent"); 
     119         
     120        if (parentId != null) { 
     121            parentId = idMapping.get(parentId); 
     122 
     123            if (parentId == null) { 
     124                // parent not yet handled, return that this elements can not be handled yet 
     125                return false; 
     126            } 
     127        } 
     128         
     129        HTMLGUIElement parent = (HTMLGUIElement) super.getGUIElementTree().find(parentId); 
     130         
    101131        ensureParsingParameters(); 
    102132         
    103133        HTMLGUIElementSpec specification = null; 
    104          
    105         String parentId = parameters.get("parent"); 
    106         HTMLGUIElement parent = (HTMLGUIElement) super.getGUIElementTree().find(parentId); 
    107  
     134        String replacementId = null; 
     135             
    108136        if (parameters.containsKey("host")) { 
    109137            // this is a server specification 
     
    115143            } 
    116144             
    117             specification = new HTMLServerSpec(parameters.get("host"), port); 
     145            String host = parameters.get("host"); 
     146            specification = new HTMLServerSpec(host, port); 
     147            replacementId = calculateId(host, portStr); 
    118148        } 
    119149        else if (parameters.containsKey("path")) { 
     
    126156                } 
    127157                 
     158                String path = parameters.get("path"); 
     159                String query = parameters.get("query"); 
     160                String title = parameters.get("title"); 
     161                 
     162                String replacement = getReplacementMapping(path, parent); 
     163                 
     164                if (replacement != null) { 
     165                    if (replacement.startsWith("CLEAR_QUERY,")) { 
     166                        query = null; 
     167                        replacement = replacement.substring("CLEAR_QUERY,".length()); 
     168                    } 
     169                    else if ("CLEAR_QUERY".equals(replacement)) { 
     170                        query = null; 
     171                        replacement = path; 
     172                    } 
     173                     
     174                    if ("".equals(replacement)) { 
     175                        path = null; 
     176                    } 
     177                    else { 
     178                        path = replacement; 
     179                    } 
     180                } 
     181                 
    128182                specification = new HTMLDocumentSpec 
    129                     ((HTMLServerSpec) parent.getSpecification(), parameters.get("path"), 
    130                      parameters.get("query"), parameters.get("title")); 
     183                    ((HTMLServerSpec) parent.getSpecification(), path, query, title); 
     184                 
     185                replacementId = calculateId(parentId, path, query, title); 
    131186            } 
    132187            else if (parentId == null) { 
     
    193248                    index = 0; 
    194249                } 
     250                 
     251                HTMLDocumentSpec documentSpec = (HTMLDocumentSpec) document.getSpecification(); 
    195252 
    196253                specification = new HTMLPageElementSpec 
    197                     ((HTMLDocumentSpec) document.getSpecification(), 
    198                      tagName.intern(), htmlId == null ? null : htmlId.intern(), index); 
     254                    (documentSpec, tagName.intern(), htmlId == null ? null : htmlId.intern(), index); 
     255                 
     256                replacementId = calculateId 
     257                    (documentSpec.getPath(), documentSpec.getQuery(), documentSpec.getTitle(), 
     258                     parentId, tagName, htmlId, (htmlId == null ? Integer.toString(index) : null)); 
    199259                 
    200260            } 
     
    209269        if (specification != null) { 
    210270            try { 
    211                 super.getGUIElementTree().add(id, parentId, specification); 
     271                idMapping.put(id, replacementId); 
     272                 
     273                super.getGUIElementTree().add(replacementId, parentId, specification); 
    212274            } 
    213275            catch (GUIModelException e) { 
     
    222284    } 
    223285     
     286    /** 
     287     * <p> 
     288     * returns the replacement mapping for the document path specified by the parameter, if a 
     289     * mapping exists. 
     290     * </p> 
     291     * 
     292     * @param path the path of the document 
     293     *  
     294     * @return the replacement mapping, if any is configured; null else 
     295     */ 
     296    private String getReplacementMapping(String path, HTMLGUIElement parent) { 
     297        List<ReplacementSpecification> mappingCandidates = 
     298            replacementSpecifications.get(ReplacementSpecification.LAST_TAG_NAME_FOR_DOCUMENTS); 
     299         
     300        List<ReplacementSpecification> candidates = new LinkedList<>(); 
     301         
     302        if (mappingCandidates != null) { 
     303            for (ReplacementSpecification replacementSpec : mappingCandidates) { 
     304                if (replacementSpec.matches(ReplacementSpecification.LAST_TAG_NAME_FOR_DOCUMENTS, 
     305                                            -1, path, parent)) 
     306                { 
     307                    candidates.add(replacementSpec); 
     308                } 
     309            } 
     310        } 
     311         
     312        prioritizeReplacementSpecs(candidates, "document " + path); 
     313         
     314        if (candidates.size() == 1) { 
     315            return candidates.get(0).getReplacement(); 
     316        } 
     317        else { 
     318            return null; 
     319        } 
     320    } 
     321 
    224322    /** 
    225323     * <p> 
     
    241339        List<ReplacementSpecification> mappingCandidates = replacementSpecifications.get(tagName); 
    242340         
     341        List<ReplacementSpecification> candidates = new LinkedList<>(); 
     342         
    243343        if (mappingCandidates != null) { 
    244344            for (ReplacementSpecification replacementSpec : mappingCandidates) { 
    245345                if (replacementSpec.matches(tagName, index, htmlId, parent)) { 
    246                     return replacementSpec.getReplacement(); 
    247                 } 
    248             } 
    249         } 
    250          
    251         return null; 
     346                    candidates.add(replacementSpec); 
     347                } 
     348            } 
     349        } 
     350         
     351        StringBuffer forWhat = new StringBuffer(); 
     352        forWhat.append("tag "); 
     353        toString(tagName, index, htmlId, parent, forWhat); 
     354         
     355        prioritizeReplacementSpecs(candidates, forWhat.toString()); 
     356         
     357        if (candidates.size() == 1) { 
     358            return candidates.get(0).getReplacement(); 
     359        } 
     360        else { 
     361            return null; 
     362        } 
     363    } 
     364     
     365    /** 
     366     * <p> 
     367     * decides, which replacement specification is to be preferred, if several match 
     368     * </p> 
     369     */ 
     370    private void prioritizeReplacementSpecs(List<ReplacementSpecification> candidates, 
     371                                            String                         forWhat) 
     372    { 
     373        boolean hasNonPattern = false; 
     374         
     375        for (ReplacementSpecification spec : candidates) { 
     376            if (!spec.isPattern()) { 
     377                hasNonPattern = true; 
     378                break; 
     379            } 
     380        } 
     381         
     382        if (hasNonPattern) { 
     383            ListIterator<ReplacementSpecification> it = candidates.listIterator(); 
     384             
     385            while (it.hasNext()) { 
     386                if (it.next().isPattern()) { 
     387                    it.remove(); 
     388                } 
     389            } 
     390        } 
     391         
     392        if (candidates.size() > 1) { 
     393            StringBuffer message = new StringBuffer(); 
     394            message.append("parse parameter file is ambigious for "); 
     395            message.append(forWhat); 
     396            message.append(". Can be mapped using "); 
     397             
     398            int counter = 0; 
     399            for (ReplacementSpecification spec : candidates) { 
     400                message.append(spec); 
     401                counter++; 
     402                 
     403                if (counter < (candidates.size() - 1)) { 
     404                    message.append(", "); 
     405                } 
     406                else if (counter < candidates.size()) { 
     407                    message.append(", and "); 
     408                } 
     409            } 
     410                         
     411            throw new IllegalArgumentException(message.toString()); 
     412        } 
     413    } 
     414 
     415    /** 
     416     * 
     417     */ 
     418    private void toString(String         tagName, 
     419                          int            index, 
     420                          String         htmlId, 
     421                          HTMLGUIElement parent, 
     422                          StringBuffer   message) 
     423    { 
     424        LinkedList<HTMLGUIElementSpec> specs = new LinkedList<>(); 
     425         
     426        HTMLGUIElement currentParent = parent; 
     427         
     428        while (currentParent != null) { 
     429            specs.addFirst((HTMLGUIElementSpec) currentParent.getSpecification()); 
     430            currentParent = (HTMLGUIElement) currentParent.getParent(); 
     431        } 
     432         
     433        for (HTMLGUIElementSpec spec : specs) { 
     434            message.append(spec.toString()); 
     435            message.append("/"); 
     436        } 
     437         
     438        message.append(tagName); 
     439         
     440        if (htmlId != null) { 
     441            message.append("(htmlId="); 
     442            message.append(htmlId); 
     443            message.append(')'); 
     444        } 
     445        else { 
     446            message.append('['); 
     447            message.append(index); 
     448            message.append(']'); 
     449        } 
    252450    } 
    253451 
     
    280478        } 
    281479         
    282         IGUIElement target = super.getGUIElementTree().find(targetId); 
    283          
    284         if (target == null) { 
     480        targetId = idMapping.get(targetId); 
     481         
     482        if (targetId == null) { 
    285483            // event not processible yet 
    286484            return false; 
    287485        } 
     486         
     487        IGUIElement target = super.getGUIElementTree().find(targetId); 
    288488 
    289489        IEventType eventType = 
     
    483683 
    484684    /** 
     685     * <p> 
     686     * calculates a unique id for the given string fragments using SHA-512 and Base64 encoding. 
     687     * </p> 
     688     * 
     689     * @param fragments strings to be used for calculating a unique id 
     690     *  
     691     * @return a Base64 encoded unique id for the provided fragments 
     692     */ 
     693    private String calculateId(String... fragments) { 
     694        try { 
     695            MessageDigest md = MessageDigest.getInstance("SHA-512"); 
     696             
     697            for (String fragment : fragments) { 
     698                if (fragment != null) { 
     699                    md.update(fragment.getBytes("UTF-8")); 
     700                } 
     701            } 
     702             
     703            return Base64.encodeBase64String(md.digest()); 
     704        } 
     705        catch (UnsupportedEncodingException e) { 
     706            throw new IllegalStateException("Java VM does not support this code"); 
     707        } 
     708        catch (NoSuchAlgorithmException e) { 
     709            throw new IllegalStateException("Java VM does not support this code"); 
     710        } 
     711    } 
     712 
     713    /** 
    485714     * <p>specification for a replacement consisting of path of tag or document specifications 
    486715     * and the appropriate replacement.</p> 
     
    489718         
    490719        /** 
     720         *  
     721         */ 
     722        private static final String LAST_TAG_NAME_FOR_DOCUMENTS = "LAST_TAG_NAME_FOR_DOCUMENTS"; 
     723         
     724        /** 
    491725         * <p> 
    492726         * the pattern used for parsing parsing parameters 
     
    494728         */ 
    495729        private Pattern htmlElementSpecPattern = Pattern.compile 
    496             ("(document\\(path=([\\w/-]+)\\))|((\\w+)(\\[(\\d+)\\]|\\(htmlId=([\\w-_#]+)\\))?)"); 
     730            ("(document\\(path=([\\w/\\-#$&%]+)\\))|((\\w+)(\\[(\\d+)\\]|\\(htmlId=([\\w\\-_#]+)\\))?)"); 
    497731         
    498732        /** 
     
    525759         * </p> 
    526760         */ 
    527         public ReplacementSpecification(String tagSpec, String replacement) { 
     761        private ReplacementSpecification(String tagSpec, String replacement) { 
    528762            List<String> tagSpecs = split(tagSpec); 
    529763             
     
    558792            } 
    559793             
    560             this.lastTagName = ((TagSpec) this.specs.get(this.specs.size() - 1)).getTagName(); 
     794            if (this.specs.get(this.specs.size() - 1) instanceof TagSpec) { 
     795                this.lastTagName = ((TagSpec) this.specs.get(this.specs.size() - 1)).getTagName(); 
     796            } 
     797            else { 
     798                this.lastTagName = LAST_TAG_NAME_FOR_DOCUMENTS; 
     799            } 
    561800             
    562801            this.replacement = replacement; 
     
    601840        /** 
    602841         * <p> 
     842         * returns true, if the spec is a pattern, i.e. matches a group of similar elements 
     843         * </p> 
     844         */ 
     845        public boolean isPattern() { 
     846            for (Spec spec : specs) { 
     847                if (spec.isPattern()) { 
     848                    return true; 
     849                } 
     850            } 
     851             
     852            return false; 
     853        } 
     854 
     855        /** 
     856         * <p> 
    603857         * checks, if the tag identified by the parameters matches this specificaiton. 
    604858         * </p> 
     
    608862            int currentIndex = index; 
    609863            String currentHtmlId = htmlId; 
    610             String currentPath = null; 
     864            String currentPath = LAST_TAG_NAME_FOR_DOCUMENTS.equals(tagName) ? htmlId : null; 
    611865            HTMLGUIElement currentParent = parent; 
    612866             
     
    634888                        currentPath = null; 
    635889                        currentParent = (HTMLGUIElement) currentParent.getParent(); 
    636                      } 
     890                    } 
    637891                    else if (currentParent instanceof HTMLDocument) { 
    638892                        currentTagName = null; 
     
    696950     * </p> 
    697951     */ 
    698     private static interface Spec { } 
     952    private static interface Spec { 
     953 
     954        /** 
     955         * <p> 
     956         * returns true if the spec is a pattern, i.e., matches a group of similar elements 
     957         * </p> 
     958         * 
     959         * @return 
     960         */ 
     961        boolean isPattern(); 
     962         
     963    } 
    699964 
    700965    /** 
     
    721986        } 
    722987 
     988        /* (non-Javadoc) 
     989         * @see de.ugoe.cs.autoquest.plugin.html.HTMLLogParser.Spec#isPattern() 
     990         */ 
     991        @Override 
     992        public boolean isPattern() { 
     993            return (pathPart != null) && (pathPart.indexOf('#') > -1); 
     994        } 
     995 
    723996        /** 
    724997         * <p> 
     
    7271000         */ 
    7281001        private boolean matches(String path) { 
    729             return path.contains(pathPart); 
     1002            if ((path != null) && (path.contains(pathPart))) { 
     1003                return true; 
     1004            } 
     1005            else if ((path != null) && (isPattern() || (pathPart.indexOf('$') > -1))) { 
     1006                // check if the path condition would match with ignoring specific characters 
     1007                 
     1008                boolean mustMatchAtEnd = pathPart.charAt(pathPart.length() - 1) == '$'; 
     1009 
     1010                int indexInPath = 0; 
     1011                int indexInPathPart = 0; 
     1012 
     1013                while (indexInPath < path.length()) { 
     1014                    if ((path.charAt(indexInPath) == pathPart.charAt(indexInPathPart)) || 
     1015                        (pathPart.charAt(indexInPathPart) == '#')) 
     1016                    { 
     1017                        indexInPathPart++; 
     1018 
     1019                        if ((indexInPathPart >= pathPart.length()) || 
     1020                            (mustMatchAtEnd && (indexInPathPart == pathPart.length() - 1) && 
     1021                             (indexInPath == path.length() - 1))) 
     1022                        { 
     1023                            // found a match 
     1024                            return true; 
     1025                        } 
     1026                    } 
     1027                    else { 
     1028                        indexInPathPart = 0; 
     1029                    } 
     1030 
     1031                    indexInPath++; 
     1032                } 
     1033                 
     1034                return false; 
     1035            } 
     1036            else { 
     1037                // no condition ignoring specific characters 
     1038                return false; 
     1039            } 
    7301040        } 
    7311041 
     
    7781088        } 
    7791089 
     1090        /* (non-Javadoc) 
     1091         * @see de.ugoe.cs.autoquest.plugin.html.HTMLLogParser.Spec#isPattern() 
     1092         */ 
     1093        @Override 
     1094        public boolean isPattern() { 
     1095            return (idCondition != null) && (idCondition.indexOf('#') > -1); 
     1096        } 
     1097 
    7801098        /** 
    7811099         * <p> 
     
    7931111                if (!idCondition.equals(htmlId)) { 
    7941112                    // check if the id condition would match with ignoring specific characters 
    795                     if ((htmlId != null) && (idCondition.indexOf('#') > -1)) { 
     1113                    if ((htmlId != null) && isPattern()) { 
    7961114                        // first of all, the length must match 
    7971115                        if (idCondition.length() != htmlId.length()) { 
Note: See TracChangeset for help on using the changeset viewer.