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

org.jboss.weld.probe.Resource Maven / Gradle / Ivy

There is a newer version: 3.0.0.Alpha1
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2014, Red Hat, Inc., and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * 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 org.jboss.weld.probe;

import static org.jboss.weld.probe.Strings.APPLICATION_FONT_MS;
import static org.jboss.weld.probe.Strings.APPLICATION_FONT_SFNT;
import static org.jboss.weld.probe.Strings.APPLICATION_FONT_WOFF;
import static org.jboss.weld.probe.Strings.ENCODING_UTF8;
import static org.jboss.weld.probe.Strings.FILE_CLIENT_HTML;
import static org.jboss.weld.probe.Strings.FILTERS;
import static org.jboss.weld.probe.Strings.HTTP_HEADER_CACHE_CONTROL;
import static org.jboss.weld.probe.Strings.IMG_ICO;
import static org.jboss.weld.probe.Strings.IMG_PNG;
import static org.jboss.weld.probe.Strings.IMG_SVG;
import static org.jboss.weld.probe.Strings.PAGE;
import static org.jboss.weld.probe.Strings.PAGE_SIZE;
import static org.jboss.weld.probe.Strings.PARAM_TRANSIENT_DEPENDENCIES;
import static org.jboss.weld.probe.Strings.PARAM_TRANSIENT_DEPENDENTS;
import static org.jboss.weld.probe.Strings.PATH_META_INF_CLIENT;
import static org.jboss.weld.probe.Strings.REPRESENTATION;
import static org.jboss.weld.probe.Strings.RESOURCE_PARAM_END;
import static org.jboss.weld.probe.Strings.RESOURCE_PARAM_START;
import static org.jboss.weld.probe.Strings.SLASH;
import static org.jboss.weld.probe.Strings.SUFFIX_CSS;
import static org.jboss.weld.probe.Strings.SUFFIX_EOT;
import static org.jboss.weld.probe.Strings.SUFFIX_HTML;
import static org.jboss.weld.probe.Strings.SUFFIX_ICO;
import static org.jboss.weld.probe.Strings.SUFFIX_JS;
import static org.jboss.weld.probe.Strings.SUFFIX_OTF;
import static org.jboss.weld.probe.Strings.SUFFIX_PNG;
import static org.jboss.weld.probe.Strings.SUFFIX_SVG;
import static org.jboss.weld.probe.Strings.SUFFIX_TTF;
import static org.jboss.weld.probe.Strings.SUFFIX_WOFF;
import static org.jboss.weld.probe.Strings.TEXT_CSS;
import static org.jboss.weld.probe.Strings.TEXT_HTML;
import static org.jboss.weld.probe.Strings.TEXT_JAVASCRIPT;
import static org.jboss.weld.probe.Strings.TEXT_PLAIN;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.enterprise.inject.Vetoed;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jboss.weld.probe.Queries.Filters;

/**
 * REST API resources.
 *
 * @author Martin Kouba
 */
@Vetoed
enum Resource {

