All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.javapla.jawn.core.AbstractContext Maven / Gradle / Ivy

The newest version!
package net.javapla.jawn.core;

import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import net.javapla.jawn.core.util.StringUtil;
import net.javapla.jawn.core.util.URLCodec;

public abstract class AbstractContext implements Context {

    // session
    // flash
    // attributes
    
    /* Attributes  */
    private HashMap attributes;
    
    private void instantiateAttributes() {
        if (attributes == null) attributes = new HashMap<>(3);
    }
    
    private Object attributeOrNull(final String name) {
        if (attributes == null || attributes.isEmpty()) return null;
        return attributes.get(name);
    }
    
    @Override
    public Context attribute(final String name, final Object value) {
        instantiateAttributes();
        attributes.put(name, value);
        return this;
    }
    
    @Override
    public Optional attribute(final String name) {
        return Optional.ofNullable(attributeOrNull(name));
    }
    
    @Override
    public Context removeAttribute(final String name) {
        if (attributes != null) attributes.remove(name);
        return this;
    }
    
    
    /* Session  */
    
    
    // ** Route **
    //Route route;
    /*void route(Route route) {
        this.route = route;
    }
    Route route() {
        return route;
    }*/
    public Router.RoutePath routePath;
    
    
    
    // ** Framework specific shortcuts
    public abstract String requestHeader(String name);
    MediaType accept(List responseTypes) {
        if (responseTypes.isEmpty()) return null;
        
        String accept = requestHeader(ACCEPT);
        if (accept == null) {
            // We got no header, so just use the first of the possible response types
            return responseTypes.get(0);
        }
        
        
        // Example
        // Multiple types, weighted with the quality value syntax:
        // Accept: text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8
        // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept
        
        // TODO take weights into account
        // For now, we assume "Accept" is a prioritised list of MIME types
        
        List acceptable = MediaType.parse(accept);
        
        // Find appropriate type
        for (MediaType accepting : acceptable) {
            for (MediaType producing : responseTypes) {
                if (accepting.matches(producing)) return producing;
            }
        }
        
        return responseTypes.get(0);
    }
    
    
    
    
    protected abstract class AbstractRequest implements Context.Request {
        
        @SuppressWarnings("unchecked")
        @Override
        public  T parse(Type type) {
            try {
                return (T) routePath.route.parsers.get(contentType()).parse(AbstractContext.this, type);
            } catch (Exception e) {
                throw Up.ParseError("", e);
            }
        }
        
        @Override
        public Value pathParam(String name) {
            if (routePath.pathParameters == null) return Value.empty();
            return Value.of(routePath.pathParameters.get(name));
        }
        
        
        /* Headers */
        @Override
        public Value header(String name) {
            return Value.of(headers().first(name));
        }
        
        
        /* Query */
        private Map query;
        private void instantiateQuery() {
            if (query != null) return;
            
            String[] split = StringUtil.split(req().queryString(), '&');
            query = new HashMap<>(split.length);
            StringUtil.split(split, '=', (k,v) -> query.put(k, URLCodec.decode(v, StandardCharsets.UTF_8)));
        }
        
        @Override
        public Value queryParam(String name) {
            instantiateQuery();
            return Value.of(query.get(name));
        }
        
        /* Cookies */
        @Override
        public Value cookie(String name) {
            return null;
        }
    }
    
    protected abstract class AbstractResponse implements Context.Response {
        protected MediaType responseType = MediaType.TEXT;
        protected MediaType defaultResponseType = null;
        protected Charset cs = StandardCharsets.UTF_8;
        protected Map responseCookies = null;
        
        
        @Override
        public Response rendererContentType(MediaType type) {
            defaultResponseType = type;
            return this;
        }
        
        @Override
        public Response cookie(Cookie cookie) {
            if ( responseCookies == null) responseCookies = new LinkedHashMap<>();
            // if we ever are going to support "context path", this is where to put it
            //cookie.path( cookie.path() == null ? contextPath() : cookie.path())
            responseCookies.put(cookie.name(), cookie.toString());
            removeHeader("Set-Cookie"); // removes all
            for (String value : responseCookies.values()) {
                header("Set-Cookie", value);
            }
            return this;
        }
        
        
        /*@Override
        public void postResponse(PostResponse task) {
            if (onComplete == null) onComplete = new LinkedList<>();
            onComplete.add(task);
        }*/
    }
    
    /*private LinkedList onComplete;
    protected void onComplete() {
        if (onComplete != null)
            onComplete.forEach(action -> action.onComplete(this, null));
    }*/
    
}