001: /*
002: #IFNDEF ALT_LICENSE
003: ThinWire(R) RIA Ajax Framework
004: Copyright (C) 2003-2007 Custom Credit Systems
005:
006: This library is free software; you can redistribute it and/or modify it under
007: the terms of the GNU Lesser General Public License as published by the Free
008: Software Foundation; either version 2.1 of the License, or (at your option) any
009: later version.
010:
011: This library is distributed in the hope that it will be useful, but WITHOUT ANY
012: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
013: PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
014:
015: You should have received a copy of the GNU Lesser General Public License along
016: with this library; if not, write to the Free Software Foundation, Inc., 59
017: Temple Place, Suite 330, Boston, MA 02111-1307 USA
018:
019: Users who would rather have a commercial license, warranty or support should
020: contact the following company who invented, built and supports the technology:
021:
022: Custom Credit Systems, Richardson, TX 75081, USA.
023: email: info@thinwire.com ph: +1 (888) 644-6405
024: http://www.thinwire.com
025: #ENDIF
026: [ v1.2_RC2 ]
027: */
028: package thinwire.render.web;
029:
030: import java.io.*;
031: import java.util.Enumeration;
032: import java.util.List;
033: import java.util.Map;
034: import java.util.Set;
035: import java.util.TreeSet;
036: import java.util.logging.Level;
037: import java.util.logging.Logger;
038:
039: import org.apache.commons.fileupload.DiskFileUpload;
040: import org.apache.commons.fileupload.FileItem;
041: import org.apache.commons.fileupload.FileUploadException;
042:
043: import thinwire.ui.FileChooser;
044:
045: import javax.servlet.*;
046: import javax.servlet.http.*;
047:
048: /**
049: * @author Joshua J. Gertzen
050: */
051: public final class WebServlet extends HttpServlet {
052: private static final Level LEVEL = Level.FINER;
053: private static final Logger log = Logger.getLogger(WebServlet.class
054: .getName());
055:
056: private static enum InitParam {
057: MAIN_CLASS, EXTRA_ARGUMENTS, STYLE_SHEET, RELOAD_ON_REFRESH;
058:
059: private String mixedCaseName;
060:
061: private InitParam() {
062: StringBuilder sb = new StringBuilder();
063: String[] parts = name().split("_");
064: sb.append(parts[0].toLowerCase());
065:
066: for (int i = 1, cnt = parts.length; i < cnt; i++) {
067: sb.append(parts[i].charAt(0)).append(
068: parts[i].toLowerCase().substring(1));
069: }
070:
071: mixedCaseName = sb.toString();
072: }
073:
074: public String mixedCaseName() {
075: return mixedCaseName;
076: }
077:
078: public static InitParam valueOfMixedCase(String mixedCaseName) {
079: for (InitParam ip : values()) {
080: if (ip.mixedCaseName().equals(mixedCaseName))
081: return ip;
082: }
083:
084: return valueOf(mixedCaseName);
085: }
086: }
087:
088: private static class ApplicationHolder implements
089: HttpSessionBindingListener, Serializable {
090: private static final long serialVersionUID = 2454889032868933806L;
091: transient WebApplication app;
092:
093: public void valueBound(HttpSessionBindingEvent event) {
094:
095: }
096:
097: public void valueUnbound(HttpSessionBindingEvent event) {
098: if (log.isLoggable(LEVEL))
099: log.log(LEVEL, "Unbinding application instance "
100: + event.getSession().getId());
101: if (app != null)
102: app.shutdown();
103: }
104: }
105:
106: public void service(HttpServletRequest request,
107: HttpServletResponse response) throws IOException,
108: ServletException {
109: String method = request.getMethod();
110:
111: if (method.equals("GET")) {
112: String resource = request.getParameter("_twr_");
113:
114: if (resource == null) {
115: handleStart(request, response);
116: } else {
117: handleResource(request, response, resource);
118: }
119: } else if (method.equals("POST")) {
120: String action = request.getParameter("_twa_");
121:
122: if (action == null) {
123: handlePostEvent(request, response);
124: } else if (action.equals("upload")) {
125: handleUserUpload(request, response);
126: }
127: } else {
128: response
129: .sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
130: }
131: }
132:
133: private Set<String> getStartArguments(HttpServletRequest request) {
134: Set<String> args = new TreeSet<String>();
135: StringBuilder sb = new StringBuilder();
136:
137: for (Map.Entry<String, String[]> e : ((Map<String, String[]>) request
138: .getParameterMap()).entrySet()) {
139: String key = e.getKey();
140: String[] values = e.getValue();
141:
142: if (values.length > 1) {
143: for (int i = 0; i < values.length; i++) {
144: sb.append(key).append(i).append('=').append(
145: values[i]);
146: }
147: } else {
148: sb.append(key).append('=').append(values[0]);
149: }
150:
151: args.add(sb.toString());
152: sb.setLength(0);
153: }
154:
155: String extraArguments = getInitParameter(InitParam.EXTRA_ARGUMENTS
156: .mixedCaseName());
157: if (extraArguments == null)
158: extraArguments = "";
159: extraArguments = "," + extraArguments + ",";
160:
161: if (extraArguments.indexOf(",contextParam,") >= 0) {
162: ServletContext sc = getServletContext();
163:
164: for (Enumeration<String> ipn = sc.getInitParameterNames(); ipn
165: .hasMoreElements();) {
166: String name = ipn.nextElement();
167: sb.append("CONTEXT_PARAM_").append(name).append('=')
168: .append(sc.getInitParameter(name));
169: args.add(sb.toString());
170: sb.setLength(0);
171: }
172: }
173:
174: if (extraArguments.indexOf(",initParam,") >= 0) {
175: InitParam[] initParams = InitParam.values();
176:
177: ipn_loop: for (Enumeration<String> ipn = getInitParameterNames(); ipn
178: .hasMoreElements();) {
179: String name = ipn.nextElement();
180:
181: for (InitParam ip : initParams) {
182: if (ip.mixedCaseName().equals(name))
183: continue ipn_loop;
184: }
185:
186: sb.append("INIT_PARAM_").append(name).append('=')
187: .append(getInitParameter(name));
188: args.add(sb.toString());
189: sb.setLength(0);
190: }
191: }
192:
193: if (extraArguments.indexOf(",header,") >= 0) {
194: for (Enumeration<String> hn = request.getHeaderNames(); hn
195: .hasMoreElements();) {
196: String name = hn.nextElement();
197: sb.append("HEADER_").append(name.toUpperCase()).append(
198: '=').append(request.getHeader(name));
199: args.add(sb.toString());
200: sb.setLength(0);
201: }
202: }
203:
204: if (extraArguments.indexOf(",clientInfo,") >= 0) {
205: sb.append("CLIENT_INFO_USER").append('=').append(
206: request.getRemoteUser());
207: args.add(sb.toString());
208: sb.setLength(0);
209: sb.append("CLIENT_INFO_HOST").append('=').append(
210: request.getRemoteHost());
211: args.add(sb.toString());
212: sb.setLength(0);
213: sb.append("CLIENT_INFO_ADDRESS").append('=').append(
214: request.getRemoteAddr());
215: args.add(sb.toString());
216: sb.setLength(0);
217: }
218:
219: return args;
220: }
221:
222: private void handleStart(HttpServletRequest request,
223: HttpServletResponse response) throws IOException,
224: ServletException {
225: HttpSession httpSession = request.getSession();
226: String id = httpSession.getId();
227:
228: ApplicationHolder holder = (ApplicationHolder) httpSession
229: .getAttribute("instance");
230: response.setContentType("text/html");
231: response.setHeader("Pragma", "no-cache");
232: response.setHeader("Cache-Control", "no-cache, no-store");
233: response.setHeader("Expires", "-1");
234: response.getOutputStream().write(WebApplication.MAIN_PAGE);
235:
236: String reload = getInitParameter(InitParam.RELOAD_ON_REFRESH
237: .mixedCaseName());
238:
239: if (holder != null
240: && holder.app != null
241: && (reload == null || reload.toLowerCase().equals(
242: "false"))) {
243: if (log.isLoggable(LEVEL))
244: log.log(LEVEL, "repainting frame for application id="
245: + id);
246: holder.app.repaint();
247: return;
248: } else {
249: if (log.isLoggable(LEVEL))
250: log
251: .log(LEVEL, "starting new application with id="
252: + id);
253:
254: if (holder != null) {
255: if (log.isLoggable(LEVEL))
256: log.log(LEVEL,
257: "removing existing application instance with id="
258: + id);
259: httpSession.removeAttribute("instance");
260: }
261: }
262:
263: Set<String> args = getStartArguments(request);
264: holder = new ApplicationHolder();
265: holder.app = new WebApplication(
266: this .getServletContext().getRealPath(""),
267: getInitParameter(InitParam.MAIN_CLASS.mixedCaseName()),
268: getInitParameter(InitParam.STYLE_SHEET.mixedCaseName()),
269: args.toArray(new String[args.size()]));
270: httpSession.setAttribute("instance", holder);
271: }
272:
273: private void handleResource(HttpServletRequest request,
274: HttpServletResponse response, String resourceName)
275: throws IOException, ServletException {
276: if (log.isLoggable(LEVEL))
277: log.log(LEVEL, "getting resource: " + resourceName);
278: byte[] data = RemoteFileMap.INSTANCE.load(resourceName);
279:
280: if (data == null) {
281: response.sendError(HttpServletResponse.SC_NOT_FOUND);
282: } else {
283: try {
284: String mimeType;
285:
286: //Necessary because the XMLHttpRequest object in certain browsers, such as Opera
287: //do not properly handle text/javascript as the content type.
288: if (resourceName.endsWith(".js")) {
289: mimeType = "text/plain";
290: } else {
291: mimeType = getServletContext().getMimeType(
292: resourceName.toLowerCase());
293: if (mimeType != null
294: && mimeType.startsWith("image/"))
295: response.setHeader("Cache-Control",
296: "max-age=43200");
297: }
298:
299: if (data[0] == 31 && data[1] == -117)
300: response.setHeader("Content-Encoding", "gzip");
301: response.setContentType(mimeType);
302: response.getOutputStream().write(data);
303: } catch (Exception e) {
304: if (log.isLoggable(Level.WARNING))
305: log.log(Level.WARNING, "resource not found: "
306: + resourceName, e);
307: response.sendError(HttpServletResponse.SC_NOT_FOUND);
308: }
309: }
310: }
311:
312: private void handlePostEvent(HttpServletRequest request,
313: HttpServletResponse response) throws IOException,
314: ServletException {
315: HttpSession httpSession = request.getSession();
316: ApplicationHolder holder = (ApplicationHolder) httpSession
317: .getAttribute("instance");
318: response.setContentType("text/plain; charset=utf-8");
319: response.setHeader("Cache-Control", "no-store");
320: if (holder == null)
321: return;
322: holder.app.processActionEvents(request.getReader(), response
323: .getWriter());
324: }
325:
326: private void handleUserUpload(HttpServletRequest request,
327: HttpServletResponse response) throws IOException,
328: ServletException {
329: HttpSession httpSession = request.getSession();
330: ApplicationHolder holder = (ApplicationHolder) httpSession
331: .getAttribute("instance");
332:
333: if (holder.app != null) {
334: try {
335: DiskFileUpload upload = new DiskFileUpload();
336: upload.setSizeThreshold(1000000);
337: upload.setSizeMax(-1);
338: upload.setRepositoryPath("C:\\");
339: List<FileItem> items = upload.parseRequest(request);
340:
341: if (items.size() > 0) {
342: FileChooser.FileInfo f = null;
343:
344: synchronized (holder.app.fileList) {
345: for (FileItem fi : items) {
346: if (!fi.isFormField()) {
347: f = new FileChooser.FileInfo();
348: f.setName(fi.getName());
349: f.setInputStream(fi.getInputStream());
350: f.setDescription("");
351: holder.app.fileList[0] = f;
352: }
353: }
354:
355: holder.app.fileList.notify();
356: }
357: }
358: } catch (FileUploadException e) {
359: log.log(Level.SEVERE, null, e);
360: }
361: }
362:
363: response.sendRedirect("?_twr_=FileUploadPage.html");
364: }
365: }
|