Source Code Cross Referenced for GWTShellServlet.java in  » Ajax » GWT » com » google » gwt » dev » shell » 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 » Ajax » GWT » com.google.gwt.dev.shell 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 2007 Google Inc.
003:         * 
004:         * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005:         * use this file except in compliance with the License. You may obtain a copy of
006:         * the License at
007:         * 
008:         * http://www.apache.org/licenses/LICENSE-2.0
009:         * 
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012:         * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013:         * License for the specific language governing permissions and limitations under
014:         * the License.
015:         */
016:        package com.google.gwt.dev.shell;
017:
018:        import com.google.gwt.core.ext.TreeLogger;
019:        import com.google.gwt.core.ext.UnableToCompleteException;
020:        import com.google.gwt.dev.cfg.ModuleDef;
021:        import com.google.gwt.dev.cfg.ModuleDefLoader;
022:        import com.google.gwt.dev.util.HttpHeaders;
023:        import com.google.gwt.dev.util.SelectionScriptGenerator;
024:        import com.google.gwt.dev.util.Util;
025:        import com.google.gwt.dev.util.log.ServletContextTreeLogger;
026:
027:        import java.io.File;
028:        import java.io.IOException;
029:        import java.io.InputStream;
030:        import java.io.OutputStream;
031:        import java.io.PrintWriter;
032:        import java.net.MalformedURLException;
033:        import java.net.URL;
034:        import java.net.URLConnection;
035:        import java.util.Date;
036:        import java.util.HashMap;
037:        import java.util.Map;
038:
039:        import javax.servlet.ServletConfig;
040:        import javax.servlet.ServletContext;
041:        import javax.servlet.ServletException;
042:        import javax.servlet.http.HttpServlet;
043:        import javax.servlet.http.HttpServletRequest;
044:        import javax.servlet.http.HttpServletResponse;
045:
046:        /**
047:         * Built-in servlet for convenient access to the public path of a specified
048:         * module.
049:         */
050:        public class GWTShellServlet extends HttpServlet {
051:
052:            private static class RequestParts {
053:                public final String moduleName;
054:
055:                public final String partialPath;
056:
057:                public RequestParts(HttpServletRequest request)
058:                        throws UnableToCompleteException {
059:                    String pathInfo = request.getPathInfo();
060:                    if (pathInfo != null) {
061:                        int slash = pathInfo.indexOf('/', 1);
062:                        if (slash != -1) {
063:                            moduleName = pathInfo.substring(1, slash);
064:                            partialPath = pathInfo.substring(slash + 1);
065:                            return;
066:                        } else {
067:                            moduleName = pathInfo.substring(1);
068:                            partialPath = null;
069:                            return;
070:                        }
071:                    }
072:                    throw new UnableToCompleteException();
073:                }
074:            }
075:
076:            /**
077:             * This the default cache time in seconds for files that aren't either
078:             * *.cache.*, *.nocache.*.
079:             */
080:            private static final int DEFAULT_CACHE_SECONDS = 5;
081:
082:            private static final String XHTML_MIME_TYPE = "application/xhtml+xml";
083:
084:            private final Map<String, ModuleDef> loadedModulesByName = new HashMap<String, ModuleDef>();
085:
086:            private final Map<String, HttpServlet> loadedServletsByModuleAndClassName = new HashMap<String, HttpServlet>();
087:
088:            private final Map<String, String> mimeTypes = new HashMap<String, String>();
089:
090:            private final Map<String, ModuleDef> modulesByServletPath = new HashMap<String, ModuleDef>();
091:
092:            private int nextRequestId;
093:
094:            private File outDir;
095:
096:            private final Object requestIdLock = new Object();
097:
098:            private TreeLogger topLogger;
099:
100:            public GWTShellServlet() {
101:                initMimeTypes();
102:            }
103:
104:            @Override
105:            protected void doGet(HttpServletRequest request,
106:                    HttpServletResponse response) throws ServletException,
107:                    IOException {
108:                processFileRequest(request, response);
109:            }
110:
111:            @Override
112:            protected void doPost(HttpServletRequest request,
113:                    HttpServletResponse response) throws ServletException,
114:                    IOException {
115:                processFileRequest(request, response);
116:            }
117:
118:            protected void processFileRequest(HttpServletRequest request,
119:                    HttpServletResponse response) throws IOException {
120:
121:                String pathInfo = request.getPathInfo();
122:                if (pathInfo.length() == 0 || pathInfo.equals("/")) {
123:                    response.setContentType("text/html");
124:                    PrintWriter writer = response.getWriter();
125:                    writer.println("<html><body><basefont face='arial'>");
126:                    writer
127:                            .println("To launch an application, specify a URL of the form <code>/<i>module</i>/<i>file.html</i></code>");
128:                    writer.println("</body></html>");
129:                    return;
130:                }
131:
132:                TreeLogger logger = getLogger();
133:
134:                // Parse the request assuming it is module/resource.
135:                //
136:                RequestParts parts;
137:                try {
138:                    parts = new RequestParts(request);
139:                } catch (UnableToCompleteException e) {
140:                    sendErrorResponse(response,
141:                            HttpServletResponse.SC_NOT_FOUND,
142:                            "Don't know what to do with this URL: '" + pathInfo
143:                                    + "'");
144:                    return;
145:                }
146:
147:                String partialPath = parts.partialPath;
148:                String moduleName = parts.moduleName;
149:
150:                if (partialPath == null) {
151:                    // Redir back to the same URL but ending with a slash.
152:                    //
153:                    response.sendRedirect(moduleName + "/");
154:                    return;
155:                } else if (partialPath.length() > 0) {
156:                    // Both the module name and a resource.
157:                    //
158:                    doGetPublicFile(request, response, logger, partialPath,
159:                            moduleName);
160:                    return;
161:                } else {
162:                    // Was just the module name, ending with a slash.
163:                    //
164:                    doGetModule(request, response, logger, parts);
165:                    return;
166:                }
167:            }
168:
169:            @Override
170:            protected void service(HttpServletRequest request,
171:                    HttpServletResponse response) throws ServletException,
172:                    IOException {
173:
174:                TreeLogger logger = getLogger();
175:                int id = allocateRequestId();
176:                if (logger.isLoggable(TreeLogger.TRACE)) {
177:                    StringBuffer url = request.getRequestURL();
178:
179:                    // Branch the logger in case we decide to log more below.
180:                    logger = logger.branch(TreeLogger.TRACE, "Request " + id
181:                            + ": " + url, null);
182:                }
183:
184:                String servletClassName = null;
185:                ModuleDef moduleDef = null;
186:
187:                try {
188:                    // Attempt to split the URL into module/path, which we'll use to see
189:                    // if we can map the request to a module's servlet.
190:                    RequestParts parts = new RequestParts(request);
191:
192:                    // See if the request references a module we know.
193:                    // Note that we do *not* actually try to load the module here, because
194:                    // we're only looking for servlet invocations, which can only happen
195:                    // when we have *already* loaded the destination module to serve up the
196:                    // client code in the first place.
197:                    moduleDef = loadedModulesByName.get(parts.moduleName);
198:                    if (moduleDef != null) {
199:                        // Okay, we know this module. Do we know this servlet path?
200:                        // It is right to prepend the slash because (1) ModuleDefSchema requires
201:                        // every servlet path to begin with a slash and (2) RequestParts always
202:                        // rips off the leading slash.
203:                        String servletPath = "/" + parts.partialPath;
204:                        servletClassName = moduleDef
205:                                .findServletForPath(servletPath);
206:
207:                        // Fall-through below, where we check servletClassName.
208:                    } else {
209:                        // Fall-through below, where we check servletClassName.
210:                    }
211:                } catch (UnableToCompleteException e) {
212:                    // Do nothing, since it was speculative anyway.
213:                }
214:
215:                // BEGIN BACKWARD COMPATIBILITY
216:                if (servletClassName == null) {
217:                    // Try to map a bare path that isn't preceded by the module name.
218:                    // This is no longer the recommended practice, so we warn.
219:                    String path = request.getPathInfo();
220:                    moduleDef = modulesByServletPath.get(path);
221:                    if (moduleDef != null) {
222:                        // See if there is a servlet we can delegate to for the given url.
223:                        servletClassName = moduleDef.findServletForPath(path);
224:
225:                        if (servletClassName != null) {
226:                            TreeLogger branch = logger
227:                                    .branch(
228:                                            TreeLogger.WARN,
229:                                            "Use of deprecated hosted mode servlet path mapping",
230:                                            null);
231:                            branch
232:                                    .log(
233:                                            TreeLogger.WARN,
234:                                            "The client code is invoking the servlet with a URL that is not module-relative: "
235:                                                    + path, null);
236:                            branch
237:                                    .log(
238:                                            TreeLogger.WARN,
239:                                            "Prepend GWT.getModuleBaseURL() to the URL in client code to create a module-relative URL: /"
240:                                                    + moduleDef.getName()
241:                                                    + path, null);
242:                            branch
243:                                    .log(
244:                                            TreeLogger.WARN,
245:                                            "Using module-relative URLs ensures correct URL-independent behavior in external servlet containers",
246:                                            null);
247:                        }
248:
249:                        // Fall-through below, where we check servletClassName.
250:                    } else {
251:                        // Fall-through below, where we check servletClassName.
252:                    }
253:                }
254:                // END BACKWARD COMPATIBILITY
255:
256:                // Load/get the servlet if we found one.
257:                if (servletClassName != null) {
258:                    HttpServlet delegatee = tryGetOrLoadServlet(logger,
259:                            moduleDef, servletClassName);
260:                    if (delegatee == null) {
261:                        logger.log(TreeLogger.ERROR,
262:                                "Unable to dispatch request", null);
263:                        sendErrorResponse(response,
264:                                HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
265:                                "Unable to find/load mapped servlet class '"
266:                                        + servletClassName + "'");
267:                        return;
268:                    }
269:
270:                    // Delegate everything to the downstream servlet and we're done.
271:                    delegatee.service(request, response);
272:                } else {
273:                    // Use normal default processing on this request, since we couldn't
274:                    // recognize it as anything special.
275:                    super .service(request, response);
276:                }
277:            }
278:
279:            private int allocateRequestId() {
280:                synchronized (requestIdLock) {
281:                    return nextRequestId++;
282:                }
283:            }
284:
285:            /**
286:             * Handle auto-generated resources.
287:             * 
288:             * @return <code>true</code> if a resource was generated
289:             */
290:            private boolean autoGenerateResources(HttpServletRequest request,
291:                    HttpServletResponse response, TreeLogger logger,
292:                    String partialPath, String moduleName) throws IOException {
293:
294:                // If the request is of the form ".../moduleName.nocache.js" or
295:                // ".../moduleName-xs.nocache.js" then generate the selection script for
296:                // them.
297:                boolean nocacheHtml = partialPath.equals(moduleName
298:                        + ".nocache.js");
299:                boolean nocacheScript = !nocacheHtml
300:                        && partialPath.equals(moduleName + "-xs.nocache.js");
301:                if (nocacheHtml || nocacheScript) {
302:                    // If the '?compiled' request property is specified, don't auto-generate.
303:                    if (request.getParameter("compiled") == null) {
304:                        // Generate the .js file.
305:                        try {
306:                            String js = genSelectionScript(logger, moduleName,
307:                                    nocacheScript);
308:                            setResponseCacheHeaders(response, 0); // do not cache selection script
309:                            response.setStatus(HttpServletResponse.SC_OK);
310:                            response.setContentType("text/javascript");
311:                            response.getWriter().println(js);
312:                            return true;
313:                        } catch (UnableToCompleteException e) {
314:                            // The error will have already been logged. Continue, since this could
315:                            // actually be a request for a static file that happens to have an
316:                            // unfortunately confusing name.
317:                        }
318:                    }
319:                }
320:
321:                return false;
322:            }
323:
324:            private void doGetModule(HttpServletRequest request,
325:                    HttpServletResponse response, TreeLogger logger,
326:                    RequestParts parts) throws IOException {
327:
328:                if ("favicon.ico".equalsIgnoreCase(parts.moduleName)) {
329:                    sendErrorResponse(response,
330:                            HttpServletResponse.SC_NOT_FOUND,
331:                            "Icon not available");
332:                    return;
333:                }
334:
335:                // Generate a generic empty host page.
336:                //
337:                String msg = "The development shell servlet received a request to generate a host page for module '"
338:                        + parts.moduleName + "' ";
339:
340:                logger = logger.branch(TreeLogger.TRACE, msg, null);
341:
342:                try {
343:                    // Try to load the module just to make sure it'll work.
344:                    getModuleDef(logger, parts.moduleName);
345:                } catch (UnableToCompleteException e) {
346:                    sendErrorResponse(response,
347:                            HttpServletResponse.SC_NOT_FOUND,
348:                            "Unable to find/load module '"
349:                                    + Util.escapeXml(parts.moduleName)
350:                                    + "' (see server log for details)");
351:                    return;
352:                }
353:
354:                response.setContentType("text/html");
355:                PrintWriter writer = response.getWriter();
356:                writer.println("<html><head>");
357:                writer.print("<script language='javascript' src='");
358:                writer.print(parts.moduleName);
359:                writer.println(".nocache.js'></script>");
360:
361:                // Create a property for each query param.
362:                Map<String, String[]> params = request.getParameterMap();
363:                for (Map.Entry<String, String[]> entry : params.entrySet()) {
364:                    String[] values = entry.getValue();
365:                    if (values.length > 0) {
366:                        writer.print("<meta name='gwt:property' content='");
367:                        writer.print(entry.getKey());
368:                        writer.print("=");
369:                        writer.print(values[values.length - 1]);
370:                        writer.println("'>");
371:                    }
372:                }
373:
374:                writer.println("</head><body>");
375:                writer
376:                        .println("<iframe src=\"javascript:''\" id='__gwt_historyFrame' "
377:                                + "style='position:absolute;width:0;height:0;border:0'></iframe>");
378:                writer.println("</body></html>");
379:
380:                // Done.
381:            }
382:
383:            /**
384:             * Fetch a file and return it as the HTTP response, setting the cache-related
385:             * headers according to the name of the file (see
386:             * {@link #getCacheTime(String)}). This function honors If-Modified-Since to
387:             * minimize the impact of limiting caching of files for development.
388:             * 
389:             * @param request the HTTP request
390:             * @param response the HTTP response
391:             * @param logger a TreeLogger to use for debug output
392:             * @param partialPath the path within the module
393:             * @param moduleName the name of the module
394:             * @throws IOException
395:             */
396:            private void doGetPublicFile(HttpServletRequest request,
397:                    HttpServletResponse response, TreeLogger logger,
398:                    String partialPath, String moduleName) throws IOException {
399:
400:                // Create a logger branch for this request.
401:                String msg = "The development shell servlet received a request for '"
402:                        + partialPath
403:                        + "' in module '"
404:                        + moduleName
405:                        + ".gwt.xml' ";
406:                logger = logger.branch(TreeLogger.TRACE, msg, null);
407:
408:                // Handle auto-generation of resources.
409:                if (autoGenerateResources(request, response, logger,
410:                        partialPath, moduleName)) {
411:                    return;
412:                }
413:
414:                URL foundResource;
415:                try {
416:                    // Look for the requested file on the public path.
417:                    //
418:                    ModuleDef moduleDef = getModuleDef(logger, moduleName);
419:                    foundResource = moduleDef.findPublicFile(partialPath);
420:
421:                    if (foundResource == null) {
422:                        // Look in the place where we write compiled output.
423:                        File moduleDir = new File(getOutputDir(), moduleName);
424:                        File requestedFile = new File(moduleDir, partialPath);
425:                        if (requestedFile.exists()) {
426:                            try {
427:                                foundResource = requestedFile.toURI().toURL();
428:                            } catch (MalformedURLException e) {
429:                                // ignore since it was speculative anyway
430:                            }
431:                        }
432:
433:                        if (foundResource == null) {
434:                            msg = "Resource not found: "
435:                                    + partialPath
436:                                    + "\n"
437:                                    + "(Could a file be missing from the public path or a <servlet> "
438:                                    + "tag misconfigured in module "
439:                                    + moduleName + ".gwt.xml ?)";
440:                            logger.log(TreeLogger.WARN, msg, null);
441:                            throw new UnableToCompleteException();
442:                        }
443:                    }
444:                } catch (UnableToCompleteException e) {
445:                    sendErrorResponse(response,
446:                            HttpServletResponse.SC_NOT_FOUND,
447:                            "Cannot find resource '" + partialPath
448:                                    + "' in the public path of module '"
449:                                    + moduleName + "'");
450:                    return;
451:                }
452:
453:                // Get the MIME type.
454:                String path = foundResource.toExternalForm();
455:                String mimeType = null;
456:                try {
457:                    mimeType = getServletContext().getMimeType(path);
458:                } catch (UnsupportedOperationException e) {
459:                    // Certain minimalist servlet containers throw this.
460:                    // Fall through to guess the type.
461:                }
462:
463:                if (mimeType == null) {
464:                    mimeType = guessMimeType(path);
465:                    msg = "Guessed MIME type '" + mimeType + "'";
466:                    logger.log(TreeLogger.TRACE, msg, null);
467:                }
468:
469:                maybeIssueXhtmlWarning(logger, mimeType, partialPath);
470:
471:                long cacheSeconds = getCacheTime(path);
472:
473:                InputStream is = null;
474:                try {
475:                    // Check for up-to-datedness.
476:                    URLConnection conn = foundResource.openConnection();
477:                    long lastModified = conn.getLastModified();
478:                    if (isNotModified(request, lastModified)) {
479:                        response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
480:                        setResponseCacheHeaders(response, cacheSeconds);
481:                        return;
482:                    }
483:
484:                    // Set up headers to really send it.
485:                    response.setStatus(HttpServletResponse.SC_OK);
486:                    long now = new Date().getTime();
487:                    response.setHeader(HttpHeaders.DATE, HttpHeaders
488:                            .toInternetDateFormat(now));
489:                    response.setContentType(mimeType);
490:                    String lastModifiedStr = HttpHeaders
491:                            .toInternetDateFormat(lastModified);
492:                    response.setHeader(HttpHeaders.LAST_MODIFIED,
493:                            lastModifiedStr);
494:
495:                    // Expiration header. Either immediately stale (requiring an
496:                    // "If-Modified-Since") or infinitely cacheable (not requiring even a
497:                    // freshness check).
498:                    setResponseCacheHeaders(response, cacheSeconds);
499:
500:                    // Content length.
501:                    int contentLength = conn.getContentLength();
502:                    if (contentLength >= 0) {
503:                        response.setHeader(HttpHeaders.CONTENT_LENGTH, Integer
504:                                .toString(contentLength));
505:                    }
506:
507:                    // Send the bytes.
508:                    is = foundResource.openStream();
509:                    streamOut(is, response.getOutputStream(), 1024 * 8);
510:                } finally {
511:                    if (is != null) {
512:                        try {
513:                            is.close();
514:                        } catch (IOException swallowed) {
515:                            // Nothing we can do now.
516:                            //
517:                        }
518:                    }
519:                }
520:            }
521:
522:            /**
523:             * Generates a module.js file on the fly. Note that the nocache file that is
524:             * generated that can only be used for hosted mode. It cannot produce a web
525:             * mode version, since this servlet doesn't know strong names, since by
526:             * definition of "hosted mode" JavaScript hasn't been compiled at this point.
527:             */
528:            private String genSelectionScript(TreeLogger logger,
529:                    String moduleName, boolean asScript)
530:                    throws UnableToCompleteException {
531:                String msg = asScript ? "Generating a script selection script for module "
532:                        : "Generating an html selection script for module ";
533:                msg += moduleName;
534:                logger.log(TreeLogger.TRACE, msg, null);
535:
536:                ModuleDef moduleDef = getModuleDef(logger, moduleName);
537:                SelectionScriptGenerator gen = new SelectionScriptGenerator(
538:                        moduleDef);
539:                return gen.generateSelectionScript(false, asScript);
540:            }
541:
542:            /**
543:             * Get the length of time a given file should be cacheable. If the path
544:             * contains *.nocache.*, it is never cacheable; if it contains *.cache.*, it
545:             * is infinitely cacheable; anything else gets a default time.
546:             * 
547:             * @return cache time in seconds, or 0 if the file is not cacheable at all
548:             */
549:            private long getCacheTime(String path) {
550:                int lastDot = path.lastIndexOf('.');
551:                if (lastDot >= 0) {
552:                    String prefix = path.substring(0, lastDot);
553:                    if (prefix.endsWith(".cache")) {
554:                        // RFC2616 says to never give a cache time of more than a year
555:                        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21
556:                        return HttpHeaders.SEC_YR;
557:                    } else if (prefix.endsWith(".nocache")) {
558:                        return 0;
559:                    }
560:                }
561:                return DEFAULT_CACHE_SECONDS;
562:            }
563:
564:            private synchronized TreeLogger getLogger() {
565:                if (topLogger == null) {
566:                    ServletContext servletContext = getServletContext();
567:                    final String attr = "com.google.gwt.dev.shell.logger";
568:                    topLogger = (TreeLogger) servletContext.getAttribute(attr);
569:                    if (topLogger == null) {
570:                        // No shell available, so wrap the regular servlet context logger.
571:                        //
572:                        topLogger = new ServletContextTreeLogger(servletContext);
573:                    }
574:                }
575:                return topLogger;
576:            }
577:
578:            /**
579:             * We don't actually log this on purpose since the client does anyway.
580:             */
581:            private ModuleDef getModuleDef(TreeLogger logger, String moduleName)
582:                    throws UnableToCompleteException {
583:                synchronized (loadedModulesByName) {
584:                    ModuleDef moduleDef = loadedModulesByName.get(moduleName);
585:                    if (moduleDef == null) {
586:                        moduleDef = ModuleDefLoader.loadFromClassPath(logger,
587:                                moduleName);
588:                        loadedModulesByName.put(moduleName, moduleDef);
589:
590:                        // BEGIN BACKWARD COMPATIBILITY
591:                        // The following map of servlet path to module is included only
592:                        // for backward-compatibility. We are going to remove this functionality
593:                        // when we go out of beta. The new behavior is that the client should
594:                        // specify the module name as part of the URL and construct it using
595:                        // getModuleBaseURL().
596:                        String[] servletPaths = moduleDef.getServletPaths();
597:                        for (int i = 0; i < servletPaths.length; i++) {
598:                            ModuleDef oldDef = modulesByServletPath.put(
599:                                    servletPaths[i], moduleDef);
600:                            if (oldDef != null) {
601:                                logger.log(TreeLogger.WARN,
602:                                        "Undefined behavior: Servlet path "
603:                                                + servletPaths[i]
604:                                                + " conflicts in modules "
605:                                                + moduleDef.getName() + " and "
606:                                                + oldDef.getName(), null);
607:                            }
608:                        }
609:                        // END BACKWARD COMPATIBILITY
610:                    }
611:                    return moduleDef;
612:                }
613:            }
614:
615:            private synchronized File getOutputDir() {
616:                if (outDir == null) {
617:                    ServletContext servletContext = getServletContext();
618:                    final String attr = "com.google.gwt.dev.shell.outdir";
619:                    outDir = (File) servletContext.getAttribute(attr);
620:                    assert (outDir != null);
621:                }
622:                return outDir;
623:            }
624:
625:            private String guessMimeType(String fullPath) {
626:                int dot = fullPath.lastIndexOf('.');
627:                if (dot != -1) {
628:                    String ext = fullPath.substring(dot + 1);
629:                    String mimeType = mimeTypes.get(ext);
630:                    if (mimeType != null) {
631:                        return mimeType;
632:                    }
633:
634:                    // Otherwise, fall through.
635:                    //
636:                }
637:
638:                // Last resort.
639:                //
640:                return "application/octet-stream";
641:            }
642:
643:            private void initMimeTypes() {
644:                mimeTypes.put("abs", "audio/x-mpeg");
645:                mimeTypes.put("ai", "application/postscript");
646:                mimeTypes.put("aif", "audio/x-aiff");
647:                mimeTypes.put("aifc", "audio/x-aiff");
648:                mimeTypes.put("aiff", "audio/x-aiff");
649:                mimeTypes.put("aim", "application/x-aim");
650:                mimeTypes.put("art", "image/x-jg");
651:                mimeTypes.put("asf", "video/x-ms-asf");
652:                mimeTypes.put("asx", "video/x-ms-asf");
653:                mimeTypes.put("au", "audio/basic");
654:                mimeTypes.put("avi", "video/x-msvideo");
655:                mimeTypes.put("avx", "video/x-rad-screenplay");
656:                mimeTypes.put("bcpio", "application/x-bcpio");
657:                mimeTypes.put("bin", "application/octet-stream");
658:                mimeTypes.put("bmp", "image/bmp");
659:                mimeTypes.put("body", "text/html");
660:                mimeTypes.put("cdf", "application/x-cdf");
661:                mimeTypes.put("cer", "application/x-x509-ca-cert");
662:                mimeTypes.put("class", "application/java");
663:                mimeTypes.put("cpio", "application/x-cpio");
664:                mimeTypes.put("csh", "application/x-csh");
665:                mimeTypes.put("css", "text/css");
666:                mimeTypes.put("dib", "image/bmp");
667:                mimeTypes.put("doc", "application/msword");
668:                mimeTypes.put("dtd", "text/plain");
669:                mimeTypes.put("dv", "video/x-dv");
670:                mimeTypes.put("dvi", "application/x-dvi");
671:                mimeTypes.put("eps", "application/postscript");
672:                mimeTypes.put("etx", "text/x-setext");
673:                mimeTypes.put("exe", "application/octet-stream");
674:                mimeTypes.put("gif", "image/gif");
675:                mimeTypes.put("gtar", "application/x-gtar");
676:                mimeTypes.put("gz", "application/x-gzip");
677:                mimeTypes.put("hdf", "application/x-hdf");
678:                mimeTypes.put("hqx", "application/mac-binhex40");
679:                mimeTypes.put("htc", "text/x-component");
680:                mimeTypes.put("htm", "text/html");
681:                mimeTypes.put("html", "text/html");
682:                mimeTypes.put("hqx", "application/mac-binhex40");
683:                mimeTypes.put("ief", "image/ief");
684:                mimeTypes.put("jad", "text/vnd.sun.j2me.app-descriptor");
685:                mimeTypes.put("jar", "application/java-archive");
686:                mimeTypes.put("java", "text/plain");
687:                mimeTypes.put("jnlp", "application/x-java-jnlp-file");
688:                mimeTypes.put("jpe", "image/jpeg");
689:                mimeTypes.put("jpeg", "image/jpeg");
690:                mimeTypes.put("jpg", "image/jpeg");
691:                mimeTypes.put("js", "text/javascript");
692:                mimeTypes.put("jsf", "text/plain");
693:                mimeTypes.put("jspf", "text/plain");
694:                mimeTypes.put("kar", "audio/x-midi");
695:                mimeTypes.put("latex", "application/x-latex");
696:                mimeTypes.put("m3u", "audio/x-mpegurl");
697:                mimeTypes.put("mac", "image/x-macpaint");
698:                mimeTypes.put("man", "application/x-troff-man");
699:                mimeTypes.put("me", "application/x-troff-me");
700:                mimeTypes.put("mid", "audio/x-midi");
701:                mimeTypes.put("midi", "audio/x-midi");
702:                mimeTypes.put("mif", "application/x-mif");
703:                mimeTypes.put("mov", "video/quicktime");
704:                mimeTypes.put("movie", "video/x-sgi-movie");
705:                mimeTypes.put("mp1", "audio/x-mpeg");
706:                mimeTypes.put("mp2", "audio/x-mpeg");
707:                mimeTypes.put("mp3", "audio/x-mpeg");
708:                mimeTypes.put("mpa", "audio/x-mpeg");
709:                mimeTypes.put("mpe", "video/mpeg");
710:                mimeTypes.put("mpeg", "video/mpeg");
711:                mimeTypes.put("mpega", "audio/x-mpeg");
712:                mimeTypes.put("mpg", "video/mpeg");
713:                mimeTypes.put("mpv2", "video/mpeg2");
714:                mimeTypes.put("ms", "application/x-wais-source");
715:                mimeTypes.put("nc", "application/x-netcdf");
716:                mimeTypes.put("oda", "application/oda");
717:                mimeTypes.put("pbm", "image/x-portable-bitmap");
718:                mimeTypes.put("pct", "image/pict");
719:                mimeTypes.put("pdf", "application/pdf");
720:                mimeTypes.put("pgm", "image/x-portable-graymap");
721:                mimeTypes.put("pic", "image/pict");
722:                mimeTypes.put("pict", "image/pict");
723:                mimeTypes.put("pls", "audio/x-scpls");
724:                mimeTypes.put("png", "image/png");
725:                mimeTypes.put("pnm", "image/x-portable-anymap");
726:                mimeTypes.put("pnt", "image/x-macpaint");
727:                mimeTypes.put("ppm", "image/x-portable-pixmap");
728:                mimeTypes.put("ppt", "application/powerpoint");
729:                mimeTypes.put("ps", "application/postscript");
730:                mimeTypes.put("psd", "image/x-photoshop");
731:                mimeTypes.put("qt", "video/quicktime");
732:                mimeTypes.put("qti", "image/x-quicktime");
733:                mimeTypes.put("qtif", "image/x-quicktime");
734:                mimeTypes.put("ras", "image/x-cmu-raster");
735:                mimeTypes.put("rgb", "image/x-rgb");
736:                mimeTypes.put("rm", "application/vnd.rn-realmedia");
737:                mimeTypes.put("roff", "application/x-troff");
738:                mimeTypes.put("rtf", "application/rtf");
739:                mimeTypes.put("rtx", "text/richtext");
740:                mimeTypes.put("sh", "application/x-sh");
741:                mimeTypes.put("shar", "application/x-shar");
742:                mimeTypes.put("smf", "audio/x-midi");
743:                mimeTypes.put("sit", "application/x-stuffit");
744:                mimeTypes.put("snd", "audio/basic");
745:                mimeTypes.put("src", "application/x-wais-source");
746:                mimeTypes.put("sv4cpio", "application/x-sv4cpio");
747:                mimeTypes.put("sv4crc", "application/x-sv4crc");
748:                mimeTypes.put("swf", "application/x-shockwave-flash");
749:                mimeTypes.put("t", "application/x-troff");
750:                mimeTypes.put("tar", "application/x-tar");
751:                mimeTypes.put("tcl", "application/x-tcl");
752:                mimeTypes.put("tex", "application/x-tex");
753:                mimeTypes.put("texi", "application/x-texinfo");
754:                mimeTypes.put("texinfo", "application/x-texinfo");
755:                mimeTypes.put("tif", "image/tiff");
756:                mimeTypes.put("tiff", "image/tiff");
757:                mimeTypes.put("tr", "application/x-troff");
758:                mimeTypes.put("tsv", "text/tab-separated-values");
759:                mimeTypes.put("txt", "text/plain");
760:                mimeTypes.put("ulw", "audio/basic");
761:                mimeTypes.put("ustar", "application/x-ustar");
762:                mimeTypes.put("xbm", "image/x-xbitmap");
763:                mimeTypes.put("xht", "application/xhtml+xml");
764:                mimeTypes.put("xhtml", "application/xhtml+xml");
765:                mimeTypes.put("xml", "text/xml");
766:                mimeTypes.put("xpm", "image/x-xpixmap");
767:                mimeTypes.put("xsl", "text/xml");
768:                mimeTypes.put("xwd", "image/x-xwindowdump");
769:                mimeTypes.put("wav", "audio/x-wav");
770:                mimeTypes.put("svg", "image/svg+xml");
771:                mimeTypes.put("svgz", "image/svg+xml");
772:                mimeTypes.put("vsd", "application/x-visio");
773:                mimeTypes.put("wbmp", "image/vnd.wap.wbmp");
774:                mimeTypes.put("wml", "text/vnd.wap.wml");
775:                mimeTypes.put("wmlc", "application/vnd.wap.wmlc");
776:                mimeTypes.put("wmls", "text/vnd.wap.wmlscript");
777:                mimeTypes.put("wmlscriptc", "application/vnd.wap.wmlscriptc");
778:                mimeTypes.put("wrl", "x-world/x-vrml");
779:                mimeTypes.put("Z", "application/x-compress");
780:                mimeTypes.put("z", "application/x-compress");
781:                mimeTypes.put("zip", "application/zip");
782:            }
783:
784:            /**
785:             * Checks to see whether or not a client's file is out of date relative to the
786:             * original.
787:             */
788:            private boolean isNotModified(HttpServletRequest request,
789:                    long ageOfServerCopy) {
790:                // The age of the server copy *must* have the milliseconds truncated.
791:                // Since milliseconds isn't part of the GMT format, failure to truncate
792:                // will leave the file in a state where it appears constantly out of date
793:                // and yet it can never get in sync because the Last-Modified date keeps
794:                // truncating off the milliseconds part on its way out.
795:                // 
796:                ageOfServerCopy -= (ageOfServerCopy % 1000);
797:
798:                long ageOfClientCopy = 0;
799:                String ifModifiedSince = request.getHeader("If-Modified-Since");
800:                if (ifModifiedSince != null) {
801:                    // Rip off any additional stuff at the end, such as "; length="
802:                    // (IE does add this).
803:                    //
804:                    int lastSemi = ifModifiedSince.lastIndexOf(';');
805:                    if (lastSemi != -1) {
806:                        ifModifiedSince = ifModifiedSince
807:                                .substring(0, lastSemi);
808:                    }
809:                    ageOfClientCopy = HttpHeaders
810:                            .fromInternetDateFormat(ifModifiedSince);
811:                }
812:
813:                if (ageOfClientCopy >= ageOfServerCopy) {
814:                    // The client already has a good copy.
815:                    //
816:                    return true;
817:                } else {
818:                    // The client needs a fresh copy of the requested file.
819:                    //
820:                    return false;
821:                }
822:            }
823:
824:            private void maybeIssueXhtmlWarning(TreeLogger logger,
825:                    String mimeType, String path) {
826:                if (!XHTML_MIME_TYPE.equals(mimeType)) {
827:                    return;
828:                }
829:
830:                String msg = "File was returned with content-type of \""
831:                        + mimeType
832:                        + "\". GWT requires browser features that are not available to "
833:                        + "documents with this content-type.";
834:
835:                int ix = path.lastIndexOf('.');
836:                if (ix >= 0 && ix < path.length()) {
837:                    String base = path.substring(0, ix);
838:                    msg += " Consider renaming \"" + path + "\" to \"" + base
839:                            + ".html\".";
840:                }
841:
842:                logger.log(TreeLogger.WARN, msg, null);
843:            }
844:
845:            private void sendErrorResponse(HttpServletResponse response,
846:                    int statusCode, String msg) throws IOException {
847:                response.setContentType("text/html");
848:                response.getWriter().println(msg);
849:                response.setStatus(statusCode);
850:            }
851:
852:            /**
853:             * Sets the Cache-control and Expires headers in the response based on the
854:             * supplied cache time.
855:             * 
856:             * Expires is used in addition to Cache-control for older clients or proxies
857:             * which may not properly understand Cache-control.
858:             * 
859:             * @param response the HttpServletResponse to update
860:             * @param cacheTime non-negative number of seconds to cache the response; 0
861:             *          means specifically do not allow caching at all.
862:             * @throws IllegalArgumentException if cacheTime is negative
863:             */
864:            private void setResponseCacheHeaders(HttpServletResponse response,
865:                    long cacheTime) {
866:                long expires;
867:                if (cacheTime < 0) {
868:                    throw new IllegalArgumentException("cacheTime of "
869:                            + cacheTime + " is negative");
870:                }
871:                if (cacheTime > 0) {
872:                    // Expire the specified seconds in the future.
873:                    expires = new Date().getTime() + cacheTime
874:                            * HttpHeaders.MS_SEC;
875:                } else {
876:                    // Prevent caching by using a time in the past for cache expiration.
877:                    // Use January 2, 1970 00:00:00, to account for timezone changes
878:                    // in case a browser tries to convert to a local timezone first
879:                    // 0=Jan 1, so add 1 day's worth of milliseconds to get Jan 2
880:                    expires = HttpHeaders.SEC_DAY * HttpHeaders.MS_SEC;
881:                }
882:                response.setHeader(HttpHeaders.CACHE_CONTROL,
883:                        HttpHeaders.CACHE_CONTROL_MAXAGE + cacheTime);
884:                String expiresString = HttpHeaders
885:                        .toInternetDateFormat(expires);
886:                response.setHeader(HttpHeaders.EXPIRES, expiresString);
887:            }
888:
889:            private void streamOut(InputStream in, OutputStream out,
890:                    int bufferSize) throws IOException {
891:                assert (bufferSize >= 0);
892:
893:                byte[] buffer = new byte[bufferSize];
894:                int bytesRead = 0;
895:                while (true) {
896:                    bytesRead = in.read(buffer);
897:                    if (bytesRead >= 0) {
898:                        // Copy the bytes out.
899:                        out.write(buffer, 0, bytesRead);
900:                    } else {
901:                        // End of input stream.
902:                        return;
903:                    }
904:                }
905:            }
906:
907:            private HttpServlet tryGetOrLoadServlet(TreeLogger logger,
908:                    ModuleDef moduleDef, String className) {
909:                synchronized (loadedServletsByModuleAndClassName) {
910:                    String moduleAndClassName = moduleDef.getName() + "/"
911:                            + className;
912:                    HttpServlet servlet = loadedServletsByModuleAndClassName
913:                            .get(moduleAndClassName);
914:                    if (servlet != null) {
915:                        // Found it.
916:                        //
917:                        return servlet;
918:                    }
919:
920:                    // Try to load and instantiate it.
921:                    //
922:                    Throwable caught = null;
923:                    try {
924:                        Class<?> servletClass = Class.forName(className);
925:                        Object newInstance = servletClass.newInstance();
926:                        if (!(newInstance instanceof  HttpServlet)) {
927:                            logger
928:                                    .log(
929:                                            TreeLogger.ERROR,
930:                                            "Not compatible with HttpServlet: "
931:                                                    + className
932:                                                    + " (does your service extend RemoteServiceServlet?)",
933:                                            null);
934:                            return null;
935:                        }
936:
937:                        // Success. Hang onto the instance so we can reuse it.
938:                        //
939:                        servlet = (HttpServlet) newInstance;
940:
941:                        // We create proxies for ServletContext and ServletConfig to enable
942:                        // RemoteServiceServlets to load public and generated resources via
943:                        // ServeletContext.getResourceAsStream()
944:                        //
945:                        ServletContext context = new HostedModeServletContextProxy(
946:                                getServletContext(), moduleDef, getOutputDir());
947:                        ServletConfig config = new HostedModeServletConfigProxy(
948:                                getServletConfig(), context);
949:
950:                        servlet.init(config);
951:
952:                        loadedServletsByModuleAndClassName.put(
953:                                moduleAndClassName, servlet);
954:                        return servlet;
955:                    } catch (ClassNotFoundException e) {
956:                        caught = e;
957:                    } catch (InstantiationException e) {
958:                        caught = e;
959:                    } catch (IllegalAccessException e) {
960:                        caught = e;
961:                    } catch (ServletException e) {
962:                        caught = e;
963:                    }
964:                    String msg = "Unable to instantiate '" + className + "'";
965:                    logger.log(TreeLogger.ERROR, msg, caught);
966:                    return null;
967:                }
968:            }
969:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.