Package com.dyuproject.web.rest.service

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

//========================================================================
//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.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;

import org.codehaus.jra.HttpResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dyuproject.util.Delim;
import com.dyuproject.web.rest.ConsumerInterceptor;
import com.dyuproject.web.rest.Interceptor;
import com.dyuproject.web.rest.RequestContext;
import com.dyuproject.web.rest.ValidatingConsumer;
import com.dyuproject.web.rest.WebContext;
import com.dyuproject.web.rest.annotation.Consume;

/**
* The application context using REST services and resources
*
* @author David Yu
* @created Dec 4, 2008
*/

public final class RESTServiceContext extends WebContext
{
   
    private static final Logger log = LoggerFactory.getLogger(RESTServiceContext.class);
   
    private final PathHandler _pathHandler = new PathHandler();
    private final List<Service> _services = new ArrayList<Service>();
    private final List<Resource> _resources = new ArrayList<Resource>();
    private final Map<String,Interceptor> _interceptors = new HashMap<String,Interceptor>();
   
    public void addService(Service service)
    {
        if(isInitialized())
            throw new IllegalStateException("already initialized");
       
        _services.add(service);
    }
   
    public void setServices(Service[] services)
    {
        if(isInitialized())
            throw new IllegalStateException("already initialized");
       
        for(Service s : services)
            _services.add(s);
    }
   
    public void setServices(List<Service> services)
    {
        if(isInitialized())
            throw new IllegalStateException("already initialized");
       
        for(Service s : services)
            _services.add(s);       
    }
   
    public void addResource(String path, Resource resource)
    {
        if(isInitialized())
            throw new IllegalStateException("already initialized");
       
        mapResource(path, resource);
    }
   
    public void setResources(Map<String,Resource> resources)
    {
        if(isInitialized())
            throw new IllegalStateException("already initialized");
       
        for(Map.Entry<String, Resource> entry : resources.entrySet())
            mapResource(entry.getKey(), entry.getValue());
    }
   
    public void addInterceptor(String path, Interceptor interceptor)
    {
        if(isInitialized())
            throw new IllegalStateException("already initialized");
       
        _interceptors.put(path, interceptor);       
    }
   
    public void setInterceptors(Map<String,Interceptor> interceptors)
    {
        if(isInitialized())
            throw new IllegalStateException("already initialized");
       
        _interceptors.putAll(interceptors);
    }

    protected void init()
    {      
        for(Service s : _services)
            initService(s);
       
        for(Resource r : _resources)
            initResource(r);
       
        for(Iterator<Map.Entry<String,Interceptor>> iter =
            _interceptors.entrySet().iterator(); iter.hasNext();)
        {
            Map.Entry<String,Interceptor> entry = iter.next();
            if(!_pathHandler.map(entry.getKey(), entry.getValue()))
                iter.remove();
        }
       
        _pathHandler.init(this);
       
        log.info(_services.size() + " services initialized.");
        log.info(_resources.size() + " resources initialized.");
        log.info(_interceptors.size() + " configured interceptors initialized.");
    }   
   
    protected void destroy()
    {
        for(Service s : _services)
            s.destroy(this);
       
        for(Resource r : _resources)
            r.destroy(this);
       
        _pathHandler.destroy(this);
       
        log.info(_services.size() + " services destroyed.");
        log.info(_resources.size() + " resources destroyed.");
        log.info(_interceptors.size() + " configured interceptors destroyed.");
       
        _services.clear();
        _resources.clear();
        _interceptors.clear();
    }   
   
    private PathHandler mapResource(String path, Resource resource)
    {
        PathHandler ph = _pathHandler.map(path, resource);
        if(ph!=null)
            _resources.add(resource);
       
        return ph;
    }
   
    private void initResource(Resource resource)
    {       
        resource.init(this);
    }
   
    private void initService(Service service)
    {       
        for(Method m : service.getClass().getMethods())
        {
            if(Modifier.isStatic(m.getModifiers()) || m.getDeclaringClass()==Object.class)
                continue;
            String location = null;
            String httpMethod = null;
            Annotation[] annotations = m.getDeclaredAnnotations();
            Consume c = null;
            if(annotations!=null)
            {               
                for(Annotation a : annotations)
                {
                    if(a instanceof HttpResource)
                    {
                        if(location!=null)
                            throw new IllegalStateException("multiple declared HttpResource annotations");
                       
                        location = ((HttpResource)a).location();                       
                        continue;
                    }
                    if(a instanceof Consume)
                    {
                        if(c!=null)
                            throw new IllegalStateException("multiple declared Consume annotations");
                       
                        c = (Consume)a;
                        continue;
                    }
                    String method = AnnotatedMethodResource.getHttpMethod(a.annotationType());
                    if(httpMethod!=null)
                    {
                        if(method!=null)
                            throw new IllegalStateException("multiple declared Http method annotations");
                    }                  
                    else
                        httpMethod = method;                   
                }
            }           
            if(location==null)
                continue;
           
            if(httpMethod==null)
            {
                log.warn(location + " not mapped.  Http method annotation is required");
                continue;
            }
           
            int len = m.getParameterTypes().length;
            if(len==0 || (len==1 && RequestContext.class.isAssignableFrom(m.getParameterTypes()[0])))
            {         
                PathHandler ph = mapResource(location, new AnnotatedMethodResource(service, m, httpMethod));
                if(c!=null && ph!=null)
                    mapConsumer(location, httpMethod, ph, c);
                continue;
            }

            log.warn(location + " not mapped.  THe annotated method's only argument must be RequestContext or can also have no args.");
        }
        service.init(this);
    }
   
