| /* |
| * 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.myfaces.view.facelets.tag.ui; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import javax.faces.component.UIComponent; |
| import javax.faces.component.UIComponentBase; |
| import javax.faces.context.FacesContext; |
| import javax.faces.context.ResponseWriter; |
| import javax.servlet.http.HttpServletResponse; |
| |
| import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFComponent; |
| import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty; |
| import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty; |
| import org.apache.myfaces.renderkit.ErrorPageWriter; |
| import org.apache.myfaces.util.lang.FastWriter; |
| |
| /** |
| * The debug tag will capture the component tree and variables when it is encoded, |
| * storing the data for retrieval later. You may launch the debug window at any time |
| * from your browser by pressing 'CTRL' + 'SHIFT' + 'D' (by default). |
| * |
| * The debug tag doesn't need to be used with the facelet.DEVELOPMENT parameter. |
| * The best place to put this tag is in your site's main template where it can be |
| * enabled/disabled across your whole application. |
| * |
| * If your application uses multiple windows, you might want to assign different |
| * hot keys to each one. |
| * |
| * @author Jacob Hookom |
| * @version $Id$ |
| */ |
| @JSFComponent(name="ui:debug") |
| @JSFJspProperty(name = "binding", tagExcluded=true) |
| public final class UIDebug extends UIComponentBase |
| { |
| public static final String COMPONENT_TYPE = "facelets.ui.Debug"; |
| public static final String COMPONENT_FAMILY = "facelets"; |
| public static final String DEFAULT_HOTKEY = "D"; |
| |
| private static final String KEY = "facelets.ui.DebugOutput"; |
| |
| private static long nextId = System.currentTimeMillis(); |
| |
| private String _hotkey = DEFAULT_HOTKEY; |
| |
| public UIDebug() |
| { |
| setTransient(true); |
| setRendererType(null); |
| } |
| |
| @Override |
| public String getFamily() |
| { |
| return COMPONENT_FAMILY; |
| } |
| |
| @Override |
| public List<UIComponent> getChildren() |
| { |
| return new ArrayList<UIComponent>() |
| { |
| @Override |
| public boolean add(UIComponent o) |
| { |
| throw new IllegalStateException("<ui:debug> does not support children"); |
| } |
| |
| @Override |
| public void add(int index, UIComponent o) |
| { |
| throw new IllegalStateException("<ui:debug> does not support children"); |
| } |
| }; |
| } |
| |
| @Override |
| public void encodeBegin(FacesContext faces) throws IOException |
| { |
| boolean partialRequest = faces.getPartialViewContext().isPartialRequest(); |
| |
| String actionId = faces.getApplication().getViewHandler() |
| .getActionURL(faces, faces.getViewRoot().getViewId()); |
| |
| StringBuilder sb = new StringBuilder(512); |
| sb.append("<script language=\"javascript\" type=\"text/javascript\">\n"); |
| if (!partialRequest) |
| { |
| sb.append("//<![CDATA[\n"); |
| } |
| sb.append("function faceletsDebug(URL) { day = new Date(); id = day.getTime(); eval(\"page\" + id + \" " |
| + "= window.open(URL, '\" + id + \"', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0," |
| + "resizable=1,width=800,height=600,left = 240,top = 212');\"); };"); |
| sb.append("var faceletsOrigKeyup = document.onkeyup; document.onkeyup = function(e) { "); |
| sb.append("if (window.event) e = window.event; if (String.fromCharCode(e.keyCode) == '"); |
| sb.append(this.getHotkey()); |
| sb.append("' & e.shiftKey & e.ctrlKey) faceletsDebug('"); |
| sb.append(actionId); |
| |
| int index = actionId.indexOf('?'); |
| if (index != -1) |
| { |
| sb.append('&'); |
| } |
| else |
| { |
| sb.append('?'); |
| } |
| sb.append(KEY); |
| sb.append('='); |
| sb.append(writeDebugOutput(faces)); |
| sb.append("'); else if (faceletsOrigKeyup) faceletsOrigKeyup(e); };\n"); |
| if (!partialRequest) |
| { |
| sb.append("//]]>\n"); |
| } |
| sb.append("</script>\n"); |
| |
| ResponseWriter writer = faces.getResponseWriter(); |
| writer.write(sb.toString()); |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static String writeDebugOutput(FacesContext faces) throws IOException |
| { |
| FastWriter fw = new FastWriter(); |
| ErrorPageWriter.debugHtml(fw, faces); |
| |
| Map<String, Object> session = faces.getExternalContext().getSessionMap(); |
| Map<String, String> debugs = (Map<String, String>) session.get(KEY); |
| if (debugs == null) |
| { |
| debugs = new LinkedHashMap<String, String>() |
| { |
| @Override |
| protected boolean removeEldestEntry(Entry<String, String> eldest) |
| { |
| return this.size() > 5; |
| } |
| }; |
| |
| session.put(KEY, debugs); |
| } |
| |
| String id = String.valueOf(nextId++); |
| |
| debugs.put(id, fw.toString()); |
| |
| return id; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private static String fetchDebugOutput(FacesContext faces, String id) |
| { |
| Map<String, Object> session = faces.getExternalContext().getSessionMap(); |
| Map<String, String> debugs = (Map<String, String>) session.get(KEY); |
| if (debugs != null) |
| { |
| return debugs.get(id); |
| } |
| |
| return null; |
| } |
| |
| public static boolean debugRequest(FacesContext faces) |
| { |
| String id = (String) faces.getExternalContext().getRequestParameterMap().get(KEY); |
| if (id != null) |
| { |
| Object resp = faces.getExternalContext().getResponse(); |
| if (!faces.getResponseComplete() && resp instanceof HttpServletResponse) |
| { |
| try |
| { |
| HttpServletResponse httpResp = (HttpServletResponse) resp; |
| String page = fetchDebugOutput(faces, id); |
| if (page != null) |
| { |
| httpResp.setContentType("text/html"); |
| httpResp.getWriter().write(page); |
| } |
| else |
| { |
| httpResp.setContentType("text/plain"); |
| httpResp.getWriter().write("No Debug Output Available"); |
| } |
| httpResp.flushBuffer(); |
| faces.responseComplete(); |
| } |
| catch (IOException e) |
| { |
| return false; |
| } |
| |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| @JSFProperty(tagExcluded=true) |
| @Override |
| public String getId() |
| { |
| return super.getId(); |
| } |
| |
| /** |
| * The hot key to use in combination with 'CTRL' + 'SHIFT' to launch the debug window. |
| * By default, when the debug tag is used, you may launch the debug window with |
| * 'CTRL' + 'SHIFT' + 'D'. This value cannot be an EL expression. |
| * |
| * @return |
| */ |
| @JSFProperty |
| public String getHotkey() |
| { |
| return _hotkey; |
| } |
| |
| public void setHotkey(String hotkey) |
| { |
| _hotkey = (hotkey != null) ? hotkey.toUpperCase() : ""; |
| } |
| } |