Source Code Cross Referenced for SingleQueryServlet.java in  » Web-Services » Gomba » org » gomba » 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 » Web Services » Gomba » org.gomba 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        package org.gomba;
002:
003:        import java.io.IOException;
004:        import java.sql.Connection;
005:        import java.sql.ResultSet;
006:        import java.util.Iterator;
007:        import java.util.Map;
008:
009:        import javax.servlet.RequestDispatcher;
010:        import javax.servlet.ServletConfig;
011:        import javax.servlet.ServletException;
012:        import javax.servlet.http.HttpServletRequest;
013:        import javax.servlet.http.HttpServletResponse;
014:
015:        /**
016:         * Base class for servlets that perform a SELECT and render the results to the
017:         * HTTP response body.
018:         * 
019:         * </p>
020:         * Init params:
021:         * <dl>
022:         * <dt>query</dt>
023:         * <dd>The SQL query to execute. May contain ${} parameters. This init-param
024:         * also accepts a path to a dynamic resource (a JSP) when dynamic SQL generation
025:         * is needed. The path must begin with a "/" and is interpreted as relative to
026:         * the current context root. (Required)</dd>
027:         * <dt>skip</dt>
028:         * <dd>The number of records to skip. May contain ${} parameters. (Optional)
029:         * </dd>
030:         * <dt>max</dt>
031:         * <dd>The maximum number of records to load. May contain ${} parameters.
032:         * (Optional)</dd>
033:         * <dt>nodata-http-status</dt>
034:         * <dd>The HTTP status code in case of empty resultset. If the code is 200 (OK)
035:         * then the subclassing servlet will output its default value. Defaults to 200
036:         * (OK). A useful code is 404 (Not found). (Optional)</dd>
037:         * <dt>nodata-default-resource</dt>
038:         * <dd>Path to a resource to serve in case of empty resultset. The path must
039:         * begin with a "/" and is interpreted as relative to the current context root.
040:         * When this init-param is not specified, the subclassing servlet default output
041:         * is used. (Optional)</dd>
042:         * </dl>
043:         * </p>
044:         * 
045:         * @author Flavio Tordini
046:         * @version $Id: SingleQueryServlet.java,v 1.5 2005/10/19 13:48:16 flaviotordini Exp $
047:         */
048:        public abstract class SingleQueryServlet extends AbstractServlet {
049:
050:            private final static String INIT_PARAM_QUERY = "query";
051:
052:            private final static String INIT_PARAM_SKIP = "skip";
053:
054:            private final static String INIT_PARAM_MAX = "max";
055:
056:            private final static String INIT_PARAM_NO_DATA_HTTP_STATUS = "nodata-http-status";
057:
058:            private final static String INIT_PARAM_NO_DATA_DEFAULT_RESOURCE = "nodata-default-resource";
059:
060:            /**
061:             * The parsed query definition. It is null when the query is dynamic, i.e. a
062:             * dynamic resource (a JSP) is used to generate the SQL.
063:             */
064:            private QueryDefinition queryDefinition;
065:
066:            /**
067:             * The path of a resource that dynamically generates a SQL query.
068:             */
069:            private String queryResource;
070:
071:            /**
072:             * Skip and max expressions. These are only set when a dynamic query is
073:             * used.
074:             */
075:            private Expression skip, max;
076:
077:            /**
078:             * The HTTP status code in case of empty resultset.
079:             */
080:            private int noDataHttpStatusCode = HttpServletResponse.SC_OK;
081:
082:            /**
083:             * Path to a resource to serve in case of empty resultset. If null the
084:             * doDefaultOutput method is invoked.
085:             */
086:            private String noDataDefaultResource;
087:
088:            /**
089:             * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
090:             */
091:            public void init(ServletConfig config) throws ServletException {
092:                super .init(config);
093:
094:                // parse the query definition
095:                try {
096:                    String query = config.getInitParameter(INIT_PARAM_QUERY);
097:                    String skip = config.getInitParameter(INIT_PARAM_SKIP);
098:                    String max = config.getInitParameter(INIT_PARAM_MAX);
099:                    if (!query.startsWith("/")) {
100:                        this .queryDefinition = new QueryDefinition(query, skip,
101:                                max);
102:                    } else {
103:                        this .queryResource = query;
104:                        if (skip != null) {
105:                            this .skip = new Expression(skip);
106:                        }
107:                        if (max != null) {
108:                            this .max = new Expression(max);
109:                        }
110:                    }
111:                } catch (Exception e) {
112:                    throw new ServletException(
113:                            "Error parsing query definition.", e);
114:                }
115:
116:                // the HTTP status code to send in case of empty resultset.
117:                try {
118:                    String noDataHttpStatusCodeString = config
119:                            .getInitParameter(INIT_PARAM_NO_DATA_HTTP_STATUS);
120:                    if (noDataHttpStatusCodeString != null) {
121:                        this .noDataHttpStatusCode = Integer
122:                                .parseInt(noDataHttpStatusCodeString);
123:                    }
124:                } catch (NumberFormatException e) {
125:                    throw new ServletException("Error parsing "
126:                            + INIT_PARAM_NO_DATA_HTTP_STATUS, e);
127:                }
128:
129:                // default resource in case of empty resultset.
130:                this .noDataDefaultResource = config
131:                        .getInitParameter(INIT_PARAM_NO_DATA_DEFAULT_RESOURCE);
132:            }
133:
134:            /**
135:             * Get the QueryDefinition, it can be a fixed QueryDefinition created at
136:             * init-time. Or a dynamic one created by evaluating a JSP.
137:             */
138:            private QueryDefinition getQueryDefinition(
139:                    HttpServletRequest request, HttpServletResponse response)
140:                    throws ServletException, IOException {
141:                QueryDefinition requestQueryDefinition;
142:                if (this .queryDefinition == null) {
143:                    // dynamic query
144:                    String sql = getDynamicQuery(this .queryResource, request,
145:                            response);
146:                    try {
147:                        requestQueryDefinition = new QueryDefinition(sql,
148:                                this .skip, this .max);
149:                    } catch (Exception e) {
150:                        throw new ServletException(
151:                                "Error parsing query definition.", e);
152:                    }
153:                } else {
154:                    // fixed query
155:                    requestQueryDefinition = this .queryDefinition;
156:                }
157:                return requestQueryDefinition;
158:            }
159:
160:            /**
161:             * The real work is done here.
162:             * 
163:             * @param request
164:             *                   The HTTP request
165:             * @param response
166:             *                   The HTTP response
167:             * @param renderBody
168:             *                   Wheter to render the response body or not.
169:             */
170:            protected final void processRequest(HttpServletRequest request,
171:                    HttpServletResponse response, boolean renderBody)
172:                    throws ServletException, IOException {
173:
174:                // get current time for benchmarking purposes
175:                final long startTime = System.currentTimeMillis();
176:
177:                // create the parameter resolver that will help us throughout this
178:                // request
179:                final ParameterResolver parameterResolver = new ParameterResolver(
180:                        request);
181:
182:                // get the query definition
183:                QueryDefinition requestQueryDefinition = getQueryDefinition(
184:                        request, response);
185:
186:                // build the Query
187:                final Query query = getQuery(requestQueryDefinition,
188:                        parameterResolver);
189:
190:                // find out if this request is part of a transaction
191:                Transaction transaction = getTransaction(parameterResolver);
192:
193:                Query.QueryResult queryResult = null;
194:                Connection connection = null;
195:
196:                // surround everything in this try/finally to be able to free JDBC
197:                // resources even in case of exceptions
198:                try {
199:
200:                    try {
201:
202:                        if (transaction == null) {
203:                            connection = getDataSource().getConnection();
204:                        } else {
205:                            if (isDebugMode()) {
206:                                log("Request is part of transaction: "
207:                                        + transaction.getUri());
208:                            }
209:                            connection = transaction.getConnection();
210:                        }
211:
212:                        // execute the query
213:                        queryResult = query.execute(connection);
214:
215:                        // queryResult may be null, if the query is an update.
216:                        if (queryResult != null) {
217:
218:                            // Make sure the resultset cursor is positioned on a row. If
219:                            // resultset is empty or after the last row, stop processing
220:                            // this request.
221:                            if (!maybeMoveCursor(queryResult.getResultSet())) {
222:                                // the resultset is empty!
223:
224:                                // if status is not 200 set the HTTP status and stop
225:                                if (this .noDataHttpStatusCode != HttpServletResponse.SC_OK) {
226:                                    response
227:                                            .sendError(this .noDataHttpStatusCode);
228:                                    return;
229:                                }
230:
231:                                // set the response headers right away
232:                                // if the response headers include an expression using
233:                                // the 'column' domain (which requires a resultset
234:                                // available to the ParameterResolver) an exception will
235:                                // be thrown. The exception is caught and logged if in
236:                                // debug mode.
237:                                Map responseHeaders = getResponseHeaders();
238:                                if (responseHeaders != null) {
239:                                    try {
240:                                        for (Iterator i = responseHeaders
241:                                                .entrySet().iterator(); i
242:                                                .hasNext();) {
243:                                            Map.Entry mapEntry = (Map.Entry) i
244:                                                    .next();
245:
246:                                            String headerName = (String) mapEntry
247:                                                    .getKey();
248:                                            Object headerValue;
249:                                            try {
250:                                                headerValue = ((Expression) mapEntry
251:                                                        .getValue())
252:                                                        .replaceParameters(parameterResolver);
253:                                            } catch (ParameterResolver.UnavailableResultSetException urse) {
254:                                                if (isDebugMode()) {
255:                                                    log(
256:                                                            "Cannot set response header: "
257:                                                                    + headerName,
258:                                                            urse);
259:                                                }
260:                                                continue;
261:                                            }
262:                                            setResponseHeader(response,
263:                                                    headerName, headerValue);
264:
265:                                        }
266:                                    } catch (Exception e) {
267:                                        throw new ServletException(
268:                                                "Error setting response headers.",
269:                                                e);
270:                                    }
271:                                }
272:
273:                                if (this .noDataDefaultResource == null) {
274:                                    // default output
275:                                    try {
276:                                        // subclasses will implement this!
277:                                        doDefaultOutput(response);
278:                                    } catch (Exception e) {
279:                                        throw new ServletException(
280:                                                "Error rendering default output.",
281:                                                e);
282:                                    }
283:                                } else {
284:                                    // default resource
285:                                    serveDefaultResource(
286:                                            this .noDataDefaultResource,
287:                                            request, response);
288:                                }
289:
290:                                // stop processing this request.
291:                                return;
292:                            }
293:
294:                            // set reference to the result set in order to resolve
295:                            // 'column' domain parameters
296:                            parameterResolver.setResultSet(queryResult
297:                                    .getResultSet());
298:
299:                        }
300:
301:                    } catch (Exception e) {
302:                        // log the SQL for debugging
303:                        log("Error executing query: " + query, e);
304:                        // but don't expose the SQL nor the exception on the web for
305:                        // security reasons. We don't want users to be able to see our
306:                        // SQL nor the JDBC driver exception messages which usually
307:                        // contain table names and such.
308:                        response.sendError(
309:                                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
310:                                "Error executing query. See logs for details.");
311:                        return;
312:                    }
313:
314:                    try {
315:                        ResultSet resultSet = null;
316:                        if (queryResult != null) {
317:                            resultSet = queryResult.getResultSet();
318:                        }
319:                        // subclasses will implement this!
320:                        doInput(resultSet, request, parameterResolver,
321:                                connection);
322:                    } catch (Exception e) {
323:                        throw new ServletException(
324:                                "Error processing request body.", e);
325:                    }
326:
327:                    // set the response headers
328:                    setResponseHeaders(response, parameterResolver);
329:
330:                    // set the HTTP status code
331:                    if (getHttpStatusCode() != HttpServletResponse.SC_OK) {
332:                        response.setStatus(getHttpStatusCode());
333:                    }
334:
335:                    // optionally write to the response body
336:                    if (renderBody) {
337:                        if (queryResult == null) {
338:                            throw new ServletException(
339:                                    "Resultset is null. The query didn't return a resultset.");
340:                        }
341:                        try {
342:                            // subclasses will implement this!
343:                            doOutput(queryResult.getResultSet(), response,
344:                                    parameterResolver);
345:                        } catch (Exception e) {
346:                            throw new ServletException(
347:                                    "Error rendering results.", e);
348:                        }
349:                    }
350:
351:                } finally {
352:                    // *always* free the JDBC resources!
353:                    try {
354:                        if (queryResult != null) {
355:                            try {
356:                                queryResult.close();
357:                            } catch (Exception e) {
358:                                throw new ServletException(
359:                                        "Error freeing JDBC resources.", e);
360:                            }
361:                        }
362:
363:                    } finally {
364:                        // close the JDBC connection if this request is not part of a
365:                        // transaction
366:                        if (transaction == null && connection != null) {
367:                            try {
368:                                connection.close();
369:                            } catch (Exception e) {
370:                                throw new ServletException(
371:                                        "Error closing JDBC connection.", e);
372:                            }
373:                        }
374:                    }
375:
376:                    // processing time
377:                    if (isDebugMode()) {
378:                        log(getProfilingMessage(request, startTime));
379:                    }
380:                }
381:
382:            }
383:
384:            /**
385:             * Override this method in order to process data from the request body. The
386:             * contract for subclasses is not to close the ResultSet and not to call
387:             * ResultSet.next().
388:             * 
389:             * @param resultSet
390:             *                   The resultset, may be null.
391:             * @param request
392:             *                   The HTTP request to read from
393:             * @param parameterResolver
394:             *                   The object used to resolve parameters.
395:             */
396:            protected void doInput(ResultSet resultSet,
397:                    HttpServletRequest request,
398:                    ParameterResolver parameterResolver, Connection connection)
399:                    throws Exception {
400:                // dummy
401:            }
402:
403:            /**
404:             * Render the content of the resultset in the response body. The contract
405:             * for subclasses is not to close the ResultSet and expect it to be
406:             * positioned on the first row to render (This means ResultSet.next() should
407:             * be called <strong>after </strong> the first row has been rendered.
408:             * 
409:             * @param resultSet
410:             *                   The resultset to render
411:             * @param response
412:             *                   The HTTP response to write to
413:             * @param parameterResolver
414:             *                   The object used to resolve parameters.
415:             */
416:            protected void doOutput(ResultSet resultSet,
417:                    HttpServletResponse response,
418:                    ParameterResolver parameterResolver) throws Exception {
419:                // dummy
420:            }
421:
422:            /**
423:             * Render a default value when the resultset is empty (0 rows).
424:             * 
425:             * @param response
426:             *                   The HTTP response to write to
427:             */
428:            protected void doDefaultOutput(HttpServletResponse response)
429:                    throws Exception {
430:                // dummy
431:            }
432:
433:            /**
434:             * Serve a default resource.
435:             * 
436:             * @param defaultResource
437:             *                   Path to the resource
438:             * @param request
439:             *                   The HTTP request
440:             * @param response
441:             *                   The HTTP response
442:             */
443:            private final void serveDefaultResource(String defaultResource,
444:                    HttpServletRequest request, HttpServletResponse response)
445:                    throws ServletException, IOException {
446:                // get the dispatcher
447:                RequestDispatcher dispatcher = getServletContext()
448:                        .getRequestDispatcher(defaultResource);
449:                if (dispatcher == null) {
450:                    throw new ServletException(
451:                            "Cannot get a RequestDispatcher for path: "
452:                                    + defaultResource);
453:                }
454:                dispatcher.forward(request, response);
455:            }
456:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.