Package org.jboss.as.domain.http.server

Source Code of org.jboss.as.domain.http.server.ResourceHandler$ResourceHandle

/*
* JBoss, Home of Professional Open Source.
* Copyright 2011, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.domain.http.server;


import static org.jboss.as.domain.http.server.Constants.APPLICATION_JAVASCRIPT;
import static org.jboss.as.domain.http.server.Constants.APPLICATION_OCTET_STREAM;
import static org.jboss.as.domain.http.server.Constants.CONTENT_TYPE;
import static org.jboss.as.domain.http.server.Constants.FORBIDDEN;
import static org.jboss.as.domain.http.server.Constants.GET;
import static org.jboss.as.domain.http.server.Constants.IMAGE_GIF;
import static org.jboss.as.domain.http.server.Constants.IMAGE_JPEG;
import static org.jboss.as.domain.http.server.Constants.IMAGE_PNG;
import static org.jboss.as.domain.http.server.Constants.LOCATION;
import static org.jboss.as.domain.http.server.Constants.METHOD_NOT_ALLOWED;
import static org.jboss.as.domain.http.server.Constants.MOVED_PERMENANTLY;
import static org.jboss.as.domain.http.server.Constants.NOT_FOUND;
import static org.jboss.as.domain.http.server.Constants.OK;
import static org.jboss.as.domain.http.server.Constants.TEXT_CSS;
import static org.jboss.as.domain.http.server.Constants.TEXT_HTML;
import static org.jboss.as.domain.http.server.HttpServerMessages.MESSAGES;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;

import org.jboss.as.domain.management.SecurityRealm;
import org.jboss.com.sun.net.httpserver.Headers;
import org.jboss.com.sun.net.httpserver.HttpExchange;
import org.jboss.com.sun.net.httpserver.HttpServer;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoadException;

/**
* A generic handler to server up resources requested using a GET request.
*
* The ClassLoader provided in the constructor should only have access to
* resources being server by this handler.
*
* @author Heiko Braun
* @date 3/14/11
*/
class ResourceHandler implements ManagementHttpHandler {

    private static final String EXPIRES_HEADER = "Expires";
    private static final String LAST_MODIFIED_HEADER = "Last-Modified";
    private static final String GMT = "GMT";
    private static final String CACHE_CONTROL_HEADER = "Cache-Control";
    private static final String CONTENT_LENGTH_HEADER = "Content-Length";

    private static Map<String, String> contentTypeMapping = new ConcurrentHashMap<String, String>();
    private static final String FORMAT_STRING = "EEE, dd MMM yyyy HH:mm:ss z";

    private final String context;
    private final String defaultResource;
    private final ClassLoader loader;

    private final String lastModified;
    private long lastExpiryDate = 0;
    private String lastExpiryHeader = null;

    private final Map<String, ResourceHandle> buffer = new ConcurrentHashMap<String, ResourceHandle>();

    static {
        contentTypeMapping.put(".js",   APPLICATION_JAVASCRIPT);
        contentTypeMapping.put(".html", TEXT_HTML);
        contentTypeMapping.put(".htm",  TEXT_HTML);
        contentTypeMapping.put(".css",  TEXT_CSS);
        contentTypeMapping.put(".gif",  IMAGE_GIF);
        contentTypeMapping.put(".png",  IMAGE_PNG);
        contentTypeMapping.put(".jpeg", IMAGE_JPEG);
    }

    public ResourceHandler(final String context, final String defaultResource, final ClassLoader loader) {
        this.context = context;
        this.defaultResource = defaultResource;
        this.loader = loader;

        lastModified = createDateFormat().format(new Date());
    }

    String getDefaultPath() {
        return context + defaultResource;
    }

    protected String getContext() {
        return context;
    }

