Save This Page
Home » struts-2.0.11.2-src » org.apache » struts2 » interceptor » debugging » [javadoc | source]
    1   /*
    2    * $Id: DebuggingInterceptor.java 483839 2006-12-08 05:52:10Z mrdon $
    3    *
    4    * Licensed to the Apache Software Foundation (ASF) under one
    5    * or more contributor license agreements.  See the NOTICE file
    6    * distributed with this work for additional information
    7    * regarding copyright ownership.  The ASF licenses this file
    8    * to you under the Apache License, Version 2.0 (the
    9    * "License"); you may not use this file except in compliance
   10    * with the License.  You may obtain a copy of the License at
   11    *
   12    *  http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing,
   15    * software distributed under the License is distributed on an
   16    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   17    * KIND, either express or implied.  See the License for the
   18    * specific language governing permissions and limitations
   19    * under the License.
   20    */
   21   package org.apache.struts2.interceptor.debugging;
   22   
   23   import java.beans.BeanInfo;
   24   import java.beans.Introspector;
   25   import java.beans.PropertyDescriptor;
   26   import java.io.IOException;
   27   import java.io.PrintWriter;
   28   import java.io.StringWriter;
   29   import java.lang.reflect.Array;
   30   import java.lang.reflect.Method;
   31   import java.util.ArrayList;
   32   import java.util.Arrays;
   33   import java.util.Collection;
   34   import java.util.HashSet;
   35   import java.util.List;
   36   import java.util.Map;
   37   
   38   import javax.servlet.http.HttpServletResponse;
   39   
   40   import org.apache.commons.logging.Log;
   41   import org.apache.commons.logging.LogFactory;
   42   import org.apache.struts2.ServletActionContext;
   43   import org.apache.struts2.views.freemarker.FreemarkerManager;
   44   import org.apache.struts2.views.freemarker.FreemarkerResult;
   45   import org.apache.struts2.StrutsConstants;
   46   
   47   import com.opensymphony.xwork2.ActionContext;
   48   import com.opensymphony.xwork2.ActionInvocation;
   49   import com.opensymphony.xwork2.inject.Inject;
   50   import com.opensymphony.xwork2.interceptor.Interceptor;
   51   import com.opensymphony.xwork2.interceptor.PreResultListener;
   52   import com.opensymphony.xwork2.util.ValueStack;
   53   
   54   /**
   55    * <!-- START SNIPPET: description -->
   56    * Provides several different debugging screens to provide insight into the
   57    * data behind the page.
   58    * <!-- END SNIPPET: description -->
   59    * The value of the 'debug' request parameter determines
   60    * the screen:
   61    * <!-- START SNIPPET: parameters -->
   62    * <ul>
   63    * <li> <code>xml</code> - Dumps the parameters, context, session, and value
   64    * stack as an XML document.</li>
   65    * <li> <code>console</code> - Shows a popup 'OGNL Console' that allows the
   66    * user to test OGNL expressions against the value stack. The XML data from
   67    * the 'xml' mode is inserted at the top of the page.</li>
   68    * <li> <code>command</code> - Tests an OGNL expression and returns the
   69    * string result. Only used by the OGNL console.</li>
   70    * </ul>
   71    * <!-- END SNIPPET: parameters -->
   72    * <p/>
   73    *  Example:
   74    * <!-- START SNIPPET: example -->
   75    *  http://localhost:8080/Welcome.action?debug=xml
   76    * <!-- END SNIPPET: example -->
   77    * <p/>
   78    * <!-- START SNIPPET: remarks -->
   79    * This interceptor only is activated when devMode is enabled in
   80    * struts.properties. The 'debug' parameter is removed from the parameter list
   81    * before the action is executed. All operations occur before the natural
   82    * Result has a chance to execute.
   83    * <!-- END SNIPPET: remarks -->
   84    */
   85   public class DebuggingInterceptor implements Interceptor {
   86   
   87       private static final long serialVersionUID = -3097324155953078783L;
   88   
   89       private final static Log log = LogFactory.getLog(DebuggingInterceptor.class);
   90   
   91       private String[] ignorePrefixes = new String[]{"org.apache.struts.",
   92               "com.opensymphony.xwork2.", "xwork."};
   93       private String[] _ignoreKeys = new String[]{"application", "session",
   94               "parameters", "request"};
   95       private HashSet<String> ignoreKeys = new HashSet<String>(Arrays.asList(_ignoreKeys));
   96   
   97       private final static String XML_MODE = "xml";
   98       private final static String CONSOLE_MODE = "console";
   99       private final static String COMMAND_MODE = "command";
  100   
  101       private final static String SESSION_KEY = "org.apache.struts2.interceptor.debugging.VALUE_STACK";
  102   
  103       private final static String DEBUG_PARAM = "debug";
  104       private final static String EXPRESSION_PARAM = "expression";
  105   
  106       private boolean enableXmlWithConsole = false;
  107       
  108       private boolean devMode;
  109       private FreemarkerManager freemarkerManager;
  110       
  111       private boolean consoleEnabled = false;
  112   
  113       @Inject(StrutsConstants.STRUTS_DEVMODE)
  114       public void setDevMode(String mode) {
  115           this.devMode = "true".equals(mode);
  116       }
  117       
  118       @Inject
  119       public void setFreemarkerManager(FreemarkerManager mgr) {
  120           this.freemarkerManager = mgr;
  121       }
  122   
  123       /**
  124        * Unused.
  125        */
  126       public void init() {
  127       }
  128   
  129   
  130       /**
  131        * Unused.
  132        */
  133       public void destroy() {
  134       }
  135   
  136   
  137       /*
  138        * (non-Javadoc)
  139        *
  140        * @see com.opensymphony.xwork2.interceptor.Interceptor#invoke(com.opensymphony.xwork2.ActionInvocation)
  141        */
  142       public String intercept(ActionInvocation inv) throws Exception {
  143   
  144           boolean cont = true;
  145           if (devMode) {
  146               final ActionContext ctx = ActionContext.getContext();
  147               String type = getParameter(DEBUG_PARAM);
  148               ctx.getParameters().remove(DEBUG_PARAM);
  149               if (XML_MODE.equals(type)) {
  150                   inv.addPreResultListener(
  151                           new PreResultListener() {
  152                               public void beforeResult(ActionInvocation inv, String result) {
  153                                   printContext();
  154                               }
  155                           });
  156               } else if (CONSOLE_MODE.equals(type)) {
  157                   consoleEnabled = true;
  158                   inv.addPreResultListener(
  159                           new PreResultListener() {
  160                               public void beforeResult(ActionInvocation inv, String actionResult) {
  161                                   String xml = "";
  162                                   if (enableXmlWithConsole) {
  163                                       StringWriter writer = new StringWriter();
  164                                       printContext(new PrettyPrintWriter(writer));
  165                                       xml = writer.toString();
  166                                       xml = xml.replaceAll("&", "&amp;");
  167                                       xml = xml.replaceAll(">", "&gt;");
  168                                       xml = xml.replaceAll("<", "&lt;");
  169                                   }
  170                                   ActionContext.getContext().put("debugXML", xml);
  171   
  172                                   FreemarkerResult result = new FreemarkerResult();
  173                                   result.setFreemarkerManager(freemarkerManager);
  174                                   result.setContentType("text/html");
  175                                   result.setLocation("/org/apache/struts2/interceptor/debugging/console.ftl");
  176                                   result.setParse(false);
  177                                   try {
  178                                       result.execute(inv);
  179                                   } catch (Exception ex) {
  180                                       log.error("Unable to create debugging console", ex);
  181                                   }
  182   
  183                               }
  184                           });
  185               } else if (COMMAND_MODE.equals(type)) {
  186                   ValueStack stack = (ValueStack) ctx.getSession().get(SESSION_KEY);
  187                   String cmd = getParameter(EXPRESSION_PARAM);
  188   
  189                   ServletActionContext.getRequest().setAttribute("decorator", "none");
  190                   HttpServletResponse res = ServletActionContext.getResponse();
  191                   res.setContentType("text/plain");
  192   
  193                   try {
  194                       PrintWriter writer =
  195                               ServletActionContext.getResponse().getWriter();
  196                       writer.print(stack.findValue(cmd));
  197                       writer.close();
  198                   } catch (IOException ex) {
  199                       ex.printStackTrace();
  200                   }
  201                   cont = false;
  202               }
  203           }
  204           if (cont) {
  205               try {
  206                   return inv.invoke();
  207               } finally {
  208                   if (devMode && consoleEnabled) {
  209                       final ActionContext ctx = ActionContext.getContext();
  210                       ctx.getSession().put(SESSION_KEY, ctx.get(ActionContext.VALUE_STACK));
  211                   }
  212               }
  213           } else {
  214               return null;
  215           }
  216       }
  217   
  218   
  219       /**
  220        * Gets a single string from the request parameters
  221        *
  222        * @param key The key
  223        * @return The parameter value
  224        */
  225       private String getParameter(String key) {
  226           String[] arr = (String[]) ActionContext.getContext().getParameters().get(key);
  227           if (arr != null && arr.length > 0) {
  228               return arr[0];
  229           }
  230           return null;
  231       }
  232   
  233   
  234       /**
  235        * Prints the current context to the response in XML format.
  236        */
  237       protected void printContext() {
  238           HttpServletResponse res = ServletActionContext.getResponse();
  239           res.setContentType("text/xml");
  240   
  241           try {
  242               PrettyPrintWriter writer = new PrettyPrintWriter(
  243                       ServletActionContext.getResponse().getWriter());
  244               printContext(writer);
  245               writer.close();
  246           } catch (IOException ex) {
  247               ex.printStackTrace();
  248           }
  249       }
  250   
  251   
  252       /**
  253        * Prints the current request to the existing writer.
  254        *
  255        * @param writer The XML writer
  256        */
  257       protected void printContext(PrettyPrintWriter writer) {
  258           ActionContext ctx = ActionContext.getContext();
  259           writer.startNode(DEBUG_PARAM);
  260           serializeIt(ctx.getParameters(), "parameters", writer,
  261                   new ArrayList<Object>());
  262           writer.startNode("context");
  263           String key;
  264           Map ctxMap = ctx.getContextMap();
  265           for (Object o : ctxMap.keySet()) {
  266               key = o.toString();
  267               boolean print = !ignoreKeys.contains(key);
  268   
  269               for (String ignorePrefixe : ignorePrefixes) {
  270                   if (key.startsWith(ignorePrefixe)) {
  271                       print = false;
  272                       break;
  273                   }
  274               }
  275               if (print) {
  276                   serializeIt(ctxMap.get(key), key, writer, new ArrayList<Object>());
  277               }
  278           }
  279           writer.endNode();
  280           serializeIt(ctx.getSession(), "request", writer, new ArrayList<Object>());
  281           serializeIt(ctx.getSession(), "session", writer, new ArrayList<Object>());
  282   
  283           ValueStack stack = (ValueStack) ctx.get(ActionContext.VALUE_STACK);
  284           serializeIt(stack.getRoot(), "valueStack", writer, new ArrayList<Object>());
  285           writer.endNode();
  286       }
  287   
  288   
  289       /**
  290        * Recursive function to serialize objects to XML. Currently it will
  291        * serialize Collections, maps, Arrays, and JavaBeans. It maintains a stack
  292        * of objects serialized already in the current functioncall. This is used
  293        * to avoid looping (stack overflow) of circular linked objects. Struts and
  294        * XWork objects are ignored.
  295        *
  296        * @param bean   The object you want serialized.
  297        * @param name   The name of the object, used for element &lt;name/&gt;
  298        * @param writer The XML writer
  299        * @param stack  List of objects we're serializing since the first calling
  300        *               of this function (to prevent looping on circular references).
  301        */
  302       protected void serializeIt(Object bean, String name,
  303                                  PrettyPrintWriter writer, List<Object> stack) {
  304           writer.flush();
  305           // Check stack for this object
  306           if ((bean != null) && (stack.contains(bean))) {
  307               if (log.isInfoEnabled()) {
  308                   log.info("Circular reference detected, not serializing object: "
  309                           + name);
  310               }
  311               return;
  312           } else if (bean != null) {
  313               // Push object onto stack.
  314               // Don't push null objects ( handled below)
  315               stack.add(bean);
  316           }
  317           if (bean == null) {
  318               return;
  319           }
  320           String clsName = bean.getClass().getName();
  321   
  322           writer.startNode(name);
  323   
  324           // It depends on the object and it's value what todo next:
  325           if (bean instanceof Collection) {
  326               Collection col = (Collection) bean;
  327   
  328               // Iterate through components, and call ourselves to process
  329               // elements
  330               for (Object aCol : col) {
  331                   serializeIt(aCol, "value", writer, stack);
  332               }
  333           } else if (bean instanceof Map) {
  334   
  335               Map map = (Map) bean;
  336   
  337               // Loop through keys and call ourselves
  338               for (Object key : map.keySet()) {
  339                   Object Objvalue = map.get(key);
  340                   serializeIt(Objvalue, key.toString(), writer, stack);
  341               }
  342           } else if (bean.getClass().isArray()) {
  343               // It's an array, loop through it and keep calling ourselves
  344               for (int i = 0; i < Array.getLength(bean); i++) {
  345                   serializeIt(Array.get(bean, i), "arrayitem", writer, stack);
  346               }
  347           } else {
  348               if (clsName.startsWith("java.lang")) {
  349                   writer.setValue(bean.toString());
  350               } else {
  351                   // Not java.lang, so we can call ourselves with this object's
  352                   // values
  353                   try {
  354                       BeanInfo info = Introspector.getBeanInfo(bean.getClass());
  355                       PropertyDescriptor[] props = info.getPropertyDescriptors();
  356   
  357                       for (PropertyDescriptor prop : props) {
  358                           String n = prop.getName();
  359                           Method m = prop.getReadMethod();
  360   
  361                           // Call ourselves with the result of the method
  362                           // invocation
  363                           if (m != null) {
  364                               serializeIt(m.invoke(bean), n, writer, stack);
  365                           }
  366                       }
  367                   } catch (Exception e) {
  368                       log.error(e, e);
  369                   }
  370               }
  371           }
  372   
  373           writer.endNode();
  374   
  375           // Remove object from stack
  376           stack.remove(bean);
  377       }
  378   
  379   
  380       /**
  381        * @param enableXmlWithConsole the enableXmlWithConsole to set
  382        */
  383       public void setEnableXmlWithConsole(boolean enableXmlWithConsole) {
  384           this.enableXmlWithConsole = enableXmlWithConsole;
  385       }
  386   
  387   
  388   
  389   }
  390   

Save This Page
Home » struts-2.0.11.2-src » org.apache » struts2 » interceptor » debugging » [javadoc | source]