1 4 5 9 10 package org.openlaszlo.servlets.responders; 11 12 import java.io.*; 13 import java.net.InetAddress ; 14 import java.net.UnknownHostException ; 15 import java.util.Date ; 16 import java.util.Properties ; 17 import java.util.Iterator ; 18 import javax.servlet.ServletConfig ; 19 import javax.servlet.ServletContext ; 20 import javax.servlet.ServletException ; 21 import javax.servlet.ServletOutputStream ; 22 import javax.servlet.http.HttpServletRequest ; 23 import javax.servlet.http.HttpServletResponse ; 24 import javax.servlet.http.HttpUtils ; 25 26 import org.openlaszlo.compiler.Canvas; 27 import org.openlaszlo.compiler.CompilationError; 28 import org.openlaszlo.media.MimeType; 29 import org.openlaszlo.utils.ChainedException; 30 import org.openlaszlo.utils.FileUtils; 31 import org.openlaszlo.utils.LZHttpUtils; 32 import org.openlaszlo.utils.SWFUtils; 33 import org.openlaszlo.server.LPS; 34 import org.openlaszlo.xml.internal.DataCompiler; 35 import org.openlaszlo.xml.internal.XMLUtils; 36 import org.openlaszlo.servlets.LoadCount; 37 import org.apache.log4j.Logger; 38 39 public abstract class Responder 40 { 41 public static final int MIME_TYPE_SWF = 0; 42 public static final int MIME_TYPE_HTML = 1; 43 public static final int MIME_TYPE_XML = 2; 44 45 public static final String LZCOOKIE = "lzc"; 46 47 48 private boolean mAllowRequest = true; 49 50 51 protected String mAllowRequestDefaultProperty = "true"; 52 53 protected static ServletContext mContext = null; 55 56 private static int mErrorSWFCount = 0; 57 private static Object mErrorSWFCountLock = new Object (); 58 private static boolean mIsInitialized = false; 59 private static boolean mEmitErrorHeader = false; 60 private static boolean mUseBogusErrorCode = false; 61 private static Logger mLogger = Logger.getLogger(Responder.class); 62 63 protected int mSWFVersionNum = -1; 64 65 private static Logger mExceptionStackTraceLogger = 67 Logger.getLogger("org.openlaszlo.exceptions"); 68 69 public static Date mSTAT_startDate = new Date (); 73 74 public static LoadCount mSTAT_otherLoadCount = new LoadCount(10); 75 public static LoadCount mSTAT_allLoadCount = new LoadCount(10); 76 public static LoadCount mSTAT_compileLoadCount = new LoadCount(10); 77 public static LoadCount mSTAT_mediaLoadCount = new LoadCount(10); 78 public static LoadCount mSTAT_dataLoadCount = new LoadCount(10); 79 80 public static Class mSTAT_adminClass; 82 public static Class mSTAT_connectClass; 83 public static Class mSTAT_compileClass; 84 public static Class mSTAT_mediaClass; 85 public static Class mSTAT_dataClass; 86 87 public static Class mCompilerClass; 88 89 protected static boolean mCollectStat = true; 90 91 92 protected abstract void respondImpl(HttpServletRequest req, 93 HttpServletResponse res) 94 throws IOException; 95 96 103 public abstract int getMimeType(); 104 105 106 107 public synchronized void init(String reqName, ServletConfig config, 108 Properties prop) 109 throws ServletException , IOException 110 { 111 mAllowRequest = 112 prop.getProperty("allowRequest" + reqName.toUpperCase(), 113 mAllowRequestDefaultProperty).intern() == "true"; 114 115 if (! mIsInitialized) { 116 117 mContext = config.getServletContext(); 118 119 try { 120 121 mSTAT_adminClass = 123 Class.forName("org.openlaszlo.servlets.responders.ResponderAdmin"); 124 mSTAT_connectClass = 125 Class.forName("org.openlaszlo.servlets.responders.ResponderCONNECT"); 126 mSTAT_compileClass = 127 Class.forName("org.openlaszlo.servlets.responders.ResponderCompile"); 128 mSTAT_mediaClass = 129 Class.forName("org.openlaszlo.servlets.responders.ResponderMEDIA"); 130 mSTAT_dataClass = 131 Class.forName("org.openlaszlo.servlets.responders.ResponderDATA"); 132 133 mCompilerClass = 134 Class.forName("org.openlaszlo.servlets.responders.ResponderCompile"); 135 136 } catch (ClassNotFoundException e) { 137 throw new ServletException (e.getMessage()); 138 } 139 140 mEmitErrorHeader = 141 prop.getProperty("emitErrorHeader", "false").intern() == "true"; 142 mUseBogusErrorCode = 143 prop.getProperty("useBogusErrorCode", "false").intern() == "true"; 144 145 mCollectStat = 146 prop.getProperty("collectStat", "true").intern() == "true"; 147 148 mIsInitialized = true; 149 } 150 } 151 152 156 protected File checkDirectory(String cacheDir) throws IOException { 157 158 File dir = new File(cacheDir); 159 try { 160 dir.mkdirs(); 161 } catch (SecurityException e) { } 162 try { 163 dir.mkdir(); 164 } catch (SecurityException e) { } 165 if ( !dir.isDirectory() ) { 166 throw new IOException(cacheDir + " is not a directory."); 167 } 168 try { 169 if ( ! dir.canRead() ) { 170 throw new IOException("can't read " + cacheDir); 171 } 172 } catch (SecurityException e) { 173 throw new IOException("can't read " + cacheDir); 174 } 175 try { 176 if ( ! dir.canWrite() ) { 177 mLogger.warn(cacheDir + " is not writable."); 178 } 179 } catch (SecurityException e) { 180 mLogger.info(cacheDir + " is not writable."); 182 } 183 return dir; 184 } 185 186 public void respond(HttpServletRequest req, HttpServletResponse res) 187 { 188 try { 189 190 if ( ! mAllowRequest ) { 191 String lzt = req.getParameter("lzt"); 192 String msg = "Forbidden request type: " + lzt; 193 res.sendError(HttpServletResponse.SC_FORBIDDEN, msg); 194 mLogger.info(msg); 195 return; 196 } 197 198 if ( mCollectStat && 200 ! mSTAT_adminClass.isInstance(this) && 201 ! mSTAT_connectClass.isInstance(this)) { 202 203 LoadCount lc = mSTAT_otherLoadCount; 204 if (mSTAT_compileClass.isInstance(this)) 205 lc = mSTAT_compileLoadCount; 206 else if (mSTAT_mediaClass.isInstance(this)) 207 lc = mSTAT_mediaLoadCount; 208 else if (mSTAT_dataClass.isInstance(this)) 209 lc = mSTAT_dataLoadCount; 210 211 long t0 = new Date ().getTime(); 212 mSTAT_allLoadCount.increment(); 213 lc.increment(); 214 215 try { 216 mSWFVersionNum = LPS.getSWFVersionNum(req); 217 respondImpl(req, res); 218 } finally { 219 long t1 = new Date ().getTime(); 220 int d = (int) (t1 - t0); 221 mSTAT_allLoadCount.decrement( d ); 222 lc.decrement( d ); 223 } 224 225 } else { 226 227 respondImpl(req, res); 228 229 } 230 231 } catch (CompilationError e) { 232 respondWithError(res, e.getMessage(), 0); 233 } catch (IOException e) { 234 respondWithException(res, e); 235 } catch (Exception e) { 236 respondWithException(res, e); 237 } 238 } 239 240 protected void respondWithError(HttpServletResponse res, String m, int status) 241 { 242 switch (getMimeType()) { 243 244 case MIME_TYPE_SWF : 245 respondWithErrorSWF(res, m); 246 break; 247 case MIME_TYPE_HTML : 248 respondWithErrorHTML(res, m); 249 break; 250 case MIME_TYPE_XML : 251 respondWithErrorXML(res, xmlErrorMsg(status, m)); 252 break; 253 default: 254 throw new ChainedException("Responder mime type unknown"); 255 } 256 } 257 258 public void respondWithMessage(HttpServletResponse res, String msg) 259 throws IOException { 260 String surl; 261 262 switch (getMimeType()) { 263 case MIME_TYPE_SWF : 264 respondWithMessageSWF(res, msg); 265 break; 266 case MIME_TYPE_HTML : 267 respondWithErrorHTML(res, msg); 268 break; 269 case MIME_TYPE_XML : 270 respondWithErrorXML(res, msg); 271 break; 272 default: 273 throw new ChainedException("Responder mime type unknown"); 274 } 275 } 276 277 278 281 protected void respondWithErrorSWF(HttpServletResponse res, String s) 282 { 283 mLogger.error("Responding with error SWF: " + s); 284 ServletOutputStream out = null; 285 InputStream in = null; 286 try { 287 res.setContentType(MimeType.SWF); 288 if (mEmitErrorHeader) { 289 res.setHeader("X-LPS", s.replace('\n', '_')); 291 } 292 if (mUseBogusErrorCode) 293 res.setStatus(700); 294 295 synchronized (mErrorSWFCountLock) { 296 mErrorSWFCount++; 297 } 298 299 302 out = res.getOutputStream(); 303 String buf = xmlErrorMsg(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, s); 304 in = DataCompiler.compile(buf.toString(), mSWFVersionNum); 305 FileUtils.sendToStream(in, out); 306 } catch (FileUtils.StreamWritingException e) { 307 mLogger.warn("StreamWritingException while sending error: " + e.getMessage()); 308 } catch (Exception e) { 309 mLogger.warn("Exception while sending error: " + e.getMessage()); 310 mExceptionStackTraceLogger.error("exception", e); 311 } finally { 312 FileUtils.close(in); 313 FileUtils.close(out); 314 } 315 } 316 317 320 public static void respondWithMessageSWF(HttpServletResponse res, String s) 321 { 322 if (mUseBogusErrorCode) 323 res.setStatus(700); 324 325 synchronized (mErrorSWFCountLock) { 326 mErrorSWFCount++; 327 } 328 329 ServletOutputStream out = null; 330 InputStream in = null; 331 try { 332 out = res.getOutputStream(); 333 in = SWFUtils.getErrorMessageSWF(s); 334 if (in != null) { 335 res.setContentType(MimeType.SWF); 336 FileUtils.sendToStream(in, out); 337 } 338 } catch (FileUtils.StreamWritingException e) { 339 mLogger.warn("StreamWritingException while sending message: " + e.getMessage()); 340 } catch (Exception e) { 341 mLogger.warn("Exception while sending message: " + e.getMessage()); 342 mExceptionStackTraceLogger.error("exception", e); 343 } finally { 344 FileUtils.close(in); 345 FileUtils.close(out); 346 } 347 } 348 349 350 353 protected void respondWithExceptionSWF(HttpServletResponse res, Throwable e) 354 { 355 mExceptionStackTraceLogger.error(e.getMessage(), e); 356 StringWriter s = new StringWriter(); 357 PrintWriter p = new PrintWriter(s); 358 e.printStackTrace(p); 359 respondWithErrorSWF(res, e.getMessage() + " : Exception stack: " + s.toString()); 360 } 361 362 363 366 public static void respondWithErrorHTML(HttpServletResponse res, String s) 367 { 368 mLogger.info("Responding with error (text/html): " + s); 369 ServletOutputStream out = null; 370 try { 371 res.setContentType ("text/html"); 372 out = res.getOutputStream(); 373 writeHeader(out, null); 374 out.print("<pre>"); 375 out.println("Error: " + XMLUtils.escapeXmlForSWFHTML(s)); 376 out.println("</pre>"); 377 writeFooter(out); 378 } catch (Exception e) { 379 mLogger.warn("Exception while sending error HTML: " + e.getMessage()); 380 mExceptionStackTraceLogger.error("exception", e); 381 } finally { 382 if (out != null) { 383 try { 384 out.close(); 385 } catch (Exception e) { 386 } 387 } 388 } 389 } 390 391 394 protected void respondWithErrorXML(HttpServletResponse res, String s) 395 { 396 mLogger.info("Responding with error (text/xml): " + s); 397 ServletOutputStream out = null; 398 try { 399 res.setContentType ("text/xml"); 400 out = res.getOutputStream(); 401 out.println("<lps-error>" + XMLUtils.escapeXml(s) + "</lps-error>"); 402 } catch (Exception e) { 403 mLogger.warn("Exception while sending error XML: " + e.getMessage()); 404 mExceptionStackTraceLogger.error("exception", e); 405 } finally { 406 FileUtils.close(out); 407 } 408 } 409 410 411 414 protected void respondWithXML(HttpServletResponse res, String xml) 415 throws IOException 416 { 417 ServletOutputStream out = null; 418 try { 419 res.setContentType ("text/xml"); 420 out = res.getOutputStream(); 421 out.println("<lps>"); 422 out.println(xml); 423 out.println("</lps>"); 424 } catch (Exception e) { 425 mLogger.warn("Exception while sending XML: " + e.getMessage()); 426 mExceptionStackTraceLogger.error("exception", e); 427 } finally { 428 FileUtils.close(out); 429 } 430 } 431 432 433 436 protected void respondWithException(HttpServletResponse res, Exception e) 437 { 438 String m = e.getMessage(); 439 StringWriter s = new StringWriter(); 440 PrintWriter p = new PrintWriter(s); 441 e.printStackTrace(p); 442 if (m == null) { 443 m = s.toString(); 444 } else { 445 m += s.toString(); 446 } 447 448 respondWithError(res, m, 449 HttpServletResponse.SC_INTERNAL_SERVER_ERROR); 450 } 451 452 453 461 protected void respondWithStatusSWF(HttpServletResponse res, int status, 462 String mesg, int serial) 463 { 464 respondWithStatusSWF(res, status, mesg, null, serial); 465 } 466 467 468 477 protected void respondWithStatusSWF(HttpServletResponse res, int status, 478 String mesg, String xmlBody, int serial) 479 { 480 res.setContentType(MimeType.SWF); 481 482 String _mesg = XMLUtils.escapeXml(mesg); 483 484 String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 487 + "<!DOCTYPE laszlo-data>" 488 + "<resultset s=\"" + serial + "\">" 489 + "<success code=\"" + status + "\" msg=\"" + _mesg + "\" />" 490 + ( xmlBody!=null ? xmlBody : "" ) 491 + "</resultset>"; 492 493 mLogger.debug("respondWithStatusSWF: " + xml); 494 495 ServletOutputStream sos = null; 496 try { 497 sos = res.getOutputStream(); 498 InputStream swfbytes = DataCompiler.compile(xml, mSWFVersionNum); 499 FileUtils.sendToStream(swfbytes, sos); 500 } catch (FileUtils.StreamWritingException e) { 501 mLogger.warn("StreamWritingException while sending status: " + e.getMessage()); 502 } catch (Exception e) { 503 mLogger.warn("Exception while sending status: " + e.getMessage()); 504 mExceptionStackTraceLogger.error("exception", e); 505 } finally { 506 FileUtils.close(sos); 507 } 508 } 509 510 513 void respondWithOverLimitMessage(HttpServletRequest req, HttpServletResponse res) 514 throws IOException { 515 StringBuffer url = HttpUtils.getRequestURL(req); 516 String msg = LPS.getProperty("messages.over-limit", 517 "The Laszlo Presentation Server that is responsible for serving " + 518 url.toString() + " is over its license limit. The site administrator has been notified."); 519 respondWithMessage(res, msg); 520 } 521 522 529 protected String xmlErrorMsg(int status, String msg) 530 { 531 return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + 532 "<!DOCTYPE laszlo-data>" + 533 "<resultset><error status=\"" + status + "\" msg=\"" + 534 XMLUtils.escapeXml(msg) + 535 "\"/></resultset>"; 536 } 537 538 542 protected static void writeHeader(ServletOutputStream out, Canvas c) 543 throws IOException 544 { 545 String bgc = ""; 546 String title = ""; 547 if (c != null) { 548 bgc = "bgcolor=\"" + c.getBGColorString() + "\""; 549 title = c.getTitle(); 550 } 551 552 out.println("<html><head><title>" + title + "</title>"); 554 555 String ico = LPS.getProperty("shortcut.icon", "http://www.laszlosystems.com/images/laszlo.ico"); 556 out.println("<link rel=\"SHORTCUT ICON\" HREF=\"" + ico + 557 "\"></head>\n"); 558 out.println("<body " + bgc + 559 " marginwidth=\"0\" marginheight=\"0\" topmargin=\"0\" leftmargin=\"0\">"); 560 } 561 562 565 protected static void writeFooter(ServletOutputStream out) 566 throws IOException 567 { 568 out.println ("</body></html>"); 569 } 570 571 protected static int getErrorSWFCount() 572 { 573 synchronized (mErrorSWFCountLock) { 574 return mErrorSWFCount; 575 } 576 } 577 578 protected static void clearErrorSWFCount() 579 { 580 synchronized (mErrorSWFCountLock) { 581 mErrorSWFCount = 0; 582 } 583 } 584 } 585 | Popular Tags |