Package com.dyuproject.web.rest.service

Source Code of com.dyuproject.web.rest.service.PathHandler

//========================================================================
//Copyright 2007-2008 David Yu dyuproject@gmail.com
//------------------------------------------------------------------------
//Licensed 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 com.dyuproject.web.rest.service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dyuproject.util.Delim;
import com.dyuproject.web.rest.AbstractLifeCycle;
import com.dyuproject.web.rest.Interceptor;
import com.dyuproject.web.rest.InterceptorCollection;
import com.dyuproject.web.rest.RequestContext;
import com.dyuproject.web.rest.WebContext;

/**
* Contains all the logic to handle the REST requests.
* Wraps the Resource and Interceptor.
* Wildcard interceptor supported.
*
* @author David Yu
* @created Dec 3, 2008
*/

public final class PathHandler extends AbstractLifeCycle
{
   
    public static final String ROOT = "/", PARAM = "$";
   
    private static final Logger log = LoggerFactory.getLogger(PathHandler.class);
   
    public static boolean isPathParameter(String id)
    {
        char first = id.charAt(0);
        return first=='$' || first=='{';
    }
   
    private final String _id;
    private final Map<String,PathHandler> _pathHandlers = new HashMap<String,PathHandler>(3);
    private final Map<String,Resource> _resources = new HashMap<String,Resource>(3);
   
    // /path/   /path/* and  /path/**
    private final Interceptor[] _mappedInterceptors = new Interceptor[3];
   
    private Interceptor _interceptor;
    private PathHandler _parent, _parameterHandler;
   
    public PathHandler()
    {
        this(ROOT);
    }
   
    PathHandler(String id)
    {
        _id = id;
    }
   
    PathHandler(String id, PathHandler parent)
    {
        this(id);
        _parent = parent;
        _parent.addPathHandler(this);       
    }
   
    PathHandler setParent(PathHandler parent)
    {
        _parent = parent;
        return this;
    }
   
    protected void init()
    {       
        for(PathHandler ph : _pathHandlers.values())
            ph.init(getWebContext());
       
        if(_parameterHandler!=null)
            _parameterHandler.init(getWebContext());
       
        if(_parent!=null)
        {
            loadInterceptors(this, _parent);
            appendInterceptor(this, _parent._mappedInterceptors[1]);
        }
        appendInterceptor(this, _mappedInterceptors[2]);
        appendInterceptor(this, _mappedInterceptors[1]);
        appendInterceptor(this, _mappedInterceptors[0]);
       
        if(_interceptor!=null)
            _interceptor.init(getWebContext());
       
        // clear configured interceptors
        _mappedInterceptors[2] = null;
        _mappedInterceptors[1] = null;
        _mappedInterceptors[0] = null;
    }
   
    protected void destroy()
    {
        for(PathHandler ph : _pathHandlers.values())
            ph.destroy(getWebContext());
       
        if(_parameterHandler!=null)
            _parameterHandler.destroy(getWebContext());
       
        if(_interceptor!=null)
            _interceptor.destroy(getWebContext());
       
        _resources.clear();       
        _pathHandlers.clear();
        _parent = null;
        _parameterHandler = null;
        _interceptor = null;
    }
   
    static void loadInterceptors(PathHandler toConfigure, PathHandler pathHandler)
    {
        PathHandler parent = pathHandler._parent;
        if(parent!=null)
            loadInterceptors(toConfigure, parent);
       
        appendInterceptor(toConfigure, pathHandler._mappedInterceptors[2])
    }
   
    static void appendInterceptor(PathHandler ph, Interceptor i)
    {
        if(i!=null)
        {
            if(ph._interceptor==null)
                ph._interceptor = i;
            else if(ph._interceptor instanceof InterceptorCollection)
                ((InterceptorCollection)ph._interceptor).addInterceptor(i);
            else
            {
                InterceptorCollection ic = new InterceptorCollection();
                ic.addInterceptor(ph._interceptor);
                ic.addInterceptor(i);
                ph._interceptor = ic;
            }
        }
    }

    public String getId()
    {
        return _id;
    }
   
    void addMappedInterceptor(Interceptor interceptor, int wildcard)
    {
        Interceptor existing = _mappedInterceptors[wildcard];
        if(existing==null)
            _mappedInterceptors[wildcard] = interceptor;
        else if(existing instanceof InterceptorCollection)
            ((InterceptorCollection)existing).addInterceptor(interceptor);
        else
        {
            InterceptorCollection ic = new InterceptorCollection();
            ic.addInterceptor(existing);
            ic.addInterceptor(interceptor);
            _mappedInterceptors[wildcard] = ic;
        }       
    }
   
    void addPathHandler(PathHandler child)
    {
        PathHandler last = _pathHandlers.put(child.getId(), child);
        if(last!=null)
            log.warn("path overridden: " + last.getId() + " | " + last);
    }
   
    void addResource(Resource resource)
    {
        Resource last = _resources.put(resource.getHttpMethod(), resource);
        if(last!=null)
            log.warn("resource overridden: " + last.getHttpMethod() + " | " + last);
    }
   
