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

com.firefly.mvc.web.Resource Maven / Gradle / Ivy

package com.firefly.mvc.web;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.firefly.mvc.web.servlet.SystemHtmlPage;
import com.firefly.mvc.web.support.ControllerMetaInfo;
import com.firefly.mvc.web.support.URLParser;
import com.firefly.server.http2.servlet.HTTPServletRequestImpl;
import com.firefly.utils.pattern.Pattern;

public class Resource {
    public static final String WILDCARD = "?";
    private static final String[] EMPTY = new String[0];
    private static String ENCODING;

    private final Map CONSTANT_URI;

    private String uri;
    private Pattern pattern;
    private ControllerMetaInfo controller;
    private ResourceSet children = new ResourceSet();

    public Resource(String encoding) {
        CONSTANT_URI = new HashMap<>();
        ENCODING = encoding;
    }

    private Resource(boolean root) {
        CONSTANT_URI = root ? new HashMap<>() : null;
    }

    public ControllerMetaInfo getController() {
        return controller;
    }

    public String getEncoding() {
        return ENCODING;
    }

    public void add(String uri, ControllerMetaInfo c) {
        if (uri.contains(WILDCARD)) {
            Resource current = this;
            List list = URLParser.parse(uri);
            int max = list.size() - 1;

            for (int i = 0; ; i++) {
                String name = list.get(i);
                if (i == max) {
                    current = current.children.add(name, c);
                    return;
                }

                current = current.children.add(name, null);
            }
        } else {
            char last = uri.charAt(uri.length() - 1);
            if (last != '/') {
                uri += "/";
            }
            Resource resource = new Resource(false);
            resource.uri = uri;
            resource.controller = c;
            Result result = new Result(resource, null);
            CONSTANT_URI.put(uri, result);
        }
    }

    public Result match(String uri) {
        char last = uri.charAt(uri.length() - 1);
        if (last != '/') {
            uri += "/";
        }

        Result ret = CONSTANT_URI.get(uri);
        if (ret != null)
            return ret;

        Resource current = this;
        List list = URLParser.parse(uri);
        List params = new ArrayList<>();

        for (String i : list) {
            ret = current.children.match(i);
            if (ret == null)
                return ret;

            if (ret.params != null) {
                for (String p : ret.params)
                    params.add(p);
            }

            current = ret.resource;
        }

        if (ret == null || ret.resource.controller == null)
            return null;

        if (params.size() > 0)
            ret.params = params.toArray(EMPTY);
        return ret;
    }

    public static class Result implements WebHandler {
        private final Resource resource;
        private String[] params;

        public Result(Resource resource, String[] params) {
            this.resource = resource;
            this.params = params;
        }

        public ControllerMetaInfo getController() {
            return resource.controller;
        }

        public String[] getParams() {
            return params;
        }

        @Override
        public View invoke(HttpServletRequest request, HttpServletResponse response) {
            if (!resource.controller.allowMethod(request.getMethod())) {
                notAllowMethodResponse(request, response);
                return null;
            }

            if (getController().getMultipartConfigElement() != null && request instanceof HTTPServletRequestImpl) {
                HTTPServletRequestImpl r = (HTTPServletRequestImpl) request;
                r.setMultipartConfigElement(getController().getMultipartConfigElement());
            }
            Object[] p = getController().getParameters(request, response, null, getParams());
            return getController().invoke(p);
        }

        private void notAllowMethodResponse(HttpServletRequest request, HttpServletResponse response) {
            response.setHeader("Allow", resource.controller.getAllowMethod());
            SystemHtmlPage.responseSystemPage(request, response, ENCODING, HttpServletResponse.SC_METHOD_NOT_ALLOWED,
                    "Only support " + resource.controller.getAllowMethod() + " method");
        }

        @Override
        public String toString() {
            return "Result [resource=" + resource + ", params=" + Arrays.toString(params) + "]";
        }

    }

    private class ResourceSet implements Iterable {
        private Map map = new HashMap<>();
        private List list = new LinkedList<>();

        private boolean isVariable() {
            return list.size() > 0;
        }

        private Result match(String str) {
            Resource ret = map.get(str);
            if (ret != null) {
                return new Result(ret, null);
            }
            for (Resource res : list) {
                String[] p = res.pattern.match(str);
                if (p != null)
                    return new Result(res, p);
            }
            return null;
        }

        private Resource add(String uri, ControllerMetaInfo c) {
            Resource resource = findByURI(uri);
            if (resource == null) {
                resource = new Resource(false);
                resource.uri = uri;

                if (uri.contains(WILDCARD)) {
                    resource.pattern = Pattern.compile(resource.uri, WILDCARD);
                    list.add(resource);
                } else {
                    map.put(uri, resource);
                }
            }
            if (c != null) {
                resource.controller = c;
            }
            return resource;
        }

        private Resource findByURI(String uri) {
            Resource r = map.get(uri);
            if (r != null) {
                return r;
            } else {
                for (Resource res : list) {
                    if (uri.equals(res.uri))
                        return res;
                }
            }
            return null;
        }

        @Override
        public Iterator iterator() {
            return new ResourceSetItr();
        }

        private class ResourceSetItr implements Iterator {

            private Iterator listItr = list.iterator();
            private Iterator> mapItr = map.entrySet().iterator();

            @Override
            public boolean hasNext() {
                return mapItr.hasNext() || listItr.hasNext();
            }

            @Override
            public Resource next() {
                if (mapItr.hasNext())
                    return mapItr.next().getValue();
                else
                    return listItr.next();
            }

            @Override
            public void remove() {
                throw new RuntimeException("not implements this method!");
            }

        }

    }

    @Override
    public String toString() {
        return toString(" ", "");
    }

    private String toString(String l, String append) {
        StringBuilder s = new StringBuilder();
        s.append(append + uri + "(" + children.isVariable() + ")" + "\r\n");
        for (Resource r : children) {
            s.append(l + r.toString(l + " ", "├"));
        }
        return s.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((uri == null) ? 0 : uri.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Resource other = (Resource) obj;
        if (uri == null) {
            if (other.uri != null)
                return false;
        } else if (!uri.equals(other.uri))
            return false;
        return true;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy