001: /**
002: * $Id: ResponseBufferServlet.java,v 1.6 2005/07/13 05:43:41 rm144952 Exp $
003: * Copyright 2003 Sun Microsystems, Inc.
004: * All rights reserved.
005: * Use of this product is subject to license terms.
006: * Federal Acquisitions: Commercial Software -- Government Users
007: * Subject to Standard License Terms and Conditions.
008: *
009: * Sun, Sun Microsystems, the Sun logo, and Sun ONE are trademarks or
010: * registered trademarks of Sun Microsystems, Inc. in the
011: * United States and other countries.
012: */package com.sun.mobile.responsebuffer;
013:
014: import java.io.IOException;
015: import java.io.PrintWriter;
016: import java.util.ResourceBundle;
017: import java.util.MissingResourceException;
018:
019: import javax.servlet.*;
020: import javax.servlet.http.*;
021:
022: import com.iplanet.sso.SSOToken;
023: import com.iplanet.sso.SSOTokenManager;
024: import com.iplanet.sso.SSOException;
025:
026: import com.iplanet.services.cdm.Client;
027: import com.iplanet.services.cdm.ClientException;
028:
029: import com.iplanet.am.util.Debug;
030: import com.iplanet.am.util.Locale;
031: import com.iplanet.am.util.AMClientDetector;
032:
033: import com.sun.identity.session.util.SessionUtils;
034:
035: import com.aligo.util.Cache;
036: import com.aligo.portal.wireless.services.rendering.CacheManager;
037: import com.aligo.portal.wireless.services.rendering.CacheManagerFactory;
038: import com.aligo.portal.wireless.services.rendering.Logger;
039: import com.aligo.portal.wireless.services.rendering.RenderingEngine;
040: import com.aligo.portal.wireless.services.rendering.RenderingEngineFactory;
041: import com.aligo.portal.wireless.services.rendering.RenderingException;
042:
043: import java.net.URLEncoder;
044:
045: // FIXME: What a strange place to put the Content class in?
046: import com.aligo.engine.Content;
047:
048: public class ResponseBufferServlet extends HttpServlet {
049: private static Debug debug = Debug
050: .getInstance("MAPResponseBufferService");
051:
052: private AMClientDetector client_detector = null;
053: private ResponseBufferService _service = null;
054: private CacheManagerFactory cache_manager_factory = null;
055: private SSOTokenManager sso_token_manager = null;
056: private RenderingEngineFactory rendering_engine_factory = null;
057:
058: public void init() throws ServletException {
059: client_detector = new AMClientDetector();
060: _service = ResponseBufferService.getInstance();
061:
062: // We'll use this repeatedly in the getContent()
063: cache_manager_factory = CacheManagerFactory.getInstance();
064:
065: // We'll use this repeatedly in the getNativeRedirectBody()
066: rendering_engine_factory = RenderingEngineFactory.getInstance();
067:
068: try {
069: sso_token_manager = SSOTokenManager.getInstance();
070: } catch (SSOException se) {
071: debug
072: .error("init(): Unable to get the SSOTokenManager, failed with message "
073: + se.getMessage());
074: }
075: }
076:
077: public void doPost(HttpServletRequest request,
078: HttpServletResponse response) throws ServletException,
079: IOException {
080: doGet(request, response);
081: }
082:
083: public void doGet(HttpServletRequest request,
084: HttpServletResponse response) throws ServletException,
085: IOException {
086: // for printing information about the method being called
087: String servlet_method = getServletMethodName(request);
088:
089: // for as yet unauthenticated requests
090: String session_id = null;
091:
092: // for authenticated clients
093: SSOToken sso_token = null;
094:
095: // identifies the type of client making this request
096: Client client = null;
097: String client_charset = null;
098:
099: if (sso_token_manager != null) {
100: try {
101: // Get the SSOToken from the request
102: sso_token = sso_token_manager.createSSOToken(request);
103: } catch (SSOException se) {
104: if (debug.messageEnabled()) {
105: debug
106: .message(servlet_method
107: + ": Unable to get the SSO token, failed with message "
108: + se.getMessage());
109: }
110:
111: // Let's see if we can at least get SessionId instead
112: session_id = SessionUtils.getSessionId(request);
113: if (session_id == null) {
114: if (debug.messageEnabled()) {
115: debug.message(servlet_method
116: + ": Unable to get the session id");
117: }
118: } else {
119: if (debug.messageEnabled()) {
120: debug
121: .message(session_id
122: + ": "
123: + servlet_method
124: + ": Using the session id instead of token");
125: }
126: }
127: }
128: }
129:
130: if ((sso_token == null) && (session_id == null)) {
131: try {
132: client = getClient(null, request, "");
133: } catch (SSOException se) {
134: }
135:
136: // redirect the user to login url
137: redirectWithBody(_service.getLoginURL(), request, response,
138: client, sso_token, "");
139: return;
140: }
141:
142: // Use this for debugging purposes!
143: String token_string = null;
144: if (sso_token != null) {
145: token_string = sso_token.getTokenID().toString();
146: } else {
147: token_string = session_id;
148: }
149:
150: try {
151: // Use this SSOToken to determine the client.
152: client = getClient(sso_token, request, token_string);
153: client_charset = sso_token.getProperty("CharSet");
154: request.setCharacterEncoding(client_charset);
155: } catch (SSOException se) {
156: debug
157: .error(token_string
158: + ": "
159: + servlet_method
160: + ": Unable to get the client type from SSO token, failed with message "
161: + se.getMessage());
162:
163: try {
164: client = getClient(null, request, token_string);
165: } catch (SSOException sse) {
166: }
167:
168: // redirect the user to login url
169: redirectWithBody(_service.getLoginURL(), request, response,
170: client, sso_token, token_string);
171: }
172:
173: // Is there entry number present in the url?
174: Integer entry_number = getEntryNumberFromRequest(request);
175: if (entry_number == null) {
176: debug
177: .error(token_string
178: + ": "
179: + servlet_method
180: + ": Unable to get the response buffer entry number from the request");
181:
182: // redirect to desktop url
183: redirectWithBody(_service.getDesktopURL(), request,
184: response, client, sso_token, token_string);
185: return;
186: }
187:
188: // Get the ResponseBufferEntry's Cache from the ResponseBufferService
189: ResponseBufferEntry entry = null;
190: if (sso_token != null) {
191: entry = _service.getEntry(sso_token, entry_number);
192: } else {
193: entry = _service.getEntry(session_id, entry_number);
194: }
195:
196: // The URL which generated the buffered data
197: String request_url = null;
198:
199: if (entry == null) {
200: if (sso_token != null) {
201: request_url = _service.getRequestURL(sso_token,
202: entry_number);
203: } else {
204: request_url = _service.getRequestURL(session_id,
205: entry_number);
206: }
207:
208: if (debug.warningEnabled()) {
209: debug
210: .warning(token_string
211: + ": "
212: + servlet_method
213: + ": Unable to get the entry corresponding to "
214: + entry_number + " generated by "
215: + request_url);
216: }
217:
218: redirectAppropriately(request_url, request, response,
219: client, sso_token, token_string);
220: } else {
221: request_url = entry.getRequestURL();
222:
223: Logger logger = new Logger(token_string + ": Entry "
224: + entry_number);
225:
226: Content content = getContent(request, entry, token_string,
227: logger);
228:
229: if (content == null) {
230: debug
231: .error(token_string
232: + ": "
233: + servlet_method
234: + ": Unable to get the cached Content for entry corresponding to "
235: + entry_number + " generated by "
236: + request_url);
237:
238: // FIXME: Are we doing the right thing here?
239: redirectAppropriately(request_url, request, response,
240: client, sso_token, token_string);
241: } else {
242: String content_type = content
243: .getHeader(Content.CONTENT_TYPE);
244: if (content_type == null) {
245: if (debug.warningEnabled()) {
246: debug
247: .warning(token_string
248: + ": "
249: + servlet_method
250: + ": Unable to get the content type from Content for entry corresponding to "
251: + entry_number
252: + " generated by "
253: + request_url);
254: }
255:
256: // Get the content type from the Client object
257: content_type = getContentTypeFromClient(client,
258: sso_token, token_string);
259: }
260: // Make sure that charset is present in content type
261: if (content_type != null
262: && content_type.indexOf(";") == -1) {
263: content_type = content_type + "; charset="
264: + client_charset;
265: }
266:
267: // this could be a redirect, as in the case of last page of a form
268: String redirect_url = content.getRedirectURL();
269: if (redirect_url != null) {
270: if (debug.messageEnabled()) {
271: debug
272: .message(token_string
273: + ": "
274: + servlet_method
275: + ": Content for entry corresponding to "
276: + entry_number
277: + " generated by "
278: + request_url
279: + " is a redirect to "
280: + redirect_url);
281: }
282:
283: redirectWithBodyAndContentType(redirect_url,
284: request, response, client, content_type,
285: token_string, sso_token);
286: return;
287: }
288:
289: if (content_type == null) {
290: debug
291: .error(token_string
292: + ": "
293: + servlet_method
294: + ": Unable to get the content type for entry corresponding to "
295: + entry_number + " generated by "
296: + request_url);
297:
298: // FIXME: Are we doing the right thing here?
299: redirectAppropriately(entry.getRequestURL(),
300: request, response, client, sso_token,
301: token_string);
302: } else {
303: response.setContentType(content_type);
304:
305: String body = content.getContents();
306:
307: if (debug.messageEnabled()) {
308: debug.message(token_string + ": "
309: + servlet_method
310: + ": Sending out content type |"
311: + content_type + "| with content |"
312: + body + "|");
313: }
314:
315: /*
316: * Would anybody ever use ResponseBuffering for binary data?
317: * Highly implausible, so I guess we are on the right track here.
318: */
319: PrintWriter out = response.getWriter();
320: out.print(body);
321: }
322: }
323: }
324: }
325:
326: /**
327: * Gets the entry number for the response buffer entry from the query part
328: * of the request url
329: */
330: private Integer getEntryNumberFromRequest(HttpServletRequest request) {
331: String entry_number_string = request
332: .getParameter(_service.ENTRY_NUMBER);
333: if (entry_number_string == null) {
334: return (null);
335: }
336:
337: Integer entry_number = null;
338: try {
339: entry_number = Integer.valueOf(entry_number_string,
340: _service.ENTRY_NUMBER_RADIX);
341: } catch (NumberFormatException ne) {
342: entry_number = null;
343: }
344:
345: return (entry_number);
346: }
347:
348: /**
349: * Gets the Content object corresponding to the given request
350: */
351: private Content getContent(HttpServletRequest request,
352: ResponseBufferEntry entry, String token_string,
353: Logger logger) {
354: CacheManager manager = null;
355:
356: try {
357: if (entry != null) {
358: Cache cache = entry.getCache();
359: manager = cache_manager_factory.getCacheManager(cache,
360: logger);
361: }
362: } catch (StaleResponseBufferDataException e) {
363: debug
364: .error(token_string
365: + ": getContent(): Unable to get content for entry "
366: + entry.getEntryNumber()
367: + ", fails with StaleResponseBufferDataException");
368:
369: manager = null;
370: }
371:
372: Content content = null;
373:
374: if (manager != null) {
375: try {
376: content = manager.getContent(request);
377: } catch (Exception e) {
378: debug
379: .error(token_string
380: + ": getContent(): Unable to get content for entry "
381: + entry.getEntryNumber()
382: + ", fails with " + e.getMessage());
383: }
384: }
385:
386: return (content);
387: }
388:
389: /**
390: * If the given url is not null client is redirected there, else
391: * it is redirected to desktop.
392: */
393: private void redirectAppropriately(String url,
394: HttpServletRequest request, HttpServletResponse response,
395: Client client, SSOToken sso_token, String token_string)
396: throws IOException {
397: String redirect_url = (url != null) ? url : (_service
398: .getDesktopURL());
399: redirectWithBody(redirect_url, request, response, client,
400: sso_token, token_string);
401: }
402:
403: /**
404: * Gets the content type to be sent back to the client.
405: */
406: private String getContentTypeFromClient(Client client,
407: SSOToken sso_token, String token_string) {
408: String content_type = null;
409:
410: if (client != null) {
411: content_type = client.getProperty("contentType");
412: if (content_type != null) {
413:
414: String locale_string = null;
415: if (sso_token != null) {
416: try {
417: locale_string = sso_token.getProperty("Locale");
418: } catch (Exception e) {
419: // do nothing
420: }
421: }
422:
423: String charset = client.getCharset(Locale
424: .getLocale(locale_string));
425: if (charset != null) {
426:
427: StringBuffer buffer = new StringBuffer(content_type);
428: buffer.append("; charset=");
429: buffer.append(charset);
430:
431: content_type = buffer.toString();
432: }
433: }
434: }
435:
436: if (debug.messageEnabled()) {
437: debug.message(token_string
438: + ": getContentTypeFromClient(): content type is "
439: + ((content_type != null) ? content_type : ""));
440: }
441:
442: return (content_type);
443: }
444:
445: /**
446: * Gets the Client from the SSOToken in one of the following ways
447: *
448: * 1. For authenticated clients ClientType is retrieved from the
449: * SSO Token.
450: *
451: * 2. For others it uses AMClientDetector.getClientType(request)
452: */
453: private Client getClient(SSOToken sso_token,
454: HttpServletRequest request, String token_string)
455: throws SSOException {
456: String client_type = null;
457:
458: if (sso_token != null) {
459: client_type = sso_token.getProperty("clientType");
460: }
461:
462: if (client_type == null) {
463: client_type = client_detector.getClientType(request);
464: }
465:
466: Client client = null;
467:
468: if (client_type != null) {
469: try {
470: client = Client.getInstance(client_type);
471: } catch (ClientException ce) {
472: }
473: }
474:
475: if (client == null) {
476: client = Client.getDefaultInstance();
477: }
478:
479: if (client != null) {
480: client_type = client.getClientType();
481: } else {
482: client_type = "";
483: }
484:
485: if (debug.messageEnabled()) {
486: debug.message(token_string + ": getClient() "
487: + ": Got clientType of " + client_type
488: + " from SSO token");
489: }
490:
491: return (client);
492: }
493:
494: /**
495: * A convenience method which uses the HTTP method of the request to
496: * spit out the called servlet method.
497: *
498: * This is especially useful because doPost() is delegating to doGet()
499: */
500: private String getServletMethodName(HttpServletRequest request) {
501: String http_method = request.getMethod().trim().toLowerCase();
502:
503: String servlet_method = null;
504: if (GET_METHOD.equals(http_method)) {
505: servlet_method = "doGet()";
506: } else if (POST_METHOD.equals(http_method)) {
507: servlet_method = "doPost()";
508: } else {
509: // this will never be the case
510: servlet_method = http_method;
511: }
512:
513: return (servlet_method);
514: }
515:
516: /**
517: * Following method is used only when there is no
518: * SSOToken or the Resource for Markup is not found
519: * in the properties file
520: * <br><br>
521: * @param url String URL that is to be encoded
522: * @return String encoded URL
523: */
524: private String getDefaultAMLRedirectBody(String url) {
525: if (url == null) {
526: return (null);
527: }
528: // Encode the url using XML encoder as AML input needs to be valid XML
529: String encoded_url = URLEncoder.encode(url);
530: StringBuffer aml_markup_for_body = new StringBuffer(512);
531:
532: aml_markup_for_body.append(REDIRECT_PREFIX);
533: aml_markup_for_body.append(encoded_url);
534: aml_markup_for_body.append(REDIRECT_SUFFIX);
535:
536: return (aml_markup_for_body.toString());
537: }
538:
539: /**
540: * getAMLRedirectBody returns the <code><BODY></code>; for the
541: * redirect page, if the supplied SSOToken is null, it uses
542: * the <code>getDefaultAMLRedirectBody(String url)</code> method
543: * to return the redirect page with a default markup wrapped
544: * redirect url
545: * <br><br>
546: * @param url String that is to be encoded and inserted in body
547: * @param sso_token if a token exists it uses it to get the locale
548: * @return String containing the markup wrapped encoded url
549: */
550:
551: private String getAMLRedirectBody(String url, SSOToken sso_token) {
552:
553: ResourceBundle bundle = null;
554: String aml_markup_from_props = null;
555: String aml_markup_for_body = null;
556: String locale_str = null;
557:
558: if (url == null) {
559: return (null);
560: }
561:
562: // Encode the url using XML encoder as AML input needs to be valid XML
563: String encoded_url = URLEncoder.encode(url);
564:
565: //Get the ResourceBundle
566: try {
567: //if there is a sso token get the locale from it
568: if (sso_token != null) {
569: locale_str = sso_token.getProperty("Locale");
570: }
571:
572: //get the bundle using the locale from token
573: if (locale_str != null) {
574: bundle = ResourceBundle.getBundle("ResponseBuffer",
575: Locale.getLocale(locale_str));
576: } else {
577: //if locale is null use the default locale to get bundle
578: bundle = ResourceBundle.getBundle("ResponseBuffer",
579: Locale.getDefaultLocale());
580: }
581:
582: //Now get the markup from resource bundle key "redirectPage"
583: aml_markup_from_props = bundle.getString("redirectPage");
584:
585: } catch (SSOException sse) {
586: //return default HardCoded page if there is SSOException
587: if (debug.messageEnabled()) {
588: debug.message(
589: "ResponseBufferServlet.getAMLRedirectBody(): ",
590: sse);
591: }
592: return getDefaultAMLRedirectBody(url);
593: } catch (MissingResourceException mre) {
594: //return default HardCoded page if there is
595: //no "redirectPage" key
596: if (debug.messageEnabled()) {
597: debug.message(
598: "ResponseBufferServlet.getAMLRedirectBody(): ",
599: mre);
600: }
601: return getDefaultAMLRedirectBody(url);
602: }
603:
604: //Log the string read from the props file
605: if (debug.messageEnabled()) {
606: debug
607: .message("ResponseBufferServlet.getAMLRedirectBody(): "
608: + "Redirect page from properties file = "
609: + aml_markup_from_props);
610: }
611:
612: //Now substitute the TOKEN [REDIRECT_URL] in the markup
613: //obtained from "ResponseBuffer.properties" file
614:
615: if (aml_markup_from_props != null) {
616: int start = aml_markup_from_props.indexOf("[REDIRECT_URL]");
617: if (start != -1) {
618: int end = start + 14;
619: StringBuffer errBuf = new StringBuffer(
620: aml_markup_from_props);
621: aml_markup_for_body = (errBuf.replace(start, end,
622: encoded_url)).toString();
623: } else {
624: aml_markup_for_body = aml_markup_from_props;
625: }
626:
627: if (debug.messageEnabled()) {
628: debug
629: .message("ResponseBufferServlet.getAMLRedirectBody(): "
630: + "Redirect Page with url = "
631: + aml_markup_for_body);
632: }
633:
634: } else {
635: //if no key exists, return the default page
636: aml_markup_for_body = getDefaultAMLRedirectBody(url);
637: }
638:
639: return (aml_markup_for_body);
640:
641: }
642:
643: private String getNativeRedirectBody(String url, Client client,
644: String token_string, SSOToken sso_token) {
645: if (client == null) {
646: return (null);
647: }
648:
649: String native_markup_for_body = null;
650:
651: String aml_markup_for_body = getAMLRedirectBody(url, sso_token);
652: if (aml_markup_for_body != null) {
653: if (debug.messageEnabled()) {
654: debug
655: .message(token_string
656: + ": getNativeRedirectBody(): AML body for redirect is "
657: + aml_markup_for_body);
658: }
659:
660: String log_name = "ResponseBufferServlet:getNativeRedirectBody:"
661: + token_string;
662: RenderingEngine engine = rendering_engine_factory
663: .getEngine(null, log_name);
664:
665: try {
666: Content content = engine.renderContent(
667: aml_markup_for_body, client, false, false);
668: if (content != null) {
669: native_markup_for_body = content.getContents();
670: if (debug.messageEnabled()) {
671: debug
672: .message(token_string
673: + ": getNativeRedirectBody(): Native body for redirect is "
674: + native_markup_for_body);
675: }
676: } else {
677: if (debug.messageEnabled()) {
678: debug
679: .message(token_string
680: + ": getNativeRedirectBody(): Native body for redirect is null");
681: }
682: }
683: } catch (RenderingException re) {
684: if (debug.messageEnabled()) {
685: debug
686: .message(
687: token_string
688: + ": getNativeRedirectBody(): Rendering exception",
689: re);
690: }
691:
692: native_markup_for_body = null;
693: }
694: }
695:
696: return (native_markup_for_body);
697: }
698:
699: private void sendRedirect(String url, HttpServletResponse response,
700: String body, String content_type, String token_string)
701: throws IOException {
702: if (debug.messageEnabled()) {
703: debug.message(token_string
704: + ": sendRedirect(): Sending a redirect to " + url);
705: }
706:
707: if (body != null) {
708: if (content_type != null) {
709: response.setContentType(content_type);
710: }
711:
712: response.setStatus(response.SC_MOVED_TEMPORARILY);
713: response.setHeader("Location", url);
714:
715: PrintWriter out = response.getWriter();
716: out.print(body);
717:
718: response.flushBuffer();
719: } else {
720: response.sendRedirect(url);
721: }
722: }
723:
724: /**
725: * A convenience method for doing redirects. This method sets the
726: * appropriate body before doing the redirect.
727: */
728: private void redirectWithBody(String url,
729: HttpServletRequest request, HttpServletResponse response,
730: Client client, SSOToken sso_token, String token_string)
731: throws IOException {
732: // first find the content type to be sent
733: String content_type = getContentTypeFromClient(client,
734: sso_token, token_string);
735:
736: redirectWithBodyAndContentType(url, request, response, client,
737: content_type, token_string, sso_token);
738: }
739:
740: /**
741: * A convenience method for doing redirects. This method sets the
742: * appropriate body before doing the redirect.
743: */
744: private void redirectWithBodyAndContentType(String url,
745: HttpServletRequest request, HttpServletResponse response,
746: Client client, String content_type, String token_string,
747: SSOToken sso_token) throws IOException {
748: String absolute_url = getAbsoluteURL(url, request, client,
749: token_string);
750:
751: String native_markup_for_body = getNativeRedirectBody(
752: absolute_url, client, token_string, sso_token);
753: sendRedirect(absolute_url, response, native_markup_for_body,
754: content_type, token_string);
755: }
756:
757: private static String getAbsoluteURL(String url,
758: HttpServletRequest request, Client client,
759: String token_string) {
760: String absolute_url = null;
761:
762: try {
763: absolute_url = ResponseBufferService.getAbsoluteURL(url,
764: request, client);
765: } catch (Exception e) {
766: debug
767: .message(token_string
768: + ": getAbsoluteURL(): Failed to convert into absolute url "
769: + url);
770: absolute_url = url;
771: }
772:
773: return (absolute_url);
774: }
775:
776: private static final String POST_METHOD = "post";
777: private static final String GET_METHOD = "get";
778:
779: private static final String REDIRECT_PREFIX = "<AmlDocument title=\"Redirect\"><AmlPage><AmlLink text=\"New Location\" url=\"";
780:
781: private static final String REDIRECT_SUFFIX = "\"/></AmlPage></AmlDocument>";
782:
783: }
|