001: /******************************************************************************
002: * ResponderAPP_CONSOLE.java
003: * ****************************************************************************/package org.openlaszlo.servlets.responders;
004:
005: import java.io.*;
006: import java.net.URLEncoder;
007: import java.util.*;
008: import javax.servlet.ServletConfig;
009: import javax.servlet.ServletException;
010: import javax.servlet.ServletOutputStream;
011: import javax.servlet.http.HttpSession;
012: import javax.servlet.http.HttpServletRequest;
013: import javax.servlet.http.HttpServletResponse;
014: import org.openlaszlo.compiler.Canvas;
015: import org.openlaszlo.compiler.CompilationError;
016: import org.openlaszlo.server.LPS;
017: import org.openlaszlo.utils.*;
018: import org.openlaszlo.xml.internal.XMLUtils;
019: import org.apache.log4j.Logger;
020:
021: public final class ResponderAPP_CONSOLE extends ResponderCompile {
022: private static Logger mLogger = Logger
023: .getLogger(ResponderAPP_CONSOLE.class);
024:
025: /* for i18n get filename from properties file.
026: original : private static String sStyleSheetPathname =
027: org.openlaszlo.server.LPS.getTemplateDirectory() +
028: File.separator + "app-console.xslt";
029: */
030:
031: private static String sStyleSheetPathname = org.openlaszlo.server.LPS
032: .getTemplateDirectory()
033: + File.separator
034: + org.openlaszlo.i18n.LaszloMessages.getMessage(
035: ResponderAPP_CONSOLE.class.getName(),
036: "xsltfilename");
037:
038: /*
039: * @param fileName Full pathname to file from request.
040: */
041: protected void respondImpl(String fileName, HttpServletRequest req,
042: HttpServletResponse res) throws IOException {
043: mLogger.info(
044: /* (non-Javadoc)
045: * @i18n.test
046: * @org-mes="Responding with HTML wrapper for " + p[0]
047: */
048: org.openlaszlo.i18n.LaszloMessages.getMessage(
049: ResponderAPP_CONSOLE.class.getName(), "051018-47",
050: new Object[] { fileName }));
051: res.setContentType("text/html");
052: ServletOutputStream out = res.getOutputStream();
053: try {
054: // Get the canvas first, so that if this fails and we
055: // write the compilation error, nothing has been written
056: // to out yet.
057: // Replace .lzo with .lzx
058: String orig = fileName;
059:
060: /* This method doesn't call writeHeader and writeFooter, since
061: * the stylesheet handles the whole HTML generation. */
062: Canvas canvas = getCanvas(fileName, req);
063: writeCanvas(out, req, canvas, orig);
064: } finally {
065: FileUtils.close(out);
066: }
067: }
068:
069: static public String getRequestXML(HttpServletRequest req,
070: String fileName) throws IOException {
071: String lps = req.getContextPath();
072: String agent = req.getHeader("user-agent");
073: // MS-specific header
074: String os = req.getHeader("ua-os");
075: String debugconsole = req.getParameter("lzconsoledebug");
076: String popupdebugconsole = req.getParameter("lzconsolewindow");
077: String query_args = getQueryArgs(req);
078: String url = req.getRequestURI();
079: int i = url.lastIndexOf("/");
080: url = url.substring(i + 1, url.length());
081: String relurl = req.getRequestURI();
082: i = relurl.indexOf("/", 1);
083: relurl = relurl.substring(i + 1, relurl.length());
084: String unopturl = url.substring(0, url.length() - 4) + ".lzx";
085: String opturl = url.substring(0, url.length() - 4) + ".lzo";
086: boolean isPocketPC = (os != null && os.indexOf("POCKET PC") > -1);
087: boolean isWin = (agent != null && agent.toLowerCase().indexOf(
088: "win") > -1);
089:
090: Properties props = initCMgrProperties(req);
091:
092: StringBuffer buffer = new StringBuffer();
093: buffer.append("<request " + "lps=\"" + XMLUtils.escapeXml(lps)
094: + "\" " + "url=\"" + XMLUtils.escapeXml(url) + "\" "
095: + "relurl=\"" + XMLUtils.escapeXml(relurl) + "\" "
096: + "fullpath=\""
097: + XMLUtils.escapeXml(req.getRequestURI()) + "\" "
098: + "opt-url=\"" + XMLUtils.escapeXml(opturl) + "\" "
099: + "unopt-url=\"" + XMLUtils.escapeXml(unopturl) + "\" "
100: + "query_args=\"" + XMLUtils.escapeXml(query_args)
101: + "\" " + "pocketpc=\"" + isPocketPC + "\" "
102: + "console-remote-debug=\"" + debugconsole + "\" "
103: + "console-floating-window=\"" + popupdebugconsole
104: + "\" " + "appuid=\"" + System.currentTimeMillis()
105: + "\" " + "windows=\"" + isWin + "\" ");
106: if (fileName != null) {
107: String optname = fileName.substring(0,
108: fileName.length() - 4)
109: + ".lzo";
110: buffer.append("opt-exists=\"" + new File(optname).exists()
111: + "\" ");
112: }
113: buffer.append(">\n");
114:
115: for (Enumeration e = req.getParameterNames(); e
116: .hasMoreElements();) {
117: String name = (String) e.nextElement();
118: String value = req.getParameter(name);
119: buffer.append("<param name=\"" + XMLUtils.escapeXml(name)
120: + "\" ");
121: buffer.append("value=\"" + XMLUtils.escapeXml(value)
122: + "\"/>\n");
123: }
124: buffer.append("</request>");
125:
126: String infoXML = "";
127: if (fileName != null) {
128: boolean isOpt = fileName.endsWith(".lzo");
129: if (isOpt) {
130: infoXML = getInfoXML(fileName, props);
131: } else {
132: infoXML = getCompilationManager().getInfoXML(fileName,
133: props);
134: }
135: }
136:
137: buffer.append(infoXML);
138:
139: // Encode the <request> and <info> block we just created as URL-encoded
140: // element named console_appinfo. This will be used by the SOLO dev console
141: // app, to parse out when it runs.
142: String console_appinfo = URLEncoder.encode("<data>"
143: + buffer.toString() + "</data>");
144: buffer.append("<console_appinfo>" + console_appinfo
145: + "</console_appinfo>\n");
146:
147: return buffer.toString();
148: }
149:
150: /**
151: * @return info XML string for .lzo files
152: */
153: private static String getInfoXML(String fileName, Properties props)
154: throws IOException {
155: String enc = props.getProperty(LZHttpUtils.CONTENT_ENCODING);
156: String zippedSize = null;
157: String unzippedSize = null;
158: String size = null;
159:
160: try {
161: unzippedSize = "" + FileUtils.fileSize(new File(fileName));
162: } catch (FileNotFoundException e) {
163: mLogger.error(e.getMessage());
164: }
165:
166: {
167: String gzName = fileName + ".gz";
168: File f = new File(gzName);
169: // Handle case where .lzo exists but not .gz yet or
170: // gz out of date
171: File nongz = new File(fileName);
172: if (nongz.exists()) {
173: if (!f.exists()
174: || f.lastModified() < nongz.lastModified()) {
175: FileUtils.encode(nongz, f, "gzip");
176: f = new File(gzName);
177: }
178: }
179: try {
180: zippedSize = "" + FileUtils.fileSize(f);
181: } catch (FileNotFoundException e) {
182: mLogger.error(e.getMessage());
183: }
184: }
185:
186: size = ("gzip".equals(enc)) ? zippedSize : unzippedSize;
187:
188: return "<info size=\"" + size + "\" zipped-size=\""
189: + zippedSize + "\" unzipped-size=\"" + unzippedSize
190: + "\" encoding=\"" + enc + "\" />";
191: }
192:
193: protected void handleCompilationError(CompilationError e,
194: HttpServletRequest req, HttpServletResponse res)
195: throws IOException {
196: respondCompilationError(e, req, res);
197: }
198:
199: public static void respondCompilationError(CompilationError e,
200: HttpServletRequest req, HttpServletResponse res)
201: throws IOException {
202: res.setContentType("text/html");
203: ServletOutputStream out = res.getOutputStream();
204: String xmlString = "<errors>" + getRequestXML(req, null)
205: + e.toXML() + "</errors>";
206: try {
207: TransformUtils.applyTransform(sStyleSheetPathname,
208: xmlString, out);
209: } catch (Exception ex) {
210: reportTransformException(req, sStyleSheetPathname, ex, out);
211: }
212: }
213:
214: /**
215: * Writes the canvas html. The canvas is the area in which the
216: * Laszlo application is rendered.
217: * @param out <tt>ServletOutputStream</tt> to write on
218: * @param req request to retrieve scheme, server name, server port and
219: * requested url
220: * @param canvas the canvas for the given request
221: */
222: private void writeCanvas(ServletOutputStream out,
223: HttpServletRequest req, Canvas canvas, String fileName)
224: throws IOException {
225: String xmlString = canvas.getXML(getRequestXML(req, fileName));
226: mLogger.debug(xmlString);
227: Properties properties = new Properties();
228: try {
229: TransformUtils.applyTransform(sStyleSheetPathname,
230: properties, xmlString, out);
231: } catch (Exception e) {
232: reportTransformException(req, sStyleSheetPathname, e, out);
233: }
234: }
235:
236: /** Report the exception to output as an internal server error,
237: * rendered in HTML, with instructions for bug reporting and with
238: * a solution message if one is available.
239: */
240: protected static void reportTransformException(
241: HttpServletRequest req, String styleSheetPathname,
242: Exception e, OutputStream out) throws IOException {
243: // Note that the following doesn't quote HTML in the filename,
244: // message, and stacktrace. This is to make it as likely as
245: // possible that this will succeed, since it's typically
246: // called when the system is having trouble calling external
247: // functions or libraries. The failure mode is that under
248: // rare cases the display could be messed up, but it will
249: // still have enough information and the page source will have
250: // everything.
251:
252: // Special solution message if the error contains this string:
253: final String XALAN_ERR_MSG =
254: /* (non-Javadoc)
255: * @i18n.test
256: * @org-mes="output format must have a '{http://xml.apache.org/xalan}content-handler' property"
257: */
258: org.openlaszlo.i18n.LaszloMessages.getMessage(
259: ResponderAPP_CONSOLE.class.getName(), "051018-270");
260:
261: Writer writer = new OutputStreamWriter(out);
262: try {
263: String title = "500 Internal Server Error";
264: writer.write("<html><title>");
265: writer.write(title);
266: writer.write("</title>");
267: writer.write("<style type='text/css'>");
268: writer
269: .write("table th {text-align: right; vertical-align: top; padding-right: 10pt}");
270: writer.write("</style>");
271: writer.write("</head><body><h1>");
272: writer.write(title);
273: writer.write("</h1>");
274: writer.write("<p>An internal server error occurred. ");
275: // Use toString() instead of getMessage(), since for chained
276: // exceptions it's possible for the original message to
277: // get buried where the latter doesn't retrieve it.
278: if (e.toString().indexOf(XALAN_ERR_MSG) >= 0) {
279: writer
280: .write("If you are running Tomcat, please verify that ");
281: writer
282: .write("that the <code>xalan.jar</code> file from the ");
283: writer
284: .write("LPS distribution has been installed in the ");
285: writer
286: .write("Tomcat <code>/common/endorsed</code> directory. ");
287: writer.write("Otherwise, please check the ");
288: writer
289: .write("<a href='http://www.laszlosystems.com/developers/learn/documentation/faq/'>");
290: writer.write("LPS Developer FAQ</a> for additional ");
291: writer
292: .write("instructions. If that does not work, please ");
293: } else {
294: writer.write("Please ");
295: }
296: writer.write("send a copy of this web page and a ");
297: writer
298: .write("description of your server environment (operating ");
299: writer.write("system, JRE version, servlet container and ");
300: writer.write("version) to ");
301: writer.write("<a href='mailto:bugs@laszlosystems.com'>");
302: writer.write("bugs@laszlosystems.com</a>.</p>");
303: writer.write("<hr /><table border='0'>");
304: // TODO [2004-04-29 ows]: Eric says the following LPS call
305: // should work, but it returns an empty string
306: //writer.write("<tr><th>Server Info</th>");
307: //writer.write("<td>" + LPS.getInfo(req, mContext, "lps-server-info") + "</td></tr>");
308: writer.write("<tr><th>Version</th>");
309: writer.write("<td>" + LPS.getShortVersion() + "</td></tr>");
310: writer.write("<tr><th>Build</th>");
311: writer.write("<td>" + LPS.getBuildDate() + "</td></tr>");
312: writer.write("<tr><th>Stylesheet</th>");
313: writer.write("<td>"
314: + new File(styleSheetPathname).getName()
315: + "</td></tr>");
316: writer.write("<tr><th>Message</th>");
317: writer.write("<td>" + e.getMessage() + "</td></tr>");
318: writer.write("</table><pre>");
319: writer.flush();
320: PrintStream ps = new PrintStream(out);
321: try {
322: e.printStackTrace(ps);
323: } finally {
324: ps.flush();
325: }
326: writer.write("</pre></body></html>");
327: } finally {
328: writer.close();
329: }
330: }
331:
332: /**
333: * Return all query args except for "lzt"
334: */
335: private static String getQueryArgs(HttpServletRequest req) {
336: StringBuffer query = new StringBuffer();
337: Enumeration e = req.getParameterNames();
338: while (e.hasMoreElements()) {
339: String name = (String) e.nextElement();
340: String val = req.getParameter(name);
341: if (!name.equals("lzt")) {
342: query.append("&" + name + "=" + URLEncoder.encode(val));
343: }
344: }
345: return query.toString();
346: }
347:
348: public int getMimeType() {
349: return MIME_TYPE_HTML;
350: }
351:
352: }
|