protected AccessLogElement getXParameterElement(PatternTokenizer tokenizer) throws IOException {
   if (!tokenizer.hasSubToken()) {
     log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!");
     return null;
   }
   String token = tokenizer.getToken();
   if (!tokenizer.hasParameter()) {
     log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!");
     return null;
   }
   String parameter = tokenizer.getParameter();
   if (parameter == null) {
     log.error("No closing ) found for in decode");
     return null;
   }
   if ("A".equals(token)) {
     return new ServletContextElement(parameter);
   } else if ("C".equals(token)) {
     return new CookieElement(parameter);
   } else if ("R".equals(token)) {
     return new RequestAttributeElement(parameter);
   } else if ("S".equals(token)) {
     return new SessionAttributeElement(parameter);
   } else if ("H".equals(token)) {
     return getServletRequestElement(parameter);
   } else if ("P".equals(token)) {
     return new RequestParameterElement(parameter);
   } else if ("O".equals(token)) {
     return new ResponseAllHeaderElement(parameter);
   }
   log.error("x param for servlet request, couldn't decode value: " + token);
   return null;
 }
 protected AccessLogElement getLogElement(String token, PatternTokenizer tokenizer)
     throws IOException {
   if ("date".equals(token)) {
     return new DateElement();
   } else if ("time".equals(token)) {
     if (tokenizer.hasSubToken()) {
       String nextToken = tokenizer.getToken();
       if ("taken".equals(nextToken)) {
         return new ElapsedTimeElement(false);
       }
     } else {
       return new TimeElement();
     }
   } else if ("bytes".equals(token)) {
     return new ByteSentElement(true);
   } else if ("cached".equals(token)) {
     /* I don't know how to evaluate this! */
     return new StringElement("-");
   } else if ("c".equals(token)) {
     String nextToken = tokenizer.getToken();
     if ("ip".equals(nextToken)) {
       return new RemoteAddrElement();
     } else if ("dns".equals(nextToken)) {
       return new HostElement();
     }
   } else if ("s".equals(token)) {
     String nextToken = tokenizer.getToken();
     if ("ip".equals(nextToken)) {
       return new LocalAddrElement();
     } else if ("dns".equals(nextToken)) {
       return new AccessLogElement() {
         @Override
         public void addElement(
             StringBuilder buf, Date date, Request request, Response response, long time) {
           String value;
           try {
             value = InetAddress.getLocalHost().getHostName();
           } catch (Throwable e) {
             ExceptionUtils.handleThrowable(e);
             value = "localhost";
           }
           buf.append(value);
         }
       };
     }
   } else if ("cs".equals(token)) {
     return getClientToServerElement(tokenizer);
   } else if ("sc".equals(token)) {
     return getServerToClientElement(tokenizer);
   } else if ("sr".equals(token) || "rs".equals(token)) {
     return getProxyElement(tokenizer);
   } else if ("x".equals(token)) {
     return getXParameterElement(tokenizer);
   }
   log.error("unable to decode with rest of chars starting: " + token);
   return null;
 }
 protected AccessLogElement getProxyElement(PatternTokenizer tokenizer) throws IOException {
   String token = null;
   if (tokenizer.hasSubToken()) {
     tokenizer.getToken();
     return new StringElement("-");
   } else if (tokenizer.hasParameter()) {
     tokenizer.getParameter();
     return new StringElement("-");
   }
   log.error("The next characters couldn't be decoded: " + token);
   return null;
 }
 protected AccessLogElement getServerToClientElement(PatternTokenizer tokenizer)
     throws IOException {
   if (tokenizer.hasSubToken()) {
     String token = tokenizer.getToken();
     if ("status".equals(token)) {
       return new HttpStatusCodeElement();
     } else if ("comment".equals(token)) {
       return new StringElement("?");
     }
   } else if (tokenizer.hasParameter()) {
     String parameter = tokenizer.getParameter();
     if (parameter == null) {
       log.error("No closing ) found for in decode");
       return null;
     }
     return new ResponseHeaderElement(parameter);
   }
   log.error("The next characters couldn't be decoded: " + tokenizer.getRemains());
   return null;
 }
 protected AccessLogElement getClientToServerElement(PatternTokenizer tokenizer)
     throws IOException {
   if (tokenizer.hasSubToken()) {
     String token = tokenizer.getToken();
     if ("method".equals(token)) {
       return new MethodElement();
     } else if ("uri".equals(token)) {
       if (tokenizer.hasSubToken()) {
         token = tokenizer.getToken();
         if ("stem".equals(token)) {
           return new RequestURIElement();
         } else if ("query".equals(token)) {
           return new AccessLogElement() {
             @Override
             public void addElement(
                 StringBuilder buf, Date date, Request request, Response response, long time) {
               String query = request.getQueryString();
               if (query != null) {
                 buf.append(query);
               } else {
                 buf.append('-');
               }
             }
           };
         }
       } else {
         return new AccessLogElement() {
           @Override
           public void addElement(
               StringBuilder buf, Date date, Request request, Response response, long time) {
             String query = request.getQueryString();
             if (query == null) {
               buf.append(request.getRequestURI());
             } else {
               buf.append(request.getRequestURI());
               buf.append('?');
               buf.append(request.getQueryString());
             }
           }
         };
       }
     }
   } else if (tokenizer.hasParameter()) {
     String parameter = tokenizer.getParameter();
     if (parameter == null) {
       log.error("No closing ) found for in decode");
       return null;
     }
     return new RequestHeaderElement(parameter);
   }
   log.error("The next characters couldn't be decoded: " + tokenizer.getRemains());
   return null;
 }
  @Override
  protected AccessLogElement[] createLogElements() {
    if (log.isDebugEnabled()) {
      log.debug("decodePattern, pattern =" + pattern);
    }
    List<AccessLogElement> list = new ArrayList<AccessLogElement>();

    PatternTokenizer tokenizer = new PatternTokenizer(pattern);
    try {

      // Ignore leading whitespace.
      tokenizer.getWhiteSpaces();

      if (tokenizer.isEnded()) {
        log.info("pattern was just empty or whitespace");
        return null;
      }

      String token = tokenizer.getToken();
      while (token != null) {
        if (log.isDebugEnabled()) {
          log.debug("token = " + token);
        }
        AccessLogElement element = getLogElement(token, tokenizer);
        if (element == null) {
          break;
        }
        list.add(element);
        String whiteSpaces = tokenizer.getWhiteSpaces();
        if (whiteSpaces.length() > 0) {
          list.add(new StringElement(whiteSpaces));
        }
        if (tokenizer.isEnded()) {
          break;
        }
        token = tokenizer.getToken();
      }
      if (log.isDebugEnabled()) {
        log.debug("finished decoding with element size of: " + list.size());
      }
      return list.toArray(new AccessLogElement[0]);
    } catch (IOException e) {
      log.error("parse error", e);
      return null;
    }
  }