    /**
     * A deployment info.
     */
    DEPLOYMENT("/deployment", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            append(resp, jsonDataProvider.receiveDeployment());
        }
    }),
    /**
     * A collection of beans.
     */
    BEANS("/beans", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            append(resp, jsonDataProvider.receiveBeans(getPage(req), getPageSize(req), req.getParameter(FILTERS), req.getParameter(REPRESENTATION)));
        }
    }),
    /**
     * A single bean detail.
     */
    BEAN("/beans/{.+}", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            appendFound(resp, jsonDataProvider.receiveBean(resourcePathParts[1], Boolean.valueOf(req.getParameter(PARAM_TRANSIENT_DEPENDENCIES)),
                    Boolean.valueOf(req.getParameter(PARAM_TRANSIENT_DEPENDENTS))));
        }
    }),
    /**
     * A contextual instance of a bean. This is only supported for a limited set of scopes.
     */
    BEAN_INSTANCE("/beans/{.+}/instance", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            appendFound(resp, jsonDataProvider.receiveBeanInstance(resourcePathParts[1]));
        }
    }),
    /**
     * A collection of observers methods.
     */
    OBSERVERS("/observers", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            append(resp, jsonDataProvider.receiveObservers(getPage(req), getPageSize(req), req.getParameter(FILTERS), req.getParameter(REPRESENTATION)));
        }
    }),
    /**
     * A single observer.
     */
    OBSERVER("/observers/{.+}", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            appendFound(resp, jsonDataProvider.receiveObserver(resourcePathParts[1]));
        }
    }),
    /**
     * A collection of inspectable contexts.
     */
    CONTEXTS("/contexts", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            append(resp, jsonDataProvider.receiveContexts());
        }
    }),
    /**
     * A collection of contextual instances for the given inspectable context.
     */
    CONTEXT("/contexts/{[a-zA-Z_0]+}", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            appendFound(resp, jsonDataProvider.receiveContext(resourcePathParts[1]));
        }
    }),
    /**
     * A collection of invocation trees.
     */
    INVOCATIONS("/invocations", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            append(resp, jsonDataProvider.receiveInvocations(getPage(req), getPageSize(req), req.getParameter(FILTERS), req.getParameter(REPRESENTATION)));
        }

        @Override
        protected void delete(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
            append(resp, jsonDataProvider.clearInvocations());
        }
    }),
    /**
     * A single invocation tree.
     */
    INVOCATION("/invocations/{.+}", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            appendFound(resp, jsonDataProvider.receiveInvocation(resourcePathParts[1]));
        }
    }),
    /**
     * The event bus
     */
    EVENTS("/events", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            append(resp, jsonDataProvider.receiveEvents(getPage(req), getPageSize(req), req.getParameter(FILTERS)));
        }

        @Override
        protected void delete(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
            append(resp, jsonDataProvider.clearEvents());
        }
    }),
    MONITORING_STATS("/monitoring", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            append(resp, jsonDataProvider.receiveMonitoringStats());
        }
    }),
    AVAILABLE_BEANS("/availableBeans", new Handler() {
        @Override
        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            append(resp, jsonDataProvider.receiveAvailableBeans(getPage(req), getPageSize(req), req.getParameter(FILTERS), req.getParameter(REPRESENTATION)));
        }
    }),
    /**
     * A default HTML client resource.
     */
    CLIENT_RESOURCE("/client/{[a-zA-Z_0-9-]+\\.\\w+}", new Handler() {
        @Override
        protected void handle(HttpMethod method, JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req,
                HttpServletResponse resp) throws IOException {

            if (!HttpMethod.GET.equals(method)) {
                resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
                return;
            }

            String resourceName = PATH_META_INF_CLIENT + (resourcePathParts.length == 0 ? FILE_CLIENT_HTML : resourcePathParts[resourcePathParts.length - 1]);
            String contentType = detectContentType(resourceName);
            setHeaders(resp, contentType);

            if (isCachableContentType(contentType)) {
                // Set Cache-Control header - 24 hours
                resp.setHeader(HTTP_HEADER_CACHE_CONTROL, "max-age=86400");
            }

            if (isTextBasedContenType(contentType)) {
                String content = IOUtils.getResourceAsString(resourceName);
                if (content == null) {
                    resp.sendError(HttpServletResponse.SC_NOT_FOUND);
                    return;
                }
                content = content.replace("${contextPath}", req.getServletContext().getContextPath() + ProbeFilter.REST_URL_PATTERN_BASE + SLASH);
                resp.getWriter().append(content);
            } else {
                if (!IOUtils.writeResource(resourceName, resp.getOutputStream())) {
                    resp.sendError(HttpServletResponse.SC_NOT_FOUND);
                }
            }
        }
    }),
    EXPORT("/export", new Handler() {
        @Override
        protected void handle(HttpMethod method, JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req,
                HttpServletResponse resp) throws IOException {
            if (!HttpMethod.GET.equals(method)) {
                resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
                return;
            }
            setHeaders(resp, "application/zip");
            resp.setHeader("Content-disposition", "attachment; filename=\"weld-probe-export.zip\"");
            ServletOutputStream out = resp.getOutputStream();
            out.write(Exports.exportJsonData(jsonDataProvider));
            out.flush();
        }
    }),
    ;

    // --- Instance variables

    private final String[] parts;

    private final Handler handler;

    Resource(String path, Handler handler) {
        this.parts = splitPath(path);
        this.handler = handler;
    }

    protected void handle(HttpMethod method, JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        handler.handle(method, jsonDataProvider, resourcePathParts, req, resp);
    }

    /**
     * @param resourcePathParts
     * @return true if the resource matches the given path, false otherwise
     */
    boolean matches(String[] resourcePathParts) {
        if (resourcePathParts.length != parts.length) {
            return false;
        }
        for (int i = 0; i < parts.length; i++) {
            if (isParam(parts[i])) {
                if (!resourcePathParts[i].matches(parts[i].substring(1, parts[i].length() - 1))) {
                    return false;
                }
            } else if (!parts[i].equals(resourcePathParts[i])) {
                return false;
            }
        }
        return true;
    }

    /**
     * @return the parts of the path
     */
    String[] getParts() {
        return parts;
    }

    static boolean isParam(String part) {
        return part.startsWith(RESOURCE_PARAM_START) && part.endsWith(RESOURCE_PARAM_END);
    }

    static String[] splitPath(String path) {
        List parts = new ArrayList();
        StringBuilder builder = null;
        for (int i = 0; i < path.length(); i++) {
            char c = path.charAt(i);
            if (c == '/') {
                if (builder != null) {
                    parts.add(builder.toString());
                    builder = null;
                }
            } else {
                if (builder == null) {
                    builder = new StringBuilder();
                }
                builder.append(c);
            }
        }
        if (builder != null) {
            parts.add(builder.toString());
        }
        return parts.toArray(new String[parts.size()]);
    }

    static String detectContentType(String resourceName) {
        if (resourceName.endsWith(SUFFIX_HTML)) {
            return TEXT_HTML;
        } else if (resourceName.endsWith(SUFFIX_CSS)) {
            return TEXT_CSS;
        } else if (resourceName.endsWith(SUFFIX_JS)) {
            return TEXT_JAVASCRIPT;
        } else if (resourceName.endsWith(SUFFIX_PNG)) {
            return IMG_PNG;
        } else if (resourceName.endsWith(SUFFIX_TTF) || resourceName.endsWith(SUFFIX_OTF)) {
            return APPLICATION_FONT_SFNT;
        } else if (resourceName.endsWith(SUFFIX_EOT)) {
            return APPLICATION_FONT_MS;
        } else if (resourceName.endsWith(SUFFIX_WOFF)) {
            return APPLICATION_FONT_WOFF;
        } else if (resourceName.endsWith(SUFFIX_SVG)) {
            return IMG_SVG;
        } else if (resourceName.endsWith(SUFFIX_ICO)) {
            return IMG_ICO;
        } else {
            return TEXT_PLAIN;
        }
    }

    static boolean isCachableContentType(String contentType) {
        return TEXT_CSS.equals(contentType) || TEXT_JAVASCRIPT.equals(contentType) || IMG_ICO.equals(contentType) || IMG_PNG.equals(contentType)
                || IMG_SVG.equals(contentType);
    }

    static boolean isTextBasedContenType(String contentType) {
        return !(IMG_PNG.equals(contentType) || IMG_ICO.equals(contentType) || APPLICATION_FONT_SFNT.equals(contentType)
                || APPLICATION_FONT_WOFF.equals(contentType) || APPLICATION_FONT_MS.equals(contentType));
    }

    abstract static class Handler implements Serializable {
        private static final long serialVersionUID = 5253937931990206305L;

        protected void handle(HttpMethod method, JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req,
                HttpServletResponse resp) throws IOException {
            setHeaders(resp, getContentType());
            switch (method) {
                case GET:
                    get(jsonDataProvider, resourcePathParts, req, resp);
                    break;
                case POST:
                    post(jsonDataProvider, resourcePathParts, req, resp);
                    break;
                case DELETE:
                    delete(jsonDataProvider, resourcePathParts, req, resp);
                    break;
                case OPTIONS:
                    options(jsonDataProvider, resourcePathParts, req, resp);
                    break;
                default:
                    resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
            }
        }

        protected void get(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp) throws IOException {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }

        protected void post(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }

        protected void delete(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
        }

        protected void options(JsonDataProvider jsonDataProvider, String[] resourcePathParts, HttpServletRequest req, HttpServletResponse resp)
                throws IOException {
            setCorsHeaders(resp);
        }

        protected void append(HttpServletResponse resp, String content) throws IOException {
            resp.getWriter().append(content);
        }

        protected void appendFound(HttpServletResponse resp, String content) throws IOException {
            if (content != null) {
                resp.getWriter().append(content);
            } else {
                resp.sendError(HttpServletResponse.SC_NOT_FOUND);
            }
        }

        protected int getPage(HttpServletRequest req) {
            String pageParam = req.getParameter(PAGE);
            if (pageParam == null) {
                return 1;
            }
            try {
                return Integer.parseInt(pageParam);
            } catch (NumberFormatException e) {
                return 1;
            }
        }

        protected int getPageSize(HttpServletRequest req) {
            String pageSizeParam = req.getParameter(PAGE_SIZE);
            if (pageSizeParam == null) {
                return Queries.DEFAULT_PAGE_SIZE;
            } else {
                try {
                    int result = Integer.parseInt(pageSizeParam);
                    return result > 0 ? result : 0;
                } catch (NumberFormatException e) {
                    return 0;
                }
            }
        }

        protected > T initFilters(HttpServletRequest req, T filters) {
            return Queries.initFilters(req.getParameter(FILTERS), filters);
        }

        protected String getContentType() {
            return Strings.APPLICATION_JSON;
        }

        static void setHeaders(HttpServletResponse resp, String contentType) {
            resp.setCharacterEncoding(ENCODING_UTF8);
            resp.setContentType(contentType);
            setCorsHeaders(resp);
        }

        static void setCorsHeaders(HttpServletResponse resp) {
            // Support cross-site HTTP requests - we want to support external HTML5 clients
            // See https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
            resp.setHeader("Access-Control-Allow-Origin", "*");
            resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
        }

    }

    static enum HttpMethod {

        GET, POST, DELETE, OPTIONS;

        static HttpMethod from(String method) {
            for (HttpMethod httpMethod : values()) {
                if (httpMethod.toString().equalsIgnoreCase(method)) {
                    return httpMethod;
                }
            }
            return null;
        }

    }

    static enum Representation {

        SIMPLE, BASIC, FULL,

        ;

        static Representation from(String value) {
            for (Representation representation : values()) {
                if (representation.toString().equalsIgnoreCase(value)) {
                    return representation;
                }
            }
            return null;
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy