# Node.java

    /*
    *  Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
    *
    *  WSO2 Inc. licenses this file to you under the Apache License,
    *  Version 2.0 (the "License"); you may not use this file except
    *  in compliance with the License.
    *  You may obtain a copy of the License at
    *
    *    http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing,
    * software distributed under the License is distributed on an
    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    * KIND, either express or implied.  See the License for the
    * specific language governing permissions and limitations
    * under the License.
    */

    package org.apache.synapse.commons.templates.uri.parser;

    import java.util.Map;

    public abstract class Node {

        protected String token;
        protected Node next;
        protected boolean hasQueryTemplate = false;

        protected Node(String token) {
            this.token = token;
        }

        public void setNext(Node next) {
            this.next = next;
        }

        public String expandAll(Map<String,String> variables) {
            StringBuilder builder = new StringBuilder();
            Node currentNode = this;
            while (currentNode != null) {
                builder.append(currentNode.expand(variables));
                currentNode = currentNode.next;
            }
            return builder.toString();
        }

        public int matchAll(String uriFragment, Map<String, String> variables) {
            int matchLength = match(uriFragment, variables);
            if (matchLength < 0) {
                return -1;
            } else if (matchLength < uriFragment.length()) {
                if (next != null) {
                    uriFragment = uriFragment.substring(matchLength);
                    return matchLength + next.matchAll(uriFragment, variables);
                } else {
                    // We have more content in the URI to match
                    // But there aren't any nodes left to match against
                    // return -1;
                    if(uriFragment.endsWith("/")){
                        matchLength = matchLength +1;
                    }
                    return matchLength;
                }
            } else if (matchLength == uriFragment.length() && next != null) {
                if(next.getToken().equalsIgnoreCase("*"))
                {
                    return matchLength;
                }
                if(next.getToken().equalsIgnoreCase("/*"))
                {
                    return matchLength;
                }
                // Below condition is only required to match scenarios where a query parameter is sent without any
                // value (e.g. "?key1=value1&key2="). Therefore we check for both the presence of a url template as well
                // as the equal sign, denoting a parameter.
                if (next.getToken().startsWith("{") && uriFragment.contains("=")) {
                    uriFragment = uriFragment.substring(matchLength);
                    return matchLength + next.matchAll(uriFragment, variables);
                }
                // We have matched all the characters in the URI
                // But there are some nodes left to be matched against
                return -1;
            }
            else {
                return matchLength;
            }
        }

        public boolean hasQueryTemplate(){
            return (next != null)? hasQueryTemplate || next.hasQueryTemplate(): hasQueryTemplate;
        }

        abstract String expand(Map<String,String> variables);
        abstract int match(String uriFragment, Map<String,String> variables);
        abstract String getToken();
        abstract char getFirstCharacter();
    }