org.apache.shindig.gadgets.servlet.JsServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.shindig.gadgets.servlet.JsServlet.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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.apache.shindig.gadgets.servlet;

import org.apache.commons.lang.StringEscapeUtils;

import org.apache.shindig.common.servlet.HttpUtil;
import org.apache.shindig.common.servlet.InjectedServlet;
import org.apache.shindig.common.uri.UriBuilder;
import org.apache.shindig.gadgets.GadgetException;
import org.apache.shindig.gadgets.uri.JsUriManager;
import org.apache.shindig.gadgets.uri.UriStatus;

import com.google.inject.Inject;

import java.io.IOException;
import java.util.regex.Pattern;

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

/**
 * Simple servlet serving up JavaScript files by their registered aliases.
 * Used by type=URL gadgets in loading JavaScript resources.
 */
public class JsServlet extends InjectedServlet {

    private static final long serialVersionUID = 6255917470412008175L;

    static final String ONLOAD_JS_TPL = "(function() {" + "var nm='%s';" + "if (typeof window[nm]==='function') {"
            + "window[nm]();" + '}' + "})();";
    private static final Pattern ONLOAD_FN_PATTERN = Pattern.compile("[a-zA-Z0-9_]+");

    private transient JsHandler jsHandler;
    private transient JsUriManager jsUriManager;

    @Inject
    public void setJsHandler(JsHandler jsHandler) {
        checkInitialized();
        this.jsHandler = jsHandler;
    }

    @Inject
    public void setUrlGenerator(JsUriManager jsUriManager) {
        checkInitialized();
        this.jsUriManager = jsUriManager;
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // If an If-Modified-Since header is ever provided, we always say
        // not modified. This is because when there actually is a change,
        // cache busting should occur.
        UriStatus vstatus = null;
        try {
            vstatus = jsUriManager.processExternJsUri(new UriBuilder(req).toUri()).getStatus();
        } catch (GadgetException e) {
            resp.sendError(e.getHttpStatusCode(), e.getMessage());
            return;
        }
        if (req.getHeader("If-Modified-Since") != null && vstatus == UriStatus.VALID_VERSIONED) {
            resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }

        // Get JavaScript content from features aliases request.
        JsHandler.JsHandlerResponse handlerResponse = jsHandler.getJsContent(req);
        StringBuilder jsData = handlerResponse.getJsData();
        boolean isProxyCacheable = handlerResponse.isProxyCacheable();

        // Add onload handler to add callback function.
        String onloadStr = req.getParameter("onload");
        if (onloadStr != null) {
            if (!ONLOAD_FN_PATTERN.matcher(onloadStr).matches()) {
                resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid onload callback specified");
                return;
            }
            jsData.append(String.format(ONLOAD_JS_TPL, StringEscapeUtils.escapeJavaScript(onloadStr)));
        }

        if (jsData.length() == 0) {
            resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
            return;
        }

        // post JavaScript content fetching
        postJsContentProcessing(resp, vstatus, isProxyCacheable);

        resp.setContentType("text/javascript; charset=utf-8");
        byte[] response = jsData.toString().getBytes("UTF-8");
        resp.setContentLength(response.length);
        resp.getOutputStream().write(response);
    }

    /**
     * Provides post JavaScript content processing. The default behavior will check the UriStatus and
     * update the response header with cache option.
     * 
     * @param resp The HttpServeltResponse object.
     * @param vstatus The UriStatus object.
     * @param isProxyCacheable boolean true if content is cacheable and false otherwise.
     */
    protected void postJsContentProcessing(HttpServletResponse resp, UriStatus vstatus, boolean isProxyCacheable) {
        switch (vstatus) {
        case VALID_VERSIONED:
            // Versioned files get cached indefinitely
            HttpUtil.setCachingHeaders(resp, !isProxyCacheable);
            break;
        case VALID_UNVERSIONED:
            // Unversioned files get cached for 1 hour.
            HttpUtil.setCachingHeaders(resp, 60 * 60, !isProxyCacheable);
            break;
        case INVALID_VERSION:
            // URL is invalid in some way, likely version mismatch.
            // Indicate no-cache forcing subsequent requests to regenerate URLs.
            HttpUtil.setNoCache(resp);
            break;
        }
    }
}