    protected void mapConsumer(String location, String httpMethod, PathHandler ph, Consume c)
    {
        Class<?> pojoClass = c.pojoClass();
        Class<?>[] consumers = c.consumers();
        if(pojoClass==null)
        {
            log.warn("consumer @ " + location + " excluded. Param pojoClass is required.");
            return;
        }
        if(consumers==null || consumers.length==0)
        {
            log.warn("consumer @ " + location + " excluded. Param consumers is required.");
            return;
        }
       
        ConsumerInterceptor ci = new ConsumerInterceptor();
        Properties fieldParams = new Properties();
        loadPropertiesFromClass(fieldParams, pojoClass);
        addParamsToProperties(fieldParams, c.fieldParams());
        for(int i=0; i<consumers.length; i++)
        {
            try
            {
                ValidatingConsumer vc = (ValidatingConsumer)consumers[i].newInstance();
                vc.preConfigure(httpMethod, c.contentType(), pojoClass, fieldParams);
                ci.addConsumer(vc);
            }
            catch(Exception e)
            {
                throw new RuntimeException(e);
            }
        }
        ph.addMappedInterceptor(ci, 0);
    }
   
    @SuppressWarnings("unchecked")
    public void loadPropertiesFromClass(Properties props, Class<?> clazz)
    {
        Map<Class<?>,Properties> cache =
            (Map<Class<?>,Properties>)getAttribute(CONSUMER_PROPERTIES_CACHE);
        if(cache==null)
        {
            cache = new HashMap<Class<?>,Properties>(7);
            setAttribute(CONSUMER_PROPERTIES_CACHE, cache);
        }
        Properties defaultProps = cache.get(clazz);
        if(defaultProps==null)
        {
            defaultProps = new Properties();
            cache.put(clazz, defaultProps);
            String resource = clazz.getName().replace('.', '/') + ".properties";
            URL url = getResource(resource);
            if(url!=null)
            {
                try
                {
                    defaultProps.load(url.openStream());
                }
                catch(IOException e)
                {
                    throw new RuntimeException(e);
                }
            }
        }
        if(defaultProps.size()!=0)
            props.putAll(defaultProps);       
    }   
   
    static void addParamsToProperties(Properties props, String params)
    {
        if(params==null || params.length()==0)
            return;
       
        String[] tokens = Delim.AMPER.split(params);
        for(int i=0; i<tokens.length; i++)
        {
            String token = tokens[i];
            int idx = token.indexOf('=');
            if(idx==-1)
            {
                if(token.length()>0)
                    props.put(token, "");
            }
            else if(idx!=0)
                props.setProperty(token.substring(0, idx), token.substring(idx+1));
        }
    }
   
    protected void preConfigure(ServletConfig config) throws Exception
    {
        String servicesParam = config.getInitParameter("services");
        if(servicesParam!=null)
        {
            StringTokenizer tokenizer = new StringTokenizer(servicesParam, ",;");
            while(tokenizer.hasMoreTokens())
                addService((Service)newObjectInstance(tokenizer.nextToken().trim()));
        }
       
        String resourcesParam = config.getInitParameter("resources");
        if(resourcesParam!=null)
        {
            StringTokenizer tokenizer = new StringTokenizer(resourcesParam, ",;");
            while(tokenizer.hasMoreTokens())
            {
                String next = tokenizer.nextToken();
                int idx = next.indexOf('@');
                if(idx==-1)
                {
                    log.warn("invalid resource mapping: " + next);
                    continue;
                }
                String resourceClass = next.substring(0, idx).trim();
                String path = next.substring(idx+1).trim();
                addResource(path, (Resource)newObjectInstance(resourceClass));
            }
        }
       
        String interceptorsParam = config.getInitParameter("interceptors");
        if(interceptorsParam!=null)
        {
            StringTokenizer tokenizer = new StringTokenizer(interceptorsParam, ",;");
            while(tokenizer.hasMoreTokens())
            {
                String next = tokenizer.nextToken();
                int idx = next.indexOf('@');
                if(idx==-1)
                {
                    log.warn("invalid interceptor mapping: " + next);
                    continue;
                }
                String interceptorClass = next.substring(0, idx).trim();
                String path = next.substring(idx+1).trim();
                addInterceptor(path, (Interceptor)newObjectInstance(interceptorClass));
            }
        }
    }

    protected void handleRoot(RequestContext requestContext)
            throws ServletException, IOException
    {
        _pathHandler.resourceHandle(requestContext);
    }

    protected void handlePath(RequestContext requestContext)
            throws ServletException, IOException
    {
        _pathHandler.handle(requestContext.getPathInfo(), requestContext);       
    }

}
TOP

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

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.