Source Code Cross Referenced for ExtendedAccessLogValve.java in  » Sevlet-Container » tomcat-catalina » org » apache » catalina » valves » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Sevlet Container » tomcat catalina » org.apache.catalina.valves 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 1999-2001,2004 The Apache Software Foundation.
0003:         * 
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         * 
0008:         *      http://www.apache.org/licenses/LICENSE-2.0
0009:         * 
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:
0017:        package org.apache.catalina.valves;
0018:
0019:        import java.io.File;
0020:        import java.io.FileWriter;
0021:        import java.io.IOException;
0022:        import java.io.PrintWriter;
0023:        import java.net.InetAddress;
0024:        import java.net.URLEncoder;
0025:        import java.text.DecimalFormat;
0026:        import java.text.SimpleDateFormat;
0027:        import java.util.Date;
0028:        import java.util.Iterator;
0029:        import java.util.LinkedList;
0030:        import java.util.TimeZone;
0031:
0032:        import javax.servlet.ServletException;
0033:        import javax.servlet.ServletRequest;
0034:        import javax.servlet.http.Cookie;
0035:        import javax.servlet.http.HttpServletRequest;
0036:        import javax.servlet.http.HttpSession;
0037:
0038:        import org.apache.catalina.HttpResponse;
0039:        import org.apache.catalina.Lifecycle;
0040:        import org.apache.catalina.LifecycleException;
0041:        import org.apache.catalina.LifecycleListener;
0042:        import org.apache.catalina.Request;
0043:        import org.apache.catalina.Response;
0044:        import org.apache.catalina.ValveContext;
0045:        import org.apache.catalina.util.LifecycleSupport;
0046:        import org.apache.catalina.util.ServerInfo;
0047:        import org.apache.catalina.util.StringManager;
0048:        import org.apache.commons.logging.Log;
0049:        import org.apache.commons.logging.LogFactory;
0050:
0051:        /**
0052:         * An implementation of the W3c Extended Log File Format. See
0053:         * http://www.w3.org/TR/WD-logfile.html for more information about the format.
0054:         *
0055:         * The following fields are supported:
0056:         * <ul>
0057:         * <li><code>c-dns</code>:  Client hostname</li>
0058:         * <li><code>c-ip</code>:  Client ip address</li>
0059:         * <li><code>bytes</code>:  bytes served</li>
0060:         * <li><code>cs-method</code>:  request method</li>
0061:         * <li><code>cs-uri</code>:  The full uri requested</li>
0062:         * <li><code>cs-uri-query</code>:  The query string</li>
0063:         * <li><code>cs-uri-stem</code>:  The uri without query string</li>
0064:         * <li><code>date</code>:  The date in yyyy-mm-dd  format for GMT</li>
0065:         * <li><code>s-dns</code>: The server dns entry </li>
0066:         * <li><code>s-ip</code>:  The server ip address</li>
0067:         * <li><code>cs(XXX)</code>:  The value of header XXX from client to server</li>
0068:         * <li><code>sc(XXX)</code>: The value of header XXX from server to client </li>
0069:         * <li><code>sc-status</code>:  The status code</li>
0070:         * <li><code>time</code>:  Time the request was served</li>
0071:         * <li><code>time-taken</code>:  Time (in seconds) taken to serve the request</li>
0072:         * <li><code>x-A(XXX)</code>: Pull XXX attribute from the servlet context </li>
0073:         * <li><code>x-C(XXX)</code>: Pull the first cookie of the name XXX </li>
0074:         * <li><code>x-R(XXX)</code>: Pull XXX attribute from the servlet request </li>
0075:         * <li><code>x-S(XXX)</code>: Pull XXX attribute from the session </li>
0076:         * <li><code>x-P(...)</code>:  Call request.getParameter(...)
0077:         *                             and URLencode it. Helpful to capture
0078:         *                             certain POST parameters.
0079:         * </li>
0080:         * <li>For any of the x-H(...) the following method will be called from the
0081:         *                HttpServletRequestObject </li>
0082:         * <li><code>x-H(authType)</code>: getAuthType </li>
0083:         * <li><code>x-H(characterEncoding)</code>: getCharacterEncoding </li>
0084:         * <li><code>x-H(contentLength)</code>: getContentLength </li>
0085:         * <li><code>x-H(locale)</code>:  getLocale</li>
0086:         * <li><code>x-H(protocol)</code>: getProtocol </li>
0087:         * <li><code>x-H(remoteUser)</code>:  getRemoteUser</li>
0088:         * <li><code>x-H(requestedSessionId)</code>: getGequestedSessionId</li>
0089:         * <li><code>x-H(requestedSessionIdFromCookie)</code>:
0090:         *                  isRequestedSessionIdFromCookie </li>
0091:         * <li><code>x-H(requestedSessionIdValid)</code>:
0092:         *                  isRequestedSessionIdValid</li>
0093:         * <li><code>x-H(scheme)</code>:  getScheme</li>
0094:         * <li><code>x-H(secure)</code>:  isSecure</li>
0095:         * </ul>
0096:         *
0097:         *
0098:         *
0099:         * <p>
0100:         * Log rotation can be on or off. This is dictated by the rotatable
0101:         * property.
0102:         * </p>
0103:         *
0104:         * <p>
0105:         * For UNIX users, another field called <code>checkExists</code>is also
0106:         * available. If set to true, the log file's existence will be checked before
0107:         * each logging. This way an external log rotator can move the file
0108:         * somewhere and tomcat will start with a new file.
0109:         * </p>
0110:         *
0111:         * <p>
0112:         * For JMX junkies, a public method called </code>rotate</code> has
0113:         * been made available to allow you to tell this instance to move
0114:         * the existing log file to somewhere else start writing a new log file.
0115:         * </p>
0116:         *
0117:         * <p>
0118:         * Conditional logging is also supported. This can be done with the
0119:         * <code>condition</code> property.
0120:         * If the value returned from ServletRequest.getAttribute(condition)
0121:         * yields a non-null value. The logging will be skipped.
0122:         * </p>
0123:         *
0124:         * <p>
0125:         * For extended attributes coming from a getAttribute() call,
0126:         * it is you responsibility to ensure there are no newline or
0127:         * control characters.
0128:         * </p>
0129:         *
0130:         *
0131:         * @author Tim Funk
0132:         * @version $Revision: 1.8.2.1 $ $Date: 2004/08/21 15:49:56 $
0133:         */
0134:
0135:        public final class ExtendedAccessLogValve extends ValveBase implements 
0136:                Lifecycle {
0137:
0138:            // ----------------------------------------------------------- Constructors
0139:
0140:            /**
0141:             * Construct a new instance of this class with default property values.
0142:             */
0143:            public ExtendedAccessLogValve() {
0144:
0145:                super ();
0146:
0147:            }
0148:
0149:            // ----------------------------------------------------- Instance Variables
0150:            private static Log log = LogFactory
0151:                    .getLog(ExtendedAccessLogValve.class);
0152:
0153:            /**
0154:             * The descriptive information about this implementation.
0155:             */
0156:            protected static final String info = "org.apache.catalina.valves.ExtendedAccessLogValve/1.0";
0157:
0158:            /**
0159:             * The lifecycle event support for this component.
0160:             */
0161:            protected LifecycleSupport lifecycle = new LifecycleSupport(this );
0162:
0163:            /**
0164:             * The string manager for this package.
0165:             */
0166:            private StringManager sm = StringManager
0167:                    .getManager(Constants.Package);
0168:
0169:            /**
0170:             * Has this component been started yet?
0171:             */
0172:            private boolean started = false;
0173:
0174:            /**
0175:             * The as-of date for the currently open log file, or a zero-length
0176:             * string if there is no open log file.
0177:             */
0178:            private String dateStamp = "";
0179:
0180:            /**
0181:             * The PrintWriter to which we are currently logging, if any.
0182:             */
0183:            private PrintWriter writer = null;
0184:
0185:            /**
0186:             * The formatter for the date contained in the file name.
0187:             */
0188:            private SimpleDateFormat fileDateFormatter = null;
0189:
0190:            /**
0191:             * A date formatter to format a Date into a date in the format
0192:             * "yyyy-MM-dd".
0193:             */
0194:            private SimpleDateFormat dateFormatter = null;
0195:
0196:            /**
0197:             * A date formatter to format a Date into a time in the format
0198:             * "kk:mm:ss" (kk is a 24-hour representation of the hour).
0199:             */
0200:            private SimpleDateFormat timeFormatter = null;
0201:
0202:            /**
0203:             * Time taken formatter for 3 decimal places.
0204:             */
0205:            private DecimalFormat timeTakenFormatter = null;
0206:
0207:            /**
0208:             * My ip address. Look it up once and remember it. Dump this if we can
0209:             * determine another reliable way to get server ip address since this
0210:             * server may have many ip's.
0211:             */
0212:            private String myIpAddress = null;
0213:
0214:            /**
0215:             * My dns name. Look it up once and remember it. Dump this if we can
0216:             * determine another reliable way to get server name address since this
0217:             * server may have many ip's.
0218:             */
0219:            private String myDNSName = null;
0220:
0221:            /**
0222:             * Holder for all of the fields to log after the pattern is decoded.
0223:             */
0224:            private FieldInfo[] fieldInfos;
0225:
0226:            /**
0227:             * The current log file we are writing to. Helpful when checkExists
0228:             * is true.
0229:             */
0230:            private File currentLogFile = null;
0231:
0232:            /**
0233:             * The system time when we last updated the Date that this valve
0234:             * uses for log lines.
0235:             */
0236:            private Date currentDate = null;
0237:
0238:            /**
0239:             * Instant when the log daily rotation was last checked.
0240:             */
0241:            private long rotationLastChecked = 0L;
0242:
0243:            /**
0244:             * The directory in which log files are created.
0245:             */
0246:            private String directory = "logs";
0247:
0248:            /**
0249:             * The pattern used to format our access log lines.
0250:             */
0251:            private String pattern = null;
0252:
0253:            /**
0254:             * The prefix that is added to log file filenames.
0255:             */
0256:            private String prefix = "access_log.";
0257:
0258:            /**
0259:             * Should we rotate our log file? Default is true (like old behavior)
0260:             */
0261:            private boolean rotatable = true;
0262:
0263:            /**
0264:             * The suffix that is added to log file filenames.
0265:             */
0266:            private String suffix = "";
0267:
0268:            /**
0269:             * Are we doing conditional logging. default false.
0270:             */
0271:            private String condition = null;
0272:
0273:            /**
0274:             * Do we check for log file existence? Helpful if an external
0275:             * agent renames the log file so we can automagically recreate it.
0276:             */
0277:            private boolean checkExists = false;
0278:
0279:            /**
0280:             * Date format to place in log file name. Use at your own risk!
0281:             */
0282:            private String fileDateFormat = null;
0283:
0284:            // ------------------------------------------------------------- Properties
0285:
0286:            /**
0287:             * Return the directory in which we create log files.
0288:             */
0289:            public String getDirectory() {
0290:
0291:                return (directory);
0292:
0293:            }
0294:
0295:            /**
0296:             * Set the directory in which we create log files.
0297:             *
0298:             * @param directory The new log file directory
0299:             */
0300:            public void setDirectory(String directory) {
0301:
0302:                this .directory = directory;
0303:
0304:            }
0305:
0306:            /**
0307:             * Return descriptive information about this implementation.
0308:             */
0309:            public String getInfo() {
0310:
0311:                return (info);
0312:
0313:            }
0314:
0315:            /**
0316:             * Return the format pattern.
0317:             */
0318:            public String getPattern() {
0319:
0320:                return (this .pattern);
0321:
0322:            }
0323:
0324:            /**
0325:             * Set the format pattern, first translating any recognized alias.
0326:             *
0327:             * @param pattern The new pattern pattern
0328:             */
0329:            public void setPattern(String pattern) {
0330:
0331:                FieldInfo[] f = decodePattern(pattern);
0332:                if (f != null) {
0333:                    this .pattern = pattern;
0334:                    this .fieldInfos = f;
0335:                }
0336:            }
0337:
0338:            /**
0339:             * Return the log file prefix.
0340:             */
0341:            public String getPrefix() {
0342:
0343:                return (prefix);
0344:
0345:            }
0346:
0347:            /**
0348:             * Set the log file prefix.
0349:             *
0350:             * @param prefix The new log file prefix
0351:             */
0352:            public void setPrefix(String prefix) {
0353:
0354:                this .prefix = prefix;
0355:
0356:            }
0357:
0358:            /**
0359:             * Return true if logs are automatically rotated.
0360:             */
0361:            public boolean isRotatable() {
0362:
0363:                return rotatable;
0364:
0365:            }
0366:
0367:            /**
0368:             * Set the value is we should we rotate the logs
0369:             *
0370:             * @param rotatable true is we should rotate.
0371:             */
0372:            public void setRotatable(boolean rotatable) {
0373:
0374:                this .rotatable = rotatable;
0375:
0376:            }
0377:
0378:            /**
0379:             * Return the log file suffix.
0380:             */
0381:            public String getSuffix() {
0382:
0383:                return (suffix);
0384:
0385:            }
0386:
0387:            /**
0388:             * Set the log file suffix.
0389:             *
0390:             * @param suffix The new log file suffix
0391:             */
0392:            public void setSuffix(String suffix) {
0393:
0394:                this .suffix = suffix;
0395:
0396:            }
0397:
0398:            /**
0399:             * Return whether the attribute name to look for when
0400:             * performing conditional loggging. If null, every
0401:             * request is logged.
0402:             */
0403:            public String getCondition() {
0404:
0405:                return condition;
0406:
0407:            }
0408:
0409:            /**
0410:             * Set the ServletRequest.attribute to look for to perform
0411:             * conditional logging. Set to null to log everything.
0412:             *
0413:             * @param condition Set to null to log everything
0414:             */
0415:            public void setCondition(String condition) {
0416:
0417:                this .condition = condition;
0418:
0419:            }
0420:
0421:            /**
0422:             * Check for file existence before logging.
0423:             */
0424:            public boolean isCheckExists() {
0425:
0426:                return checkExists;
0427:
0428:            }
0429:
0430:            /**
0431:             * Set whether to check for log file existence before logging.
0432:             *
0433:             * @param checkExists true meaning to check for file existence.
0434:             */
0435:            public void setCheckExists(boolean checkExists) {
0436:
0437:                this .checkExists = checkExists;
0438:
0439:            }
0440:
0441:            /**
0442:             *  Return the date format date based log rotation.
0443:             */
0444:            public String getFileDateFormat() {
0445:                return fileDateFormat;
0446:            }
0447:
0448:            /**
0449:             *  Set the date format date based log rotation.
0450:             */
0451:            public void setFileDateFormat(String fileDateFormat) {
0452:                this .fileDateFormat = fileDateFormat;
0453:            }
0454:
0455:            // --------------------------------------------------------- Public Methods
0456:
0457:            /**
0458:             * Log a message summarizing the specified request and response, according
0459:             * to the format specified by the <code>pattern</code> property.
0460:             *
0461:             * @param request Request being processed
0462:             * @param response Response being processed
0463:             * @param context The valve context used to invoke the next valve
0464:             *  in the current processing pipeline
0465:             *
0466:             * @exception IOException if an input/output error has occurred
0467:             * @exception ServletException if a servlet error has occurred
0468:             */
0469:            public void invoke(Request request, Response response,
0470:                    ValveContext context) throws IOException, ServletException {
0471:
0472:                // Pass this request on to the next valve in our pipeline
0473:                long endTime;
0474:                long runTime;
0475:                long startTime = System.currentTimeMillis();
0476:
0477:                context.invokeNext(request, response);
0478:
0479:                endTime = System.currentTimeMillis();
0480:                runTime = endTime - startTime;
0481:
0482:                if (fieldInfos == null || condition != null
0483:                        && null != request.getRequest().getAttribute(condition)) {
0484:                    return;
0485:                }
0486:
0487:                Date date = getDate(endTime);
0488:                StringBuffer result = new StringBuffer();
0489:
0490:                for (int i = 0; fieldInfos != null && i < fieldInfos.length; i++) {
0491:                    switch (fieldInfos[i].type) {
0492:                    case FieldInfo.DATA_CLIENT:
0493:                        if (FieldInfo.FIELD_IP == fieldInfos[i].location)
0494:                            result.append(request.getRequest().getRemoteAddr());
0495:                        else if (FieldInfo.FIELD_DNS == fieldInfos[i].location)
0496:                            result.append(request.getRequest().getRemoteHost());
0497:                        else
0498:                            result.append("?WTF?"); /* This should never happen! */
0499:                        break;
0500:                    case FieldInfo.DATA_SERVER:
0501:                        if (FieldInfo.FIELD_IP == fieldInfos[i].location)
0502:                            result.append(myIpAddress);
0503:                        else if (FieldInfo.FIELD_DNS == fieldInfos[i].location)
0504:                            result.append(myDNSName);
0505:                        else
0506:                            result.append("?WTF?"); /* This should never happen! */
0507:                        break;
0508:                    case FieldInfo.DATA_REMOTE:
0509:                        result.append('?'); /* I don't know how to handle these! */
0510:                        break;
0511:                    case FieldInfo.DATA_CLIENT_TO_SERVER:
0512:                        result
0513:                                .append(getClientToServer(fieldInfos[i],
0514:                                        request));
0515:                        break;
0516:                    case FieldInfo.DATA_SERVER_TO_CLIENT:
0517:                        result
0518:                                .append(getServerToClient(fieldInfos[i],
0519:                                        response));
0520:                        break;
0521:                    case FieldInfo.DATA_SERVER_TO_RSERVER:
0522:                        result.append('-');
0523:                        break;
0524:                    case FieldInfo.DATA_RSERVER_TO_SERVER:
0525:                        result.append('-');
0526:                        break;
0527:                    case FieldInfo.DATA_APP_SPECIFIC:
0528:                        result.append(getAppSpecific(fieldInfos[i], request));
0529:                        break;
0530:                    case FieldInfo.DATA_SPECIAL:
0531:                        if (FieldInfo.SPECIAL_DATE == fieldInfos[i].location)
0532:                            result.append(dateFormatter.format(date));
0533:                        else if (FieldInfo.SPECIAL_TIME_TAKEN == fieldInfos[i].location)
0534:                            result.append(timeTakenFormatter
0535:                                    .format(runTime / 1000d));
0536:                        else if (FieldInfo.SPECIAL_TIME == fieldInfos[i].location)
0537:                            result.append(timeFormatter.format(date));
0538:                        else if (FieldInfo.SPECIAL_BYTES == fieldInfos[i].location) {
0539:                            int length = response.getContentCount();
0540:                            if (length > 0)
0541:                                result.append(length);
0542:                            else
0543:                                result.append("-");
0544:                        } else if (FieldInfo.SPECIAL_CACHED == fieldInfos[i].location)
0545:                            result.append('-'); /* I don't know how to evaluate this! */
0546:                        else
0547:                            result.append("?WTF?"); /* This should never happen! */
0548:                        break;
0549:                    default:
0550:                        result.append("?WTF?"); /* This should never happen! */
0551:                    }
0552:
0553:                    if (fieldInfos[i].postWhiteSpace != null) {
0554:                        result.append(fieldInfos[i].postWhiteSpace);
0555:                    }
0556:                }
0557:                log(result.toString(), date);
0558:
0559:            }
0560:
0561:            /**
0562:             * Rename the existing log file to something else. Then open the
0563:             * old log file name up once again. Intended to be called by a JMX
0564:             * agent.
0565:             *
0566:             *
0567:             * @param newFileName The file name to move the log file entry to
0568:             * @return true if a file was rotated with no error
0569:             */
0570:            public synchronized boolean rotate(String newFileName) {
0571:
0572:                if (currentLogFile != null) {
0573:                    File holder = currentLogFile;
0574:                    close();
0575:                    try {
0576:                        holder.renameTo(new File(newFileName));
0577:                    } catch (Throwable e) {
0578:                        log.error("rotate failed", e);
0579:                    }
0580:
0581:                    /* Make sure date is correct */
0582:                    currentDate = new Date(System.currentTimeMillis());
0583:                    dateStamp = fileDateFormatter.format(currentDate);
0584:
0585:                    open();
0586:                    return true;
0587:                } else {
0588:                    return false;
0589:                }
0590:
0591:            }
0592:
0593:            // -------------------------------------------------------- Private Methods
0594:
0595:            /**
0596:             *  Return the client to server data.
0597:             *  @param fieldInfo The field to decode.
0598:             *  @param request The object we pull data from.
0599:             *  @return The appropriate value.
0600:             */
0601:            private String getClientToServer(FieldInfo fieldInfo,
0602:                    Request request) {
0603:
0604:                ServletRequest sr = request.getRequest();
0605:                HttpServletRequest hsr = null;
0606:                if (sr instanceof  HttpServletRequest)
0607:                    hsr = (HttpServletRequest) sr;
0608:
0609:                switch (fieldInfo.location) {
0610:                case FieldInfo.FIELD_METHOD:
0611:                    return hsr.getMethod();
0612:                case FieldInfo.FIELD_URI:
0613:                    if (null == hsr.getQueryString())
0614:                        return hsr.getRequestURI();
0615:                    else
0616:                        return hsr.getRequestURI() + "?" + hsr.getQueryString();
0617:                case FieldInfo.FIELD_URI_STEM:
0618:                    return hsr.getRequestURI();
0619:                case FieldInfo.FIELD_URI_QUERY:
0620:                    if (null == hsr.getQueryString())
0621:                        return "-";
0622:                    return hsr.getQueryString();
0623:                case FieldInfo.FIELD_HEADER:
0624:                    return wrap(hsr.getHeader(fieldInfo.value));
0625:                default:
0626:                    ;
0627:                }
0628:
0629:                return "-";
0630:
0631:            }
0632:
0633:            /**
0634:             *  Return the server to client data.
0635:             *  @param fieldInfo The field to decode.
0636:             *  @param response The object we pull data from.
0637:             *  @return The appropriate value.
0638:             */
0639:            private String getServerToClient(FieldInfo fieldInfo,
0640:                    Response response) {
0641:                HttpResponse r = (HttpResponse) response;
0642:                switch (fieldInfo.location) {
0643:                case FieldInfo.FIELD_STATUS:
0644:                    return "" + r.getStatus();
0645:                case FieldInfo.FIELD_COMMENT:
0646:                    return "?"; /* Not coded yet*/
0647:                case FieldInfo.FIELD_HEADER:
0648:                    return wrap(r.getHeader(fieldInfo.value));
0649:                default:
0650:                    ;
0651:                }
0652:
0653:                return "-";
0654:
0655:            }
0656:
0657:            /**
0658:             * Get app specific data.
0659:             * @param fieldInfo The field to decode
0660:             * @param request Where we will pull the data from.
0661:             * @return The appropriate value
0662:             */
0663:            private String getAppSpecific(FieldInfo fieldInfo, Request request) {
0664:
0665:                ServletRequest sr = request.getRequest();
0666:                HttpServletRequest hsr = null;
0667:                if (sr instanceof  HttpServletRequest)
0668:                    hsr = (HttpServletRequest) sr;
0669:
0670:                switch (fieldInfo.xType) {
0671:                case FieldInfo.X_PARAMETER:
0672:                    return wrap(urlEncode(sr.getParameter(fieldInfo.value)));
0673:                case FieldInfo.X_REQUEST:
0674:                    return wrap(sr.getAttribute(fieldInfo.value));
0675:                case FieldInfo.X_SESSION:
0676:                    HttpSession session = null;
0677:                    if (hsr != null) {
0678:                        session = hsr.getSession(false);
0679:                        if (session != null)
0680:                            return wrap(session.getAttribute(fieldInfo.value));
0681:                    }
0682:                    break;
0683:                case FieldInfo.X_COOKIE:
0684:                    Cookie[] c = hsr.getCookies();
0685:                    for (int i = 0; c != null && i < c.length; i++) {
0686:                        if (fieldInfo.value.equals(c[i].getName())) {
0687:                            return wrap(c[i].getValue());
0688:                        }
0689:                    }
0690:                case FieldInfo.X_APP:
0691:                    return wrap(request.getContext().getServletContext()
0692:                            .getAttribute(fieldInfo.value));
0693:                case FieldInfo.X_SERVLET_REQUEST:
0694:                    if (fieldInfo.location == FieldInfo.X_LOC_AUTHTYPE) {
0695:                        return wrap(hsr.getAuthType());
0696:                    } else if (fieldInfo.location == FieldInfo.X_LOC_REMOTEUSER) {
0697:                        return wrap(hsr.getRemoteUser());
0698:                    } else if (fieldInfo.location == FieldInfo.X_LOC_REQUESTEDSESSIONID) {
0699:                        return wrap(hsr.getRequestedSessionId());
0700:                    } else if (fieldInfo.location == FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE) {
0701:                        return wrap("" + hsr.isRequestedSessionIdFromCookie());
0702:                    } else if (fieldInfo.location == FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID) {
0703:                        return wrap("" + hsr.isRequestedSessionIdValid());
0704:                    } else if (fieldInfo.location == FieldInfo.X_LOC_CONTENTLENGTH) {
0705:                        return wrap("" + hsr.getContentLength());
0706:                    } else if (fieldInfo.location == FieldInfo.X_LOC_CHARACTERENCODING) {
0707:                        return wrap(hsr.getCharacterEncoding());
0708:                    } else if (fieldInfo.location == FieldInfo.X_LOC_LOCALE) {
0709:                        return wrap(hsr.getLocale());
0710:                    } else if (fieldInfo.location == FieldInfo.X_LOC_PROTOCOL) {
0711:                        return wrap(hsr.getProtocol());
0712:                    } else if (fieldInfo.location == FieldInfo.X_LOC_SCHEME) {
0713:                        return wrap(hsr.getScheme());
0714:                    } else if (fieldInfo.location == FieldInfo.X_LOC_SECURE) {
0715:                        return wrap("" + hsr.isSecure());
0716:                    }
0717:                    break;
0718:                default:
0719:                    ;
0720:                }
0721:
0722:                return "-";
0723:
0724:            }
0725:
0726:            /**
0727:             *  urlEncode the given string. If null or empty, return null.
0728:             */
0729:            private String urlEncode(String value) {
0730:                if (null == value || value.length() == 0) {
0731:                    return null;
0732:                }
0733:                return URLEncoder.encode(value);
0734:            }
0735:
0736:            /**
0737:             *  Wrap the incoming value into quotes and escape any inner
0738:             *  quotes with double quotes.
0739:             *
0740:             *  @param value - The value to wrap quotes around
0741:             *  @return '-' if empty of null. Otherwise, toString() will
0742:             *     be called on the object and the value will be wrapped
0743:             *     in quotes and any quotes will be escaped with 2
0744:             *     sets of quotes.
0745:             */
0746:            private String wrap(Object value) {
0747:
0748:                String svalue;
0749:                // Does the value contain a " ? If so must encode it
0750:                if (value == null || "-".equals(value))
0751:                    return "-";
0752:
0753:                try {
0754:                    svalue = value.toString();
0755:                    if ("".equals(svalue))
0756:                        return "-";
0757:                } catch (Throwable e) {
0758:                    /* Log error */
0759:                    return "-";
0760:                }
0761:
0762:                /* Wrap all quotes in double quotes. */
0763:                StringBuffer buffer = new StringBuffer(svalue.length() + 2);
0764:                buffer.append('"');
0765:                int i = 0;
0766:                while (i < svalue.length()) {
0767:                    int j = svalue.indexOf('"', i);
0768:                    if (j == -1) {
0769:                        buffer.append(svalue.substring(i));
0770:                        i = svalue.length();
0771:                    } else {
0772:                        buffer.append(svalue.substring(i, j + 1));
0773:                        buffer.append('"');
0774:                        i = j + 2;
0775:                    }
0776:                }
0777:
0778:                buffer.append('"');
0779:                return buffer.toString();
0780:
0781:            }
0782:
0783:            /**
0784:             * Close the currently open log file (if any)
0785:             */
0786:            private synchronized void close() {
0787:
0788:                if (writer == null)
0789:                    return;
0790:                writer.flush();
0791:                writer.close();
0792:                writer = null;
0793:                currentLogFile = null;
0794:
0795:            }
0796:
0797:            /**
0798:             * Log the specified message to the log file, switching files if the date
0799:             * has changed since the previous log call.
0800:             *
0801:             * @param message Message to be logged
0802:             * @param date the current Date object (so this method doesn't need to
0803:             *        create a new one)
0804:             */
0805:            private void log(String message, Date date) {
0806:
0807:                if (rotatable) {
0808:                    // Only do a logfile switch check once a second, max.
0809:                    long systime = System.currentTimeMillis();
0810:                    if ((systime - rotationLastChecked) > 1000) {
0811:
0812:                        // We need a new currentDate
0813:                        currentDate = new Date(systime);
0814:                        rotationLastChecked = systime;
0815:
0816:                        // Check for a change of date
0817:                        String tsDate = fileDateFormatter.format(currentDate);
0818:
0819:                        // If the date has changed, switch log files
0820:                        if (!dateStamp.equals(tsDate)) {
0821:                            synchronized (this ) {
0822:                                if (!dateStamp.equals(tsDate)) {
0823:                                    close();
0824:                                    dateStamp = tsDate;
0825:                                    open();
0826:                                }
0827:                            }
0828:                        }
0829:                    }
0830:                }
0831:
0832:                /* In case something external rotated the file instead */
0833:                if (checkExists) {
0834:                    synchronized (this ) {
0835:                        if (currentLogFile != null && !currentLogFile.exists()) {
0836:                            try {
0837:                                close();
0838:                            } catch (Throwable e) {
0839:                                log.info("at least this wasn't swallowed", e);
0840:                            }
0841:
0842:                            /* Make sure date is correct */
0843:                            currentDate = new Date(System.currentTimeMillis());
0844:                            dateStamp = fileDateFormatter.format(currentDate);
0845:
0846:                            open();
0847:                        }
0848:                    }
0849:                }
0850:
0851:                // Log this message
0852:                if (writer != null) {
0853:                    writer.println(message);
0854:                }
0855:
0856:            }
0857:
0858:            /**
0859:             * Open the new log file for the date specified by <code>dateStamp</code>.
0860:             */
0861:            private synchronized void open() {
0862:
0863:                // Create the directory if necessary
0864:                File dir = new File(directory);
0865:                if (!dir.isAbsolute())
0866:                    dir = new File(System.getProperty("catalina.base"),
0867:                            directory);
0868:                dir.mkdirs();
0869:
0870:                // Open the current log file
0871:                try {
0872:                    String pathname;
0873:
0874:                    // If no rotate - no need for dateStamp in fileName
0875:                    if (rotatable) {
0876:                        pathname = dir.getAbsolutePath() + File.separator
0877:                                + prefix + dateStamp + suffix;
0878:                    } else {
0879:                        pathname = dir.getAbsolutePath() + File.separator
0880:                                + prefix + suffix;
0881:                    }
0882:
0883:                    currentLogFile = new File(pathname);
0884:                    writer = new PrintWriter(new FileWriter(pathname, true),
0885:                            true);
0886:                    if (currentLogFile.length() == 0) {
0887:                        writer.println("#Fields: " + pattern);
0888:                        writer.println("#Version: 1.0");
0889:                        writer.println("#Software: "
0890:                                + ServerInfo.getServerInfo());
0891:                    }
0892:
0893:                } catch (IOException e) {
0894:                    writer = null;
0895:                    currentLogFile = null;
0896:                }
0897:
0898:            }
0899:
0900:            /**
0901:             * This method returns a Date object that is accurate to within one
0902:             * second.  If a thread calls this method to get a Date and it's been
0903:             * less than 1 second since a new Date was created, this method
0904:             * simply gives out the same Date again so that the system doesn't
0905:             * spend time creating Date objects unnecessarily.
0906:             */
0907:            private Date getDate(long systime) {
0908:                /* Avoid extra call to System.currentTimeMillis(); */
0909:                if (0 == systime) {
0910:                    systime = System.currentTimeMillis();
0911:                }
0912:
0913:                // Only create a new Date once per second, max.
0914:                if ((systime - currentDate.getTime()) > 1000) {
0915:                    currentDate.setTime(systime);
0916:                }
0917:
0918:                return currentDate;
0919:
0920:            }
0921:
0922:            // ------------------------------------------------------ Lifecycle Methods
0923:
0924:            /**
0925:             * Add a lifecycle event listener to this component.
0926:             *
0927:             * @param listener The listener to add
0928:             */
0929:            public void addLifecycleListener(LifecycleListener listener) {
0930:
0931:                lifecycle.addLifecycleListener(listener);
0932:
0933:            }
0934:
0935:            /**
0936:             * Get the lifecycle listeners associated with this lifecycle. If this
0937:             * Lifecycle has no listeners registered, a zero-length array is returned.
0938:             */
0939:            public LifecycleListener[] findLifecycleListeners() {
0940:
0941:                return lifecycle.findLifecycleListeners();
0942:
0943:            }
0944:
0945:            /**
0946:             * Remove a lifecycle event listener from this component.
0947:             *
0948:             * @param listener The listener to add
0949:             */
0950:            public void removeLifecycleListener(LifecycleListener listener) {
0951:
0952:                lifecycle.removeLifecycleListener(listener);
0953:
0954:            }
0955:
0956:            /**
0957:             * Prepare for the beginning of active use of the public methods of this
0958:             * component.  This method should be called after <code>configure()</code>,
0959:             * and before any of the public methods of the component are utilized.
0960:             *
0961:             * @exception LifecycleException if this component detects a fatal error
0962:             *  that prevents this component from being used
0963:             */
0964:            public void start() throws LifecycleException {
0965:
0966:                // Validate and update our current component state
0967:                if (started)
0968:                    throw new LifecycleException(sm
0969:                            .getString("extendedAccessLogValve.alreadyStarted"));
0970:                lifecycle.fireLifecycleEvent(START_EVENT, null);
0971:                started = true;
0972:
0973:                // Initialize the timeZone, Date formatters, and currentDate
0974:                TimeZone tz = TimeZone.getTimeZone("GMT");
0975:                dateFormatter = new SimpleDateFormat("yyyy-MM-dd");
0976:                dateFormatter.setTimeZone(tz);
0977:                timeFormatter = new SimpleDateFormat("HH:mm:ss");
0978:                timeFormatter.setTimeZone(tz);
0979:                currentDate = new Date(System.currentTimeMillis());
0980:                if (fileDateFormat == null || fileDateFormat.length() == 0)
0981:                    fileDateFormat = "yyyy-MM-dd";
0982:                fileDateFormatter = new SimpleDateFormat(fileDateFormat);
0983:                dateStamp = fileDateFormatter.format(currentDate);
0984:                timeTakenFormatter = new DecimalFormat("0.000");
0985:
0986:                /* Everybody say ick ... ick */
0987:                try {
0988:                    InetAddress inetAddress = InetAddress.getLocalHost();
0989:                    myIpAddress = inetAddress.getHostAddress();
0990:                    myDNSName = inetAddress.getHostName();
0991:                } catch (Throwable e) {
0992:                    myIpAddress = "127.0.0.1";
0993:                    myDNSName = "localhost";
0994:                }
0995:
0996:                open();
0997:
0998:            }
0999:
1000:            /**
1001:             * Gracefully terminate the active use of the public methods of this
1002:             * component.  This method should be the last one called on a given
1003:             * instance of this component.
1004:             *
1005:             * @exception LifecycleException if this component detects a fatal error
1006:             *  that needs to be reported
1007:             */
1008:            public void stop() throws LifecycleException {
1009:
1010:                // Validate and update our current component state
1011:                if (!started)
1012:                    throw new LifecycleException(sm
1013:                            .getString("extendedAccessLogValve.notStarted"));
1014:                lifecycle.fireLifecycleEvent(STOP_EVENT, null);
1015:                started = false;
1016:
1017:                close();
1018:
1019:            }
1020:
1021:            /**
1022:             * Decode the given pattern. Is public so a pattern may
1023:             * allows to be validated.
1024:             * @param fields The pattern to decode
1025:             * @return null on error.  Otherwise array of decoded fields
1026:             */
1027:            public FieldInfo[] decodePattern(String fields) {
1028:
1029:                if (log.isDebugEnabled())
1030:                    log.debug("decodePattern, fields=" + fields);
1031:
1032:                LinkedList list = new LinkedList();
1033:
1034:                //Ignore leading whitespace.
1035:                int i = 0;
1036:                for (; i < fields.length()
1037:                        && Character.isWhitespace(fields.charAt(i)); i++)
1038:                    ;
1039:
1040:                if (i >= fields.length()) {
1041:                    log.info("fields was just empty or whitespace");
1042:                    return null;
1043:                }
1044:
1045:                int j;
1046:                while (i < fields.length()) {
1047:                    if (log.isDebugEnabled())
1048:                        log.debug("fields.substring(i)=" + fields.substring(i));
1049:
1050:                    FieldInfo currentFieldInfo = new FieldInfo();
1051:
1052:                    if (fields.startsWith("date", i)) {
1053:                        currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
1054:                        currentFieldInfo.location = FieldInfo.SPECIAL_DATE;
1055:                        i += "date".length();
1056:                    } else if (fields.startsWith("time-taken", i)) {
1057:                        currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
1058:                        currentFieldInfo.location = FieldInfo.SPECIAL_TIME_TAKEN;
1059:                        i += "time-taken".length();
1060:                    } else if (fields.startsWith("time", i)) {
1061:                        currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
1062:                        currentFieldInfo.location = FieldInfo.SPECIAL_TIME;
1063:                        i += "time".length();
1064:                    } else if (fields.startsWith("bytes", i)) {
1065:                        currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
1066:                        currentFieldInfo.location = FieldInfo.SPECIAL_BYTES;
1067:                        i += "bytes".length();
1068:                    } else if (fields.startsWith("cached", i)) {
1069:                        currentFieldInfo.type = FieldInfo.DATA_SPECIAL;
1070:                        currentFieldInfo.location = FieldInfo.SPECIAL_CACHED;
1071:                        i += "cached".length();
1072:                    } else if (fields.startsWith("c-ip", i)) {
1073:                        currentFieldInfo.type = FieldInfo.DATA_CLIENT;
1074:                        currentFieldInfo.location = FieldInfo.FIELD_IP;
1075:                        i += "c-ip".length();
1076:                    } else if (fields.startsWith("c-dns", i)) {
1077:                        currentFieldInfo.type = FieldInfo.DATA_CLIENT;
1078:                        currentFieldInfo.location = FieldInfo.FIELD_DNS;
1079:                        i += "c-dns".length();
1080:                    } else if (fields.startsWith("s-ip", i)) {
1081:                        currentFieldInfo.type = FieldInfo.DATA_SERVER;
1082:                        currentFieldInfo.location = FieldInfo.FIELD_IP;
1083:                        i += "s-ip".length();
1084:                    } else if (fields.startsWith("s-dns", i)) {
1085:                        currentFieldInfo.type = FieldInfo.DATA_SERVER;
1086:                        currentFieldInfo.location = FieldInfo.FIELD_DNS;
1087:                        i += "s-dns".length();
1088:                    } else if (fields.startsWith("cs", i)) {
1089:                        i = decode(fields, i + 2, currentFieldInfo,
1090:                                FieldInfo.DATA_CLIENT_TO_SERVER);
1091:                        if (i < 0)
1092:                            return null;
1093:                    } else if (fields.startsWith("sc", i)) {
1094:                        i = decode(fields, i + 2, currentFieldInfo,
1095:                                FieldInfo.DATA_SERVER_TO_CLIENT);
1096:                        if (i < 0)
1097:                            return null;
1098:                    } else if (fields.startsWith("sr", i)) {
1099:                        i = decode(fields, i + 2, currentFieldInfo,
1100:                                FieldInfo.DATA_SERVER_TO_RSERVER);
1101:                        if (i < 0)
1102:                            return null;
1103:                    } else if (fields.startsWith("rs", i)) {
1104:                        i = decode(fields, i + 2, currentFieldInfo,
1105:                                FieldInfo.DATA_RSERVER_TO_SERVER);
1106:                        if (i < 0)
1107:                            return null;
1108:                    } else if (fields.startsWith("x", i)) {
1109:                        i = decodeAppSpecific(fields, i, currentFieldInfo);
1110:                    } else {
1111:                        // Unable to decode ...
1112:                        log.error("unable to decode with rest of chars being: "
1113:                                + fields.substring(i));
1114:                        return null;
1115:                    }
1116:
1117:                    // By this point we should have the field, get the whitespace
1118:                    j = i;
1119:                    for (; j < fields.length()
1120:                            && Character.isWhitespace(fields.charAt(j)); j++)
1121:                        ;
1122:
1123:                    if (j >= fields.length()) {
1124:                        if (j == i) {
1125:                            // Special case - end of string
1126:                            currentFieldInfo.postWhiteSpace = "";
1127:                        } else {
1128:                            currentFieldInfo.postWhiteSpace = fields
1129:                                    .substring(i);
1130:                            i = j;
1131:                        }
1132:                    } else {
1133:                        currentFieldInfo.postWhiteSpace = fields
1134:                                .substring(i, j);
1135:                        i = j;
1136:                    }
1137:
1138:                    list.add(currentFieldInfo);
1139:                }
1140:
1141:                i = 0;
1142:                FieldInfo[] f = new FieldInfo[list.size()];
1143:                for (Iterator k = list.iterator(); k.hasNext();)
1144:                    f[i++] = (FieldInfo) k.next();
1145:
1146:                if (log.isDebugEnabled())
1147:                    log.debug("finished decoding with length of: " + i);
1148:
1149:                return f;
1150:            }
1151:
1152:            /**
1153:             * Decode the cs or sc fields.
1154:             * Returns negative on error.
1155:             *
1156:             * @param fields The pattern to decode
1157:             * @param i The string index where we are decoding.
1158:             * @param fieldInfo Where to store the results
1159:             * @param type The type we are decoding.
1160:             * @return -1 on error. Otherwise the new String index.
1161:             */
1162:            private int decode(String fields, int i, FieldInfo fieldInfo,
1163:                    short type) {
1164:
1165:                if (fields.startsWith("-status", i)) {
1166:                    fieldInfo.location = FieldInfo.FIELD_STATUS;
1167:                    i += "-status".length();
1168:                } else if (fields.startsWith("-comment", i)) {
1169:                    fieldInfo.location = FieldInfo.FIELD_COMMENT;
1170:                    i += "-comment".length();
1171:                } else if (fields.startsWith("-uri-query", i)) {
1172:                    fieldInfo.location = FieldInfo.FIELD_URI_QUERY;
1173:                    i += "-uri-query".length();
1174:                } else if (fields.startsWith("-uri-stem", i)) {
1175:                    fieldInfo.location = FieldInfo.FIELD_URI_STEM;
1176:                    i += "-uri-stem".length();
1177:                } else if (fields.startsWith("-uri", i)) {
1178:                    fieldInfo.location = FieldInfo.FIELD_URI;
1179:                    i += "-uri".length();
1180:                } else if (fields.startsWith("-method", i)) {
1181:                    fieldInfo.location = FieldInfo.FIELD_METHOD;
1182:                    i += "-method".length();
1183:                } else if (fields.startsWith("(", i)) {
1184:                    fieldInfo.location = FieldInfo.FIELD_HEADER;
1185:                    i++; /* Move past the ( */
1186:                    int j = fields.indexOf(')', i);
1187:                    if (j == -1) { /* Not found */
1188:                        log.error("No closing ) found for in decode");
1189:                        return -1;
1190:                    }
1191:                    fieldInfo.value = fields.substring(i, j);
1192:                    i = j + 1; // Move pointer past ) */
1193:                } else {
1194:                    log.error("The next characters couldn't be decoded: "
1195:                            + fields.substring(i));
1196:                    return -1;
1197:                }
1198:
1199:                fieldInfo.type = type;
1200:                return i;
1201:
1202:            }
1203:
1204:            /**
1205:             * Decode app specific log entry.
1206:             *
1207:             * Special fields are of the form:
1208:             * x-C(...) - For cookie
1209:             * x-A(...) - Value in servletContext
1210:             * x-S(...) - Value in session
1211:             * x-R(...) - Value in servletRequest
1212:             * @param fields The pattern to decode
1213:             * @param i The string index where we are decoding.
1214:             * @param fieldInfo Where to store the results
1215:             * @return -1 on error. Otherwise the new String index.
1216:             */
1217:            private int decodeAppSpecific(String fields, int i,
1218:                    FieldInfo fieldInfo) {
1219:
1220:                fieldInfo.type = FieldInfo.DATA_APP_SPECIFIC;
1221:                /* Move past 'x-' */
1222:                i += 2;
1223:
1224:                if (i >= fields.length()) {
1225:                    log.error("End of line reached before decoding x- param");
1226:                    return -1;
1227:                }
1228:
1229:                switch (fields.charAt(i)) {
1230:                case 'A':
1231:                    fieldInfo.xType = FieldInfo.X_APP;
1232:                    break;
1233:                case 'C':
1234:                    fieldInfo.xType = FieldInfo.X_COOKIE;
1235:                    break;
1236:                case 'R':
1237:                    fieldInfo.xType = FieldInfo.X_REQUEST;
1238:                    break;
1239:                case 'S':
1240:                    fieldInfo.xType = FieldInfo.X_SESSION;
1241:                    break;
1242:                case 'H':
1243:                    fieldInfo.xType = FieldInfo.X_SERVLET_REQUEST;
1244:                    break;
1245:                case 'P':
1246:                    fieldInfo.xType = FieldInfo.X_PARAMETER;
1247:                    break;
1248:                default:
1249:                    return -1;
1250:                }
1251:
1252:                /* test that next char is a ( */
1253:                if (i + 1 != fields.indexOf('(', i)) {
1254:                    log
1255:                            .error("x param in wrong format. Needs to be 'x-#(...)' read the docs!");
1256:                    return -1;
1257:                }
1258:                i += 2; /* Move inside of the () */
1259:
1260:                /* Look for ending ) and return error if not found. */
1261:                int j = fields.indexOf(')', i);
1262:                if (j == -1) {
1263:                    log.error("x param in wrong format. No closing ')'!");
1264:                    return -1;
1265:                }
1266:
1267:                fieldInfo.value = fields.substring(i, j);
1268:
1269:                if (fieldInfo.xType == FieldInfo.X_SERVLET_REQUEST) {
1270:                    if ("authType".equals(fieldInfo.value)) {
1271:                        fieldInfo.location = FieldInfo.X_LOC_AUTHTYPE;
1272:                    } else if ("remoteUser".equals(fieldInfo.value)) {
1273:                        fieldInfo.location = FieldInfo.X_LOC_REMOTEUSER;
1274:                    } else if ("requestedSessionId".equals(fieldInfo.value)) {
1275:                        fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONID;
1276:                    } else if ("requestedSessionIdFromCookie"
1277:                            .equals(fieldInfo.value)) {
1278:                        fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE;
1279:                    } else if ("requestedSessionIdValid"
1280:                            .equals(fieldInfo.value)) {
1281:                        fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID;
1282:                    } else if ("contentLength".equals(fieldInfo.value)) {
1283:                        fieldInfo.location = FieldInfo.X_LOC_CONTENTLENGTH;
1284:                    } else if ("characterEncoding".equals(fieldInfo.value)) {
1285:                        fieldInfo.location = FieldInfo.X_LOC_CHARACTERENCODING;
1286:                    } else if ("locale".equals(fieldInfo.value)) {
1287:                        fieldInfo.location = FieldInfo.X_LOC_LOCALE;
1288:                    } else if ("protocol".equals(fieldInfo.value)) {
1289:                        fieldInfo.location = FieldInfo.X_LOC_PROTOCOL;
1290:                    } else if ("scheme".equals(fieldInfo.value)) {
1291:                        fieldInfo.location = FieldInfo.X_LOC_SCHEME;
1292:                    } else if ("secure".equals(fieldInfo.value)) {
1293:                        fieldInfo.location = FieldInfo.X_LOC_SECURE;
1294:                    } else {
1295:                        log
1296:                                .error("x param for servlet request, couldn't decode value: "
1297:                                        + fieldInfo.location);
1298:                        return -1;
1299:                    }
1300:                }
1301:
1302:                return j + 1;
1303:
1304:            }
1305:
1306:        }
1307:
1308:        /**
1309:         * A simple helper for decoding the pattern.
1310:         */
1311:        class FieldInfo {
1312:            /*
1313:               The goal of the constants listed below is to make the construction of the log
1314:               entry as quick as possible via numerci decodings of the methods to call instead
1315:               of performing many String comparisons on each logging request.
1316:             */
1317:
1318:            /* Where the data is located. */
1319:            static final short DATA_CLIENT = 0;
1320:            static final short DATA_SERVER = 1;
1321:            static final short DATA_REMOTE = 2;
1322:            static final short DATA_CLIENT_TO_SERVER = 3;
1323:            static final short DATA_SERVER_TO_CLIENT = 4;
1324:            static final short DATA_SERVER_TO_RSERVER = 5; /* Here to honor the spec. */
1325:            static final short DATA_RSERVER_TO_SERVER = 6; /* Here to honor the spec. */
1326:            static final short DATA_APP_SPECIFIC = 7;
1327:            static final short DATA_SPECIAL = 8;
1328:
1329:            /* The type of special fields. */
1330:            static final short SPECIAL_DATE = 1;
1331:            static final short SPECIAL_TIME_TAKEN = 2;
1332:            static final short SPECIAL_TIME = 3;
1333:            static final short SPECIAL_BYTES = 4;
1334:            static final short SPECIAL_CACHED = 5;
1335:
1336:            /* Where to pull the data for prefixed values */
1337:            static final short FIELD_IP = 1;
1338:            static final short FIELD_DNS = 2;
1339:            static final short FIELD_STATUS = 3;
1340:            static final short FIELD_COMMENT = 4;
1341:            static final short FIELD_METHOD = 5;
1342:            static final short FIELD_URI = 6;
1343:            static final short FIELD_URI_STEM = 7;
1344:            static final short FIELD_URI_QUERY = 8;
1345:            static final short FIELD_HEADER = 9;
1346:
1347:            /* Application Specific parameters */
1348:            static final short X_REQUEST = 1; /* For x app specific */
1349:            static final short X_SESSION = 2; /* For x app specific */
1350:            static final short X_COOKIE = 3; /* For x app specific */
1351:            static final short X_APP = 4; /* For x app specific */
1352:            static final short X_SERVLET_REQUEST = 5; /* For x app specific */
1353:            static final short X_PARAMETER = 6; /* For x app specific */
1354:
1355:            static final short X_LOC_AUTHTYPE = 1;
1356:            static final short X_LOC_REMOTEUSER = 2;
1357:            static final short X_LOC_REQUESTEDSESSIONID = 3;
1358:            static final short X_LOC_REQUESTEDSESSIONIDFROMCOOKIE = 4;
1359:            static final short X_LOC_REQUESTEDSESSIONIDVALID = 5;
1360:            static final short X_LOC_CONTENTLENGTH = 6;
1361:            static final short X_LOC_CHARACTERENCODING = 7;
1362:            static final short X_LOC_LOCALE = 8;
1363:            static final short X_LOC_PROTOCOL = 9;
1364:            static final short X_LOC_SCHEME = 10;
1365:            static final short X_LOC_SECURE = 11;
1366:
1367:            /** The field type */
1368:            short type;
1369:
1370:            /** Where to pull the data from? Icky variable name. */
1371:            short location;
1372:
1373:            /** The x- specific place to pull the data from. */
1374:            short xType;
1375:
1376:            /** The field value if needed. Needed for headers and app specific. */
1377:            String value;
1378:
1379:            /** Any white space after this field? Put it here. */
1380:            String postWhiteSpace = null;
1381:
1382:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.