comparison src/fschmidt/util/servlet/JtpContextServlet.java @ 68:00520880ad02

add fschmidt source
author Franklin Schmidt <fschmidt@gmail.com>
date Sun, 05 Oct 2025 17:24:15 -0600
parents
children
comparison
equal deleted inserted replaced
67:9d0fefce6985 68:00520880ad02
1 /*
2 Copyright (c) 2008 Franklin Schmidt <fschmidt@gmail.com>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22
23 package fschmidt.util.servlet;
24
25 import fschmidt.util.java.ProcUtils;
26 import fschmidt.util.java.SimpleClassLoader;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import javax.servlet.ServletContext;
31 import javax.servlet.ServletException;
32 import javax.servlet.ServletOutputStream;
33 import javax.servlet.http.HttpServlet;
34 import javax.servlet.http.HttpServletRequest;
35 import javax.servlet.http.HttpServletResponse;
36 import javax.servlet.http.HttpServletResponseWrapper;
37 import java.io.File;
38 import java.io.IOException;
39 import java.io.PrintWriter;
40 import java.net.URL;
41 import java.util.Arrays;
42 import java.util.Collection;
43 import java.util.Collections;
44 import java.util.HashMap;
45 import java.util.HashSet;
46 import java.util.LinkedHashMap;
47 import java.util.LinkedList;
48 import java.util.Map;
49 import java.util.Set;
50
51
52 public final class JtpContextServlet extends HttpServlet implements JtpContext {
53 private static final Logger logger = LoggerFactory.getLogger(JtpContextServlet.class);
54
55 private static final Set<String> allowedMethods = new HashSet<String>(Arrays.asList(
56 "GET", "POST", "HEAD"
57 ));
58 private String base;
59 private boolean reload = false;
60 private boolean recompile = false;
61 private SimpleClassLoader.Filter filter = null;
62 private ClassLoader cl = null;
63 private Map<String,HttpServlet> map = new HashMap<String,HttpServlet>();
64 private long clTime;
65 private Object lock = new Object();
66 private HttpCache httpCache;
67 private boolean isCaching;
68 private String characterEncoding;
69 private Map<String, String> customHeaders = new HashMap<String, String>();
70 private UrlMapper urlMapper = new UrlMapper() {
71 public UrlMapping getUrlMapping(HttpServletRequest request) {
72 return null;
73 }
74 };
75 private Set<String> errorCache = null;
76 private Collection<String> ipList = null;
77 private static final String authKeyAttr = "authKey";
78 private static final String[] noModifyingEvents = new String[]{"_"};
79
80 public void setUrlMapper(UrlMapper urlMapper) {
81 this.urlMapper = urlMapper;
82 }
83
84 public HttpCache getHttpCache() {
85 return httpCache;
86 }
87
88 public void setHttpCache(HttpCache httpCache) {
89 this.httpCache = httpCache;
90 }
91
92 public void addCustomHeader(String key, String value) {
93 this.customHeaders.put(key, value);
94 }
95
96 public void unloadServlets() {
97 if( !reload )
98 throw new UnsupportedOperationException("'reload' must be set");
99 synchronized(lock) {
100 cl = new SimpleClassLoader(filter);
101 map = new HashMap<String,HttpServlet>();
102 clTime = System.currentTimeMillis();
103 }
104 }
105
106 public void setBase(String base) {
107 if( base==null )
108 throw new NullPointerException();
109 this.base = base;
110 }
111
112 public void init()
113 throws ServletException
114 {
115 ServletContext context = getServletContext();
116 String newBase = getInitParameter("base");
117 if( newBase != null )
118 setBase(newBase);
119 recompile = Boolean.valueOf(getInitParameter("recompile"));
120 reload = recompile || Boolean.valueOf(getInitParameter("reload"));
121 if( reload ) {
122 filter = new SimpleClassLoader.Filter(){
123 final String s = base + ".";
124 public boolean load(String className) {
125 return className.startsWith(s);
126 }
127 };
128 unloadServlets();
129 }
130 context.setAttribute(JtpContext.attrName,this);
131 String servletS = getInitParameter("servlet");
132 if( servletS != null ) {
133 throw new RuntimeException("the 'servlet' init parameter is no longer supported");
134 }
135 isCaching = "true".equalsIgnoreCase(getInitParameter("cache"));
136 if( isCaching ) {
137 if( httpCache==null ) {
138 logger.error("can't set init parameter 'cache' to true without httpCache");
139 System.exit(-1);
140 }
141 logger.info("cache");
142 }
143 characterEncoding = getInitParameter("characterEncoding");
144 {
145 String s = getInitParameter("timeLimit");
146 if( s != null )
147 timeLimit = Long.parseLong(s);
148 }
149 {
150 String s = getInitParameter("errorCacheSize");
151 if( s != null ) {
152 final int errorCacheSize = Integer.parseInt(s);
153 errorCache = Collections.synchronizedSet(Collections.newSetFromMap(new LinkedHashMap<String,Boolean>(){
154 protected boolean removeEldestEntry(Map.Entry eldest) {
155 return size() > errorCacheSize;
156 }
157 }));
158 }
159 }
160 {
161 String s = getInitParameter("ipListSize");
162 if( s != null ) {
163 final int ipListSize = Integer.parseInt(s);
164 ipList = Collections.synchronizedList(new LinkedList<String>() {
165 public boolean add(String s) {
166 if( contains(s) )
167 return false;
168 super.add(s);
169 if( size() > ipListSize )
170 removeFirst();
171 return true;
172 }
173 });
174 }
175 }
176 }
177
178 private boolean isInErrorCache(String s) {
179 return errorCache==null || !errorCache.add(s);
180 }
181
182 private boolean isInIpList(String ip) {
183 return ipList!=null && !ipList.add(ip);
184 }
185
186 public static interface DestroyListener {
187 public void destroyed();
188 }
189
190 private DestroyListener destroyListener = null;
191
192 public void addDestroyListener(DestroyListener dl) {
193 synchronized(lock) {
194 if( destroyListener!=null )
195 throw new RuntimeException("only one DestroyListener allowed");
196 destroyListener = dl;
197 }
198 }
199
200 public void destroy() {
201 synchronized(lock) {
202 if( destroyListener != null )
203 destroyListener.destroyed();
204 }
205 }
206
207 public static final class RequestAndResponse {
208 public final HttpServletRequest request;
209 public final HttpServletResponse response;
210
211 public RequestAndResponse(HttpServletRequest request,HttpServletResponse response) {
212 this.request = request;
213 this.response = response;
214 }
215 }
216
217 public static interface CustomWrappers {
218 public RequestAndResponse wrap(HttpServletRequest request, HttpServletResponse response);
219 }
220
221 private CustomWrappers customWrappers;
222
223 public void setCustomWrappers(CustomWrappers customWrappers) {
224 this.customWrappers = customWrappers;
225 }
226
227 private static String hideNull(String s) {
228 return s==null ? "" : s;
229 }
230
231 private String getServletPath(HttpServletRequest request) {
232 return request.getServletPath() + hideNull(request.getPathInfo());
233 }
234
235 protected void service(HttpServletRequest request,HttpServletResponse response)
236 throws ServletException, IOException
237 {
238 final TimeLimit tl = startTimeLimit(request);
239 response = new HttpServletResponseWrapper(response) {
240 PrintWriter writer = null;
241 ServletOutputStream out = null;
242
243 public PrintWriter getWriter()
244 throws java.io.IOException
245 {
246 if( writer==null ) {
247 writer = new PrintWriter(super.getWriter()) {
248 public void write(String s,int off,int len) {
249 long t = System.currentTimeMillis();
250 super.write(s,off,len);
251 tl.ioTime += System.currentTimeMillis() - t;
252 }
253 public void write(char[] buf,int off,int len) {
254 long t = System.currentTimeMillis();
255 super.write(buf,off,len);
256 tl.ioTime += System.currentTimeMillis() - t;
257 }
258 public void write(int c) {
259 long t = System.currentTimeMillis();
260 super.write(c);
261 tl.ioTime += System.currentTimeMillis() - t;
262 }
263 public void flush() {
264 long t = System.currentTimeMillis();
265 super.flush();
266 tl.ioTime += System.currentTimeMillis() - t;
267 }
268 public void println() {
269 long t = System.currentTimeMillis();
270 super.println();
271 tl.ioTime += System.currentTimeMillis() - t;
272 }
273 };
274 }
275 return writer;
276 }
277
278 public ServletOutputStream getOutputStream()
279 throws java.io.IOException
280 {
281 if( out==null ) {
282 final ServletOutputStream sos = super.getOutputStream();
283 out = new ServletOutputStream() {
284 public void write(byte[] b,int off,int len) throws IOException {
285 long t = System.currentTimeMillis();
286 sos.write(b,off,len);
287 tl.ioTime += System.currentTimeMillis() - t;
288 }
289 public void write(byte[] b) throws IOException {
290 long t = System.currentTimeMillis();
291 sos.write(b);
292 tl.ioTime += System.currentTimeMillis() - t;
293 }
294 public void write(int c) throws IOException {
295 long t = System.currentTimeMillis();
296 sos.write(c);
297 tl.ioTime += System.currentTimeMillis() - t;
298 }
299 public void flush() throws IOException {
300 long t = System.currentTimeMillis();
301 sos.flush();
302 tl.ioTime += System.currentTimeMillis() - t;
303 }
304 };
305 }
306 return out;
307 }
308
309 public void sendError(int sc) throws IOException {
310 long t = System.currentTimeMillis();
311 super.sendError(sc);
312 tl.ioTime += System.currentTimeMillis() - t;
313 }
314
315 public void sendRedirect(String location) throws IOException {
316 if( containsHeader("Expires") )
317 setHeader("Expires",null);
318 if( containsHeader("Last-Modified") )
319 setHeader("Last-Modified",null);
320 if( containsHeader("Etag") )
321 setHeader("Etag",null);
322 if( containsHeader("Cache-Control") )
323 setHeader("Cache-Control",null);
324 if( containsHeader("Content-Type") )
325 setHeader("Content-Type",null);
326 if( containsHeader("Content-Length") )
327 // setHeader("Content-Length",null);
328 setContentLength(0);
329 super.sendRedirect(location);
330 }
331 };
332 service2(request,response);
333 checkTimeLimit(request);
334 }
335
336 private void service2(HttpServletRequest request, HttpServletResponse response)
337 throws ServletException, IOException
338 {
339 if( !allowedMethods.contains(request.getMethod()) ) {
340 response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
341 return;
342 }
343 // String contextPath = request.getContextPath();
344 // String contextUrl = ServletUtils.getContextURL(request);
345
346 // First we set the character encoding because any manipulation
347 // of request parameters will break without this.
348 response.setHeader("Content-Type","text/html; charset=utf-8"); // default, servlet can override
349 if( characterEncoding != null ) {
350 response.setCharacterEncoding(characterEncoding);
351 request.setCharacterEncoding(characterEncoding);
352 }
353
354 HttpServlet servlet;
355 String path = getServletPath(request);
356
357 UrlMapping urlMapping = urlMapper.getUrlMapping(request);
358 if( urlMapping != null ) {
359 try {
360 servlet = getServletFromClass(urlMapping.servletClass.getName());
361 } catch(ClassNotFoundException e) {
362 throw new RuntimeException(e);
363 }
364 final Map params = urlMapping.parameterMap;
365 request = new BetterRequestWrapper(request) {
366 public Map getParameterMap() {
367 return params;
368 }
369 };
370 } else {
371 try {
372 servlet = getServlet(path);
373 } catch(ClassNotFoundException e) {
374 response.sendError(HttpServletResponse.SC_NOT_FOUND);
375 String agent = request.getHeader("user-agent");
376 String referer = request.getHeader("referer");
377 String remote = request.getRemoteAddr();
378 String msg = request.getRequestURL()+" referer="+referer+" user-agent="+agent+" remote="+remote;
379 if( referer==null ) {
380 logger.info(msg,e);
381 } else {
382 logger.warn(msg,e);
383 }
384 return;
385 }
386 }
387
388 // Custom headers
389 addCustomHeaders(response);
390
391 AuthorizingServlet auth = servlet instanceof AuthorizingServlet ? (AuthorizingServlet)servlet : null;
392 if( isCaching ) {
393 String etagS = request.getHeader("If-None-Match");
394 if( etagS != null ) {
395 String prevEtag = null;
396 for( String etag : etagS.split("\\s*,\\s*") ) {
397 if( etag.equals(prevEtag) )
398 continue;
399 prevEtag = etag;
400 if( etag.length()>=2 && etag.charAt(0)=='"' && etag.charAt(etag.length()-1)=='"' )
401 etag = etag.substring(1,etag.length()-1);
402 String authKey = null;
403 if( etag.length()>=2 && etag.charAt(0)=='[' ) {
404 int i = etag.indexOf(']');
405 if( i > 0 ) {
406 if( auth != null )
407 authKey = etag.substring(1,i);
408 etag = etag.substring(i+1);
409 }
410 }
411 String[] events = etag.split("~");
412 long lastModified = getLastModified(events);
413 try {
414 if( lastModified <= request.getDateHeader("If-Modified-Since") ) {
415 if( authKey==null || authorize(auth,authKey,request,response) )
416 response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
417 return;
418 }
419 } catch(RuntimeException e) {
420 handleException(request,e);
421 }
422 }
423 }
424 }
425 String authKey = auth==null ? null : getAuthorizationKey(auth,request);
426 if( authKey != null ) {
427 if( !authorize(auth,authKey,request,response) )
428 return;
429 request.setAttribute(authKeyAttr,authKey);
430 }
431
432 if( servlet instanceof CanonicalUrl ) {
433 CanonicalUrl srv = (CanonicalUrl)servlet;
434 StringBuffer currentUrl = request.getRequestURL();
435 int i = currentUrl.indexOf(";");
436 if( i != -1 )
437 currentUrl.setLength(i);
438 String query = request.getQueryString();
439 if( query != null )
440 currentUrl.append( '?' ).append( query );
441 try {
442 String canonicalUrl = srv.getCanonicalUrl(request);
443 if( canonicalUrl != null && !currentUrl.toString().equals(canonicalUrl) ) {
444 response.setHeader("Location",canonicalUrl);
445 response.sendError( HttpServletResponse.SC_MOVED_PERMANENTLY );
446 return;
447 }
448 } catch(RuntimeException e) {
449 logger.warn("couldn't get canonical url",e);
450 }
451 }
452
453 request.setAttribute("servlet",servlet);
454
455 try {
456 if (customWrappers != null) {
457 RequestAndResponse rr = customWrappers.wrap(request, response);
458 request = rr.request;
459 response = rr.response;
460 }
461 servlet.service(request,response);
462 } catch(RuntimeException e) {
463 handleException(request,e);
464 } catch(ServletException e) {
465 handleException(request,e);
466 }
467 }
468
469 public void setEtag( HttpServletRequest request, HttpServletResponse response, String... modifyingEvents ) {
470 if( modifyingEvents.length == 0 )
471 modifyingEvents = noModifyingEvents;
472 StringBuilder buf = new StringBuilder();
473 String authKey = (String)request.getAttribute(authKeyAttr);
474 if( authKey != null )
475 buf.append( '[' ).append( authKey).append( ']' );
476 buf.append( modifyingEvents[0] );
477 for( int i=1; i<modifyingEvents.length; i++ ) {
478 buf.append( '~' ).append( modifyingEvents[i] );
479 }
480 response.setHeader("Etag",buf.toString());
481 long lastModified = getLastModified(modifyingEvents);
482 response.setDateHeader("Last-Modified",lastModified);
483 response.setHeader("Cache-Control","max-age=0");
484 }
485
486 private boolean authorize(AuthorizingServlet auth,String authKey,HttpServletRequest request,HttpServletResponse response)
487 throws IOException, ServletException
488 {
489 try {
490 if (customWrappers != null) {
491 RequestAndResponse rr = customWrappers.wrap(request, response);
492 request = rr.request;
493 response = rr.response;
494 }
495 return auth.authorize(authKey,request,response);
496 } catch(RuntimeException e) {
497 handleException(request,e);
498 } catch(ServletException e) {
499 handleException(request,e);
500 }
501 throw new RuntimeException("never");
502 }
503
504 private String getAuthorizationKey(AuthorizingServlet auth,HttpServletRequest request)
505 throws ServletException
506 {
507 try {
508 return auth.getAuthorizationKey(request);
509 } catch(RuntimeException e) {
510 handleException(request,e);
511 } catch(ServletException e) {
512 handleException(request,e);
513 }
514 return null; // never gets here
515 }
516
517 private long getLastModified(String[] modifyingEvents) {
518 long[] lastModifieds = httpCache.lastModifieds(modifyingEvents);
519 long lastModified = lastModifieds[0];
520 for( int i=1; i<lastModifieds.length; i++ ) {
521 long lm = lastModifieds[i];
522 if( lastModified < lm )
523 lastModified = lm;
524 }
525 return lastModified;
526 }
527
528 /** Adds all custom headers to the response object. */
529 private void addCustomHeaders(HttpServletResponse response) {
530 Set<Map.Entry<String, String>> entries = this.customHeaders.entrySet();
531 for (Map.Entry<String, String> entry : entries) {
532 response.setHeader(entry.getKey(), entry.getValue());
533 }
534 }
535
536 private void handleException(HttpServletRequest request,RuntimeException e)
537 throws ServletException
538 {
539 JtpRuntimeException rte;
540 try {
541 String agent = request.getHeader("user-agent");
542 if( agent == null )
543 throw new JtpServletException(request,"null agent",e);
544 if (!isValidAgent(agent))
545 throw new JtpServletException(request, "bad agent " + agent, e);
546 String remote = request.getRemoteAddr();
547 String referer = request.getHeader("referer");
548 StringBuilder buf = new StringBuilder()
549 .append( "method=" ).append( request.getMethod() )
550 .append( " user-agent=" ).append( agent )
551 .append( " referer=" ).append( referer )
552 .append( " remote=" ).append( remote )
553 ;
554 String etag = request.getHeader("If-None-Match");
555 if( etag != null )
556 buf.append( " etag=[" ).append( etag ).append( "]" );
557 if( referer==null || isInIpList(remote) )
558 throw new JtpServletException(request,buf.toString(),e);
559 rte = new JtpRuntimeException(request,buf.toString(),e);
560 } catch(RuntimeException e2) {
561 logger.error("failed to handle",e);
562 throw e2;
563 }
564 throw rte;
565 }
566
567 private static void handleException(HttpServletRequest request,ServletException e)
568 throws ServletException
569 {
570 String agent = request.getHeader("user-agent");
571 throw new JtpServletException(request,"user-agent="+agent+" method="+request.getMethod()+" referer="+request.getHeader("referer"),e);
572 }
573
574 private static class JtpRuntimeException extends RuntimeException {
575 private JtpRuntimeException(HttpServletRequest request,String msg,RuntimeException e) {
576 super("url="+getCurrentURL(request)+" "+msg,e);
577 }
578 }
579
580 private static class JtpServletException extends ServletException {
581 private JtpServletException(HttpServletRequest request,String msg,Exception e) {
582 super("url="+getCurrentURL(request)+" "+msg,e);
583 }
584 }
585
586 // work-around jetty bug
587 private static String getCurrentURL(HttpServletRequest request) {
588 try {
589 return ServletUtils.getCurrentURL(request);
590 } catch(RuntimeException e) {
591 logger.warn("jetty screwed up",e);
592 return "[failed]";
593 }
594 }
595
596 private static boolean isValidAgent(String agent) {
597 if (agent == null)
598 return false;
599 for (String badAgent : badAgents) {
600 if (agent.indexOf(badAgent) >= 0)
601 return false;
602 }
603 return true;
604 }
605
606 private static final String[] badAgents = new String[]{
607 "MJ12bot",
608 "WISEnutbot",
609 "Win98", // not worth handling these
610 "Windows 98",
611 "Windows 95",
612 "RixBot",
613 "User-Agent", // from corrupt header
614 "Firefox/0", // ancient version of Firefox
615 "Firefox/2.", // ancient version of Firefox
616 "Firefox/3.", // ancient version of Firefox
617 "Opera 7.", // ancient version of Opera
618 "Opera/7.",
619 "Opera 8.",
620 "Opera/8.",
621 "Opera/9.",
622 "TwitterFeed 3",
623 "NAVER Blog Rssbot",
624 "AOL 9.0",
625 "rssreader@newstin.com",
626 "PHPCrawl",
627 "MSIE 2.",
628 "MSIE 4.",
629 "MSIE 5.",
630 "MSIE 6.",
631 "MSIE 7.0",
632 "Mozilla/0.",
633 "Mozilla/2.0",
634 "Mozilla/3.0",
635 "Mozilla/4.6",
636 "Mozilla/4.7",
637 "RSSIncludeBot/1.0", // cause exceptions in xml feeds
638 "Powermarks",
639 "GenwiFeeder",
640 "Akregator",
641 "ia_archiver",
642 "Atomic_Email_Hunter",
643 "Yahoo! Slurp",
644 "Python-urllib",
645 "BlackBerry",
646 "SimplePie", // Feeds parser
647 "www.webintegration.at", // crazy bot
648 "www.run4dom.com", // crazy bot
649 "zia-httpmirror",
650 "POE-Component-Client-HTTP",
651 "anonymous",
652 "Sosospider",
653 "Java/1.6",
654 "Shareaza",
655 "Jakarta Commons-HttpClient",
656 "Apache-HttpClient",
657 "Baiduspider",
658 "bingbot",
659 "MLBot", // www.metadatalabs.com/mlbot
660 "www.vbseo.com",
661 "yacybot", // yacy.net/bot.html
662 "SearchBot"
663 };
664
665 private static boolean isBot(String agent) {
666 if (agent == null)
667 return false;
668 for (String bot : bots) {
669 if (agent.indexOf(bot) >= 0)
670 return true;
671 }
672 return false;
673 }
674
675 private static final String[] bots = new String[]{
676 "Googlebot"
677 };
678
679 private HttpServlet getServlet(String path)
680 throws ServletException, ClassNotFoundException, IOException
681 {
682 int i = path.lastIndexOf('.');
683 if( i == -1 )
684 throw new ClassNotFoundException(path);
685 return getServletFromClass(
686 base + path.substring(0,i).replace('/','.')
687 );
688 }
689
690 private HttpServlet getServletFromClass(String cls)
691 throws ClassNotFoundException
692 {
693 synchronized(lock) {
694 if( reload && hasChanged(cls) ) {
695 unloadServlets();
696 }
697 HttpServlet srv = map.get(cls);
698 if( srv==null ) {
699 try {
700 Class clas = reload ? cl.loadClass(cls) : Class.forName(cls);
701 srv = (HttpServlet)clas.newInstance();
702 } catch(IllegalAccessException e) {
703 throw new RuntimeException(e);
704 } catch(InstantiationException e) {
705 throw new RuntimeException(e);
706 }
707 try {
708 srv.init(this);
709 } catch(ServletException e) {
710 throw new RuntimeException(e);
711 }
712 map.put(cls,srv);
713 }
714 return srv;
715 }
716 }
717
718 private boolean hasChanged(String cls) {
719 try {
720 URL url = cl.getResource( SimpleClassLoader.classToResource(cls) );
721 if( url==null )
722 return true;
723 File file = new File(url.getPath());
724 if( recompile ) {
725 String path = file.toString();
726 if( !path.endsWith(".class") )
727 throw new RuntimeException();
728 File dir = file.getParentFile();
729 String base = path.substring(0,path.length()-6);
730 File source = new File( base + ".jtp" );
731 if( source.lastModified() > clTime ) {
732 Process proc = Runtime.getRuntime().exec(new String[]{
733 "java", "fschmidt.tools.Jtp", source.getName()
734 },null,dir);
735 ProcUtils.checkProc(proc);
736 }
737 source = new File( base + ".java" );
738 if( source.lastModified() > clTime ) {
739 Process proc = Runtime.getRuntime().exec(new String[]{
740 "javac", "-g", source.getName()
741 },null,dir);
742 ProcUtils.checkProc(proc);
743 }
744 }
745 return file.lastModified() > clTime;
746 } catch(IOException e) {
747 throw new RuntimeException(e);
748 }
749 }
750
751
752 private long timeLimit = 0;
753 private static final String timeLimitAttr = "time-limit";
754
755 private static class TimeLimit {
756 long timeLimit;
757 final long startTime = System.currentTimeMillis();
758 long ioTime = 0L;
759
760 TimeLimit(long timeLimit) {
761 this.timeLimit = timeLimit;
762 }
763 }
764
765 public long getTimeLimit() {
766 return timeLimit;
767 }
768
769 public void setTimeLimit(long timeLimit) {
770 this.timeLimit = timeLimit;
771 }
772
773 private TimeLimit startTimeLimit(HttpServletRequest request) {
774 TimeLimit tl = new TimeLimit(timeLimit);
775 request.setAttribute( timeLimitAttr, tl );
776 return tl;
777 }
778
779 public void setTimeLimit(HttpServletRequest request,long timeLimit) {
780 TimeLimit tl = (TimeLimit)request.getAttribute(timeLimitAttr);
781 tl.timeLimit = timeLimit;
782 }
783
784 private void checkTimeLimit(HttpServletRequest request) {
785 TimeLimit tl = (TimeLimit)request.getAttribute(timeLimitAttr);
786 if( tl.timeLimit == 0L )
787 return;
788 long time = System.currentTimeMillis() - tl.startTime - tl.ioTime;
789 if( time > tl.timeLimit ) {
790 float free = Runtime.getRuntime().freeMemory();
791 float total = Runtime.getRuntime().totalMemory();
792 float used = (total - free) * 100f;
793 logger.error(ServletUtils.getCurrentURL(request,100) + " took " + time + " ms | " + String.format("%.1f",used/total) + '%');
794 /*
795 Scheduler scheduler = TheScheduler.get();
796 if( scheduler instanceof ProfilingScheduler ) {
797 ProfilingScheduler profilingScheduler = (ProfilingScheduler)scheduler;
798 if( profilingScheduler.getMode()==ProfilingScheduler.Mode.FOREGROUND ) {
799 profilingScheduler.captureCPUSnapshot();
800 }
801 }
802 */
803 }
804 }
805
806 }