/** * Copyright (C) [2013] [Anjuke Inc] * * 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.apache.hadoop.hive.hwi.servlet; import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServletRequest; import org.apache.velocity.Template; import org.apache.velocity.tools.view.VelocityView; import org.apache.velocity.context.Context; import org.apache.velocity.exception.MethodInvocationException; public class Velocity extends VelocityView{ /** * The velocity.properties key for specifying the servlet's error template. */ public static final String PROPERTY_ERROR_TEMPLATE = "tools.view.servlet.error.template"; /** * The velocity.properties key for specifying the relative directory holding * layout templates. */ public static final String PROPERTY_LAYOUT_DIR = "tools.view.servlet.layout.directory"; /** * The velocity.properties key for specifying the servlet's default layout * template's filename. */ public static final String PROPERTY_DEFAULT_LAYOUT = "tools.view.servlet.layout.default.template"; /** * The default error template's filename. */ public static final String DEFAULT_ERROR_TEMPLATE = "Error.vm"; /** * The default layout directory */ public static final String DEFAULT_LAYOUT_DIR = "layout/"; /** * The default filename for the servlet's default layout */ public static final String DEFAULT_DEFAULT_LAYOUT = "Default.vm"; /** * The context key that will hold the content of the screen. * * This key ($screen_content) must be present in the layout template for the * current screen to be rendered. */ public static final String KEY_SCREEN_CONTENT = "screen_content"; /** * The context/parameter key used to specify an alternate layout to be used * for a request instead of the default layout. */ public static final String KEY_LAYOUT = "layout"; /** * The context key that holds the {@link Throwable} that broke the rendering * of the requested screen. */ public static final String KEY_ERROR_CAUSE = "error_cause"; /** * The context key that holds the stack trace of the error that broke the * rendering of the requested screen. */ public static final String KEY_ERROR_STACKTRACE = "stack_trace"; /** * The context key that holds the {@link MethodInvocationException} that * broke the rendering of the requested screen. * * If this value is placed in the context, then $error_cause will hold the * error that this invocation exception is wrapping. */ public static final String KEY_ERROR_INVOCATION_EXCEPTION = "invocation_exception"; protected String errorTemplate; protected String layoutDir; protected String defaultLayout; public Velocity(ServletConfig config) { super(config); // check for default template path overrides errorTemplate = getProperty(PROPERTY_ERROR_TEMPLATE, DEFAULT_ERROR_TEMPLATE); layoutDir = getProperty(PROPERTY_LAYOUT_DIR, DEFAULT_LAYOUT_DIR); defaultLayout = getProperty(PROPERTY_DEFAULT_LAYOUT, DEFAULT_DEFAULT_LAYOUT); // preventive error checking! directory must end in / if (!layoutDir.endsWith("/")) { layoutDir += '/'; } // for efficiency's sake, make defaultLayout a full path now defaultLayout = layoutDir + defaultLayout; } public void render(String path, HttpServletRequest request, Writer writer) throws IOException { // then get a context Context context = createContext(request, null); // get the template Template template = getTemplate(path); // merge the template and context into the response mergeTemplate(template, context, writer); } /** * Overrides VelocityViewServlet.mergeTemplate to do a two-pass render for * handling layouts */ protected void mergeTemplate(Template template, Context context, Writer writer) throws IOException { // // this section is based on Tim Colson's "two pass render" // // Render the screen content StringWriter sw = new StringWriter(); template.merge(context, sw); // Add the resulting content to the context context.put(KEY_SCREEN_CONTENT, sw.toString()); //Get layout Object obj = context.get(KEY_LAYOUT); String layout = (obj == null) ? null : obj.toString(); if (layout == null) { layout = defaultLayout; } else { layout = layoutDir + layout; } //Render layout try { template = getTemplate(layout); } catch (Exception e) { if (!layout.equals(defaultLayout)) { template = getTemplate(defaultLayout); } } merge(template, context, writer); } public boolean templateExists(String name){ return velocity.resourceExists(name); } }