    void resourceHandle(RequestContext rc) throws ServletException, IOException
    {
        Resource resource = _resources.get(rc.getRequest().getMethod());
        if(resource==null)
        {
            rc.getResponse().sendError(405);
            return;
        }
       
        // cache to local copy
        Interceptor interceptor = _interceptor;
        if(interceptor==null)
        {
            resource.handle(rc);
            return;
        }

        boolean success = false;
        try
        {
            success = interceptor.preHandle(rc);
        }
        finally
        {           
            if(success)
            {
                try
                {
                    resource.handle(rc);
                }
                finally
                {
                    interceptor.postHandle(true, rc);
                }
            }
            else
                interceptor.postHandle(false, rc);
        }     
    }   
   
    boolean map(int index, String[] pathInfo, Interceptor interceptor, int wildcard)
    {       
        String id = pathInfo[index++];       
        PathHandler pathHandler = _pathHandlers.get(id);
        if(pathHandler==null)
        {
            log.warn("unmapped interceptor: " + interceptor);
            return false;
        }
       
        if(index==pathInfo.length)
        {           
            pathHandler.addMappedInterceptor(interceptor, wildcard);
            return true;
        }
       
        String next = pathInfo[index++];
        if(isPathParameter(next))
        {
            if(pathHandler._parameterHandler==null)
            {
                log.warn("unmapped interceptor: " + interceptor);
                return false;
            }
           
            if(index==pathInfo.length)
            {              
                pathHandler._parameterHandler.addMappedInterceptor(interceptor, wildcard);
                return true;
            }           
            return pathHandler._parameterHandler.map(index, pathInfo, interceptor, wildcard);
        }
       
        return pathHandler.map(--index, pathInfo, interceptor, wildcard);
    }
   
    PathHandler map(int index, String[] pathInfo, Resource resource)
    {       
        String id = pathInfo[index++];
        PathHandler pathHandler = _pathHandlers.get(id);
        if(pathHandler==null)
            pathHandler = new PathHandler(id, this);    
       
        if(index==pathInfo.length)
        {           
            pathHandler.addResource(resource);
            return pathHandler;
        }
       
        String next = pathInfo[index++];
        if(isPathParameter(next))
        {
            if(pathHandler._parameterHandler==null)
                pathHandler._parameterHandler = new PathHandler(PARAM).setParent(pathHandler);
           
            if(index==pathInfo.length)
            {
                pathHandler._parameterHandler.addResource(resource);
                return pathHandler._parameterHandler;
            }           
           
            return pathHandler._parameterHandler.map(index, pathInfo, resource);
        }
       
        return pathHandler.map(--index, pathInfo, resource);
    }
   
    public boolean map(String path, Interceptor interceptor)
    {
        path = path.trim();
        if(path.length()==0)
            throw new IllegalStateException("invalid path: " + path);
       
        int wildcard = 0;
        int lastSlashIdx = path.lastIndexOf('/');
        if(lastSlashIdx==path.length()-1)
        {
            if(path.length()==1)
            {
                addMappedInterceptor(interceptor, 0);
                return true;
            }
           
            path = path.substring(0, path.length()-1);
            lastSlashIdx = path.lastIndexOf('/');
        }
       
        int asteriskIdx = path.lastIndexOf('*');
        if(asteriskIdx!=-1)
        {
            if(asteriskIdx<lastSlashIdx)
                throw new IllegalStateException("invalid path: " + path);
           
            int len = asteriskIdx - lastSlashIdx;
            if(len>2 || asteriskIdx+1!=path.length())
                throw new IllegalArgumentException("wild card: " + path + " must end with /* or /**");
        
            if(len==2)
            {
                if(path.charAt(asteriskIdx-1)!='*')
                    throw new IllegalArgumentException("wild card: " + path + " must end with /* or /**");
                wildcard = 2;
            }
            else
                wildcard = 1;
           
            path = path.substring(0, lastSlashIdx);
        }
        if(path.charAt(0)=='/')
            path = path.substring(1);

        return map(0, Delim.SLASH.split(path), interceptor, wildcard);       
    }
   
    public PathHandler map(String path, Resource resource)
    {
        path = path.trim();
        if(path.length()==0 || path.indexOf('*')!=-1)
            throw new IllegalStateException("invalid path: " + path);
       
        int lastSlashIdx = path.lastIndexOf('/');
        if(lastSlashIdx==path.length()-1)
        {
            if(path.length()==1)
            {
                addResource(resource);
                return this;
            }
            path = path.substring(0, path.length()-1);
        }
       
        if(path.charAt(0)=='/')
            path = path.substring(1);       
    
        return map(0, Delim.SLASH.split(path), resource);
    }
   
    public void handle(String[] pathInfo, RequestContext rc)
    throws ServletException, IOException
    {
        handle(this, 0, pathInfo, rc);
    }
   
    static void handle(PathHandler parentHandler, int index, String[] pathInfo, RequestContext rc)
    throws ServletException, IOException
    {
        String id = pathInfo[index++];
        PathHandler pathHandler = parentHandler._pathHandlers.get(id);
        if(pathHandler==null)
        {
            // cache to local copy
            PathHandler parentParamHandler = parentHandler._parameterHandler;
            if(parentParamHandler==null)
                WebContext.getCurrentRequestContext().getResponse().sendError(404);
            else if(index==pathInfo.length)
                parentParamHandler.resourceHandle(rc);
            else
                handle(parentParamHandler, index, pathInfo, rc);           
        }
        else if(index==pathInfo.length)
            pathHandler.resourceHandle(rc);
        else
            handle(pathHandler, index, pathInfo, rc);
    }

}
TOP

Related Classes of com.dyuproject.web.rest.service.PathHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.