    public void handle(HttpExchange http) throws IOException {
        final URI uri = http.getRequestURI();
        final String requestMethod = http.getRequestMethod();

        // only GET supported
        if (!GET.equals(requestMethod)) {
            http.sendResponseHeaders(METHOD_NOT_ALLOWED, -1);
            return;
        }

        // normalize to request resource
        String path = uri.getPath();
        String resource = path.substring(context.length(), path.length());
        if(resource.startsWith("/")) resource = resource.substring(1);

        if (resource.equals("")) {
            /*
             * This is a request to the root of the context, redirect to the
             * default resource.
             */
            Headers responseHeaders = http.getResponseHeaders();
            responseHeaders.add(LOCATION, getDefaultPath());
            http.sendResponseHeaders(MOVED_PERMENANTLY, 0);
            http.close();

            return;
        } else if (!resource.contains(".")) {
            respond404(http);
        }

        /*
         * This allows a sub-class of the ResourceHandler to store resources it may need in META-INF
         * without these resources being served up to remote clients unchecked.
         */
        if (resource.startsWith("META-INF")) {
            http.sendResponseHeaders(FORBIDDEN, 0);
            http.close();

            return;
        }

        // load resource
        ResourceHandle handle = getResourceHandle(resource);

        if(handle.getInputStream()!=null) {

            InputStream inputStream = handle.getInputStream();

            final Headers responseHeaders = http.getResponseHeaders();
            responseHeaders.add(CONTENT_TYPE, resolveContentType(path));

            // provide the ability to cache GWT artifacts
            if(!skipCache(resource)){

                if(System.currentTimeMillis()>lastExpiryDate) {
                    lastExpiryDate = calculateExpiryDate();
                    lastExpiryHeader = createDateFormat().format(new Date(lastExpiryDate));
                }

                responseHeaders.add(CACHE_CONTROL_HEADER, "private, max-age=2678400, must-revalidate");
                responseHeaders.add(EXPIRES_HEADER, lastExpiryHeader);
            }

            responseHeaders.add(LAST_MODIFIED_HEADER, lastModified);
            responseHeaders.add(CONTENT_LENGTH_HEADER, String.valueOf(handle.getSize()));

            http.sendResponseHeaders(OK, 0);

            // nio write
            OutputStream outputStream = http.getResponseBody();
            fastChannelCopy(inputStream, outputStream);
            outputStream.flush();

            safeClose(outputStream);
            safeClose(inputStream);

        } else {
            respond404(http);
        }

    }

    private ResourceHandle getResourceHandle(String resource) {


        ResourceHandle handle = buffer.get(resource);

        if(handle==null){

            InputStream resourceStream = getLoader().getResourceAsStream(resource);

            if(resourceStream!=null) {

                try {
                    ByteArrayOutputStream bout = new ByteArrayOutputStream();
                    fastChannelCopy(resourceStream, bout);
                    bout.flush();
                    bout.close();
                    resourceStream.close();
                    handle = new ResourceHandle(bout.toByteArray());
                } catch (IOException e) {
                    throw MESSAGES.failedReadingResource(e, resource);
                }

                 buffer.put(resource, handle);
            }
            else {
                // 404
                handle = new ResourceHandle(null);
            }
        }

        return handle;
    }

    private static DateFormat createDateFormat(){
        DateFormat df = new SimpleDateFormat(FORMAT_STRING, Locale.US);
        df.setTimeZone(TimeZone.getTimeZone(GMT));
        return df;
    }

    private static long calculateExpiryDate() {
        Calendar cal = Calendar.getInstance();
        cal.roll(Calendar.MONTH, 1);
        return cal.getTime().getTime();
    }

    public static void fastChannelCopy(final InputStream in, final OutputStream out) throws IOException {

        final ReadableByteChannel src = Channels.newChannel(in);
        final WritableByteChannel dest = Channels.newChannel(out);

        try {
            final ByteBuffer buffer = ByteBuffer.allocate(8 * 1024);
            while (src.read(buffer) != -1) {
                buffer.flip();
                dest.write(buffer);
                buffer.compact();
            }
            buffer.flip();

            while (buffer.hasRemaining()) {
                dest.write(buffer);
            }
        } finally {
            safeClose(src);
            safeClose(dest);
        }
    }

    private static void safeClose(Closeable close) {
        try {
            if(close!=null)
                close.close();
        } catch (Throwable eat) {
        }
    }

    private String resolveContentType(String resource) {
        assert resource.indexOf(".")!=-1 : MESSAGES.invalidResource();

        String contentType = null;
        for(String suffix : contentTypeMapping.keySet()) {
            if(resource.endsWith(suffix)) {
                contentType = contentTypeMapping.get(suffix);
                break;
            }
        }

        if(null==contentType) contentType = APPLICATION_OCTET_STREAM;

        return contentType;
    }

    private void respond404(HttpExchange http) throws IOException {

        final Headers responseHeaders = http.getResponseHeaders();
        responseHeaders.add(CONTENT_TYPE, TEXT_HTML);
        http.sendResponseHeaders(NOT_FOUND, 0);
        OutputStream out = http.getResponseBody();
        out.flush();
        safeClose(out);
    }

    private ClassLoader getLoader() {
            return loader;
    }

    public void start(HttpServer httpServer, SecurityRealm securityRealm) {
        httpServer.createContext(context, this);
    }

    public void stop(HttpServer httpServer) {
        httpServer.removeContext(context);
    }

    protected static ClassLoader getClassLoader(final String module, final String slot) throws ModuleLoadException {
        ModuleIdentifier id = ModuleIdentifier.create(module, slot);
        ClassLoader cl = Module.getCallerModuleLoader().loadModule(id).getClassLoader();

        return cl;
    }

    protected boolean skipCache(String resource) {
        return false;
    }

    class ResourceHandle {

        private final byte[] content;

        ResourceHandle(byte[] content) {
            this.content = content;
        }

        public int getSize() {
            return content.length;
        }

        public InputStream getInputStream() {
            return content!=null ? new ByteArrayInputStream(content) : null;
        }
    }
}
TOP

Related Classes of org.jboss.as.domain.http.server.ResourceHandler$ResourceHandle

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.