001: //** Copyright Statement ***************************************************
002: //The Salmon Open Framework for Internet Applications (SOFIA)
003: // Copyright (C) 1999 - 2002, Salmon LLC
004: //
005: // This program is free software; you can redistribute it and/or
006: // modify it under the terms of the GNU General Public License version 2
007: // as published by the Free Software Foundation;
008: //
009: // This program is distributed in the hope that it will be useful,
010: // but WITHOUT ANY WARRANTY; without even the implied warranty of
011: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: // GNU General Public License for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // along with this program; if not, write to the Free Software
016: // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
017: //
018: // For more information please visit http://www.salmonllc.com
019: //** End Copyright Statement ***************************************************
020: package com.salmonllc.jsp.tags;
021:
022: /////////////////////////
023: //$Archive: /SOFIA/SourceCode/com/salmonllc/jsp/tags/PageTag.java $
024: //$Author: Dan $
025: //$Revision: 82 $
026: //$Modtime: 8/25/04 11:34a $
027: /////////////////////////
028:
029: import java.net.SocketException;
030: import java.util.Hashtable;
031: import java.util.Vector;
032:
033: import javax.servlet.http.HttpServletRequest;
034: import javax.servlet.http.HttpServletResponse;
035: import javax.servlet.http.HttpSession;
036: import javax.servlet.http.HttpSessionBindingEvent;
037: import javax.servlet.http.HttpSessionBindingListener;
038: import javax.servlet.jsp.JspException;
039: import javax.servlet.jsp.tagext.BodyTag;
040: import javax.servlet.jsp.tagext.TagSupport;
041:
042: import com.salmonllc.html.HtmlPageBase;
043: import com.salmonllc.html.HtmlValidatorText;
044: import com.salmonllc.html.HttpServletResponseWrapper;
045: import com.salmonllc.jsp.JspController;
046: import com.salmonllc.jsp.JspServlet;
047: import com.salmonllc.personalization.Skin;
048: import com.salmonllc.personalization.SkinManager;
049: import com.salmonllc.portlet.PortletInfo;
050: import com.salmonllc.portlet.SalmonPortlet;
051: import com.salmonllc.portlet.SalmonPortletException;
052: import com.salmonllc.properties.Props;
053: import com.salmonllc.sql.DB2SalvageException;
054: import com.salmonllc.util.MessageLog;
055: import com.salmonllc.util.URLGenerator;
056:
057: /**
058: * The page tag is the parent for all the tags in the library. It controls the flow of and processing for the rest of the tags
059: */
060:
061: public class PageTag extends TagSupport {
062: private String _controller;
063: private String _secondaryController;
064: private String _application;
065: private String _contenttype;
066: private boolean _alwaysCreateNew = false;
067: private String _keepOnSession = null;
068: private String _sessionKeepAlive = null;
069: private int _startTagRet = 0;
070:
071: private TagContext _tagContext;
072: private boolean _isWml = false;
073: private boolean _isWmlMaintained = false;
074: private static Hashtable _wmlSessions = new Hashtable();
075: private static String _sessidentifier = ";jid";
076:
077: private class WmlSession implements HttpSessionBindingListener {
078: private String _sessId;
079: private HttpSession _sess;
080:
081: public WmlSession(String sessId, HttpSession sess) {
082: _sessId = sessId;
083: _sess = sess;
084: }
085:
086: public void valueBound(HttpSessionBindingEvent hsbe) {
087: }
088:
089: public void valueUnbound(HttpSessionBindingEvent hsbe) {
090: PageTag.removeSession(_sessId);
091: PageTag.removeSession(_sess);
092: }
093: }
094:
095: public static String getSessionIdentifier() {
096: return _sessidentifier;
097: }
098:
099: public static HttpSession getSession(String sessid) {
100: if (sessid == null)
101: return null;
102: return (HttpSession) _wmlSessions.get(sessid);
103: }
104:
105: public static String getWmlSessId(HttpSession sess) {
106: if (sess == null)
107: return null;
108: return (String) _wmlSessions.get(sess);
109: }
110:
111: public static void removeSession(String sessid) {
112: if (sessid == null)
113: return;
114: _wmlSessions.remove(sessid);
115: }
116:
117: public static void removeSession(HttpSession sess) {
118: if (sess == null)
119: return;
120: _wmlSessions.remove(sess);
121: }
122:
123: private void maintainWmlSession(String sessid, HttpSession sess) {
124: _wmlSessions.put(sessid, sess);
125: _wmlSessions.put(sess, sessid);
126: if (sess.getAttribute("wmlsession") == null)
127: sess.setAttribute("wmlsession",
128: new WmlSession(sessid, sess));
129: }
130:
131: /**
132: * Removes the page from the session
133: */
134: public void clearFromSession() {
135: HttpSession sess = pageContext.getSession();
136: if (sess.getAttribute("$jsp$"
137: + _tagContext.getControllerObject().getSessionKey()) != null)
138: sess
139: .removeAttribute("$jsp$"
140: + _tagContext.getControllerObject()
141: .getSessionKey());
142:
143: }
144:
145: /**
146: * This method is part of the JSP tag library specification
147: */
148: public int doStartTag() throws JspException {
149: int retVal = BodyTag.EVAL_BODY_INCLUDE;
150: _startTagRet = retVal;
151: _isWmlMaintained = false;
152: _isWml = false;
153: if (_contenttype != null) {
154: if (_contenttype.endsWith(".wml")) {
155: _isWml = true;
156: if (Props
157: .getProps(getApplication(), "")
158: .getBooleanProperty(Props.WML_MAINTAIN_SESSIONS))
159: _isWmlMaintained = true;
160: }
161: }
162: try {
163: HttpServletRequest req = (HttpServletRequest) pageContext
164: .getRequest();
165: _tagContext = getTagContext();
166: try {
167: boolean genVars = req.getParameter("vars") != null;
168: boolean genCode = req.getParameter("generateCode") != null;
169: boolean sessionKeepAlive = req
170: .getParameter("sessionKeepAlive") != null;
171: if ((genVars || genCode)
172: && !Props.getSystemProps().getBooleanProperty(
173: Props.SYS_ENABLE_CODE_GENERATION, true)) {
174: genVars = false;
175: genCode = false;
176: }
177: _tagContext.setPrintingVars(genVars);
178: _tagContext.setGenerateCode(genCode);
179: if (sessionKeepAlive) {
180: getJSPController().generateSessionKeepAliveHtml(
181: pageContext.getOut());
182: _startTagRet = SKIP_PAGE;
183: return SKIP_PAGE;
184: }
185:
186: } catch (Exception e) {
187: }
188:
189: _tagContext.setControllerObject(getJSPController());
190: JspController controllerObject = _tagContext
191: .getControllerObject();
192: if (!_tagContext.isPrintingVars()
193: && !_tagContext.isGenerateCode()) {
194: if (!_tagContext.isInitializing()) {
195: long time = System.currentTimeMillis();
196: while (controllerObject.isInitializing()) {
197: Thread.sleep(500);
198: if ((System.currentTimeMillis() - time) > 5000) {
199: clearFromSession();
200: controllerObject.sendPageRedirect();
201: return retVal;
202: }
203: }
204:
205: synchronized (controllerObject) {
206: if (!_tagContext.getDreamWeaverMode()
207: && !controllerObject.isInitialized()) {
208: controllerObject.autoBindComponents();
209: setUpValidators(_tagContext
210: .getValidatorAttributes(),
211: controllerObject);
212:
213: Skin sk = controllerObject.getSkin();
214: if (sk != null)
215: controllerObject.applySkin(sk, false);
216:
217: controllerObject.initializeContainers();
218: controllerObject.initialize();
219: if (controllerObject
220: .getSecondaryController() != null)
221: controllerObject
222: .getSecondaryController()
223: .initialize();
224:
225: controllerObject.setInitialized();
226: }
227:
228: _tagContext.setRefIndexPrinted(false);
229: if (_contenttype != null) {
230: controllerObject
231: .setContentType(_contenttype);
232: (pageContext.getResponse())
233: .setContentType(_contenttype);
234: if (_isWmlMaintained) {
235: controllerObject.setWMLMaintained(true);
236: }
237: }
238: if (!_isWml) {
239: if (controllerObject.isRequestFromPortlet()) {
240: if (controllerObject.getPortletInfo()
241: .getRenderRequest() != null) {
242: controllerObject
243: .incrementRefIndex();
244: retVal = controllerObject.doGet(
245: req, true);
246: } else {
247: retVal = controllerObject
248: .doPost(
249: req,
250: (HttpServletResponse) pageContext
251: .getResponse());
252: }
253: } else if (req.getMethod().equals("GET")
254: || controllerObject
255: .isRequestFromForward()) {
256: controllerObject.incrementRefIndex();
257: retVal = controllerObject.doGet(req,
258: true);
259: } else if (req.getMethod().equals("POST")) {
260: retVal = controllerObject
261: .doPost(
262: req,
263: (HttpServletResponse) pageContext
264: .getResponse());
265: HttpServletResponseWrapper res = (HttpServletResponseWrapper) controllerObject
266: .getCurrentResponse();
267: if (!controllerObject
268: .getDoPostRedirected()
269: && !res.getRedirectSent())
270: controllerObject.doGet(req, true);
271: }
272:
273: } else {
274: if (req.getMethod().equals("POST")
275: || (req.getParameter("method") != null && req
276: .getParameter("method")
277: .toUpperCase().equals(
278: "POST"))) {
279: retVal = controllerObject
280: .doPost(
281: req,
282: (HttpServletResponse) pageContext
283: .getResponse());
284: } else
285: retVal = controllerObject.doGet(req,
286: true);
287: }
288: }
289: } else if (!_tagContext.getDreamWeaverMode()
290: && (req
291: .getAttribute(JspServlet.SALMON_SERVLET_KEY) == null))
292: controllerObject.sendPageRedirect();
293: } else if (!_tagContext.getDreamWeaverMode()
294: && (req.getAttribute(JspServlet.SALMON_SERVLET_KEY) == null)
295: && _tagContext.isInitializing())
296: controllerObject.sendPageRedirect();
297: } catch (SocketException e) {
298: // ignore java.net.SocketException
299: MessageLog.writeInfoMessage(
300: "SocketException would have been thrown", this );
301:
302: } catch (SalmonPortletException ex) {
303: //let this bubble up to the SalmonPortlet and let it handle it
304: throw new JspException(ex);
305: } catch (Exception e) {
306: MessageLog.writeErrorMessage("doStartTag", e, this );
307: if (e.getClass().getName().equals(
308: "com.ibm.db2.jcc.c.SqlException"))
309: throw new DB2SalvageException(e);
310: throw new JspException(e.getMessage());
311: }
312: _startTagRet = retVal;
313: return retVal;
314: }
315:
316: public int doEndTag() throws JspException {
317: return _startTagRet;
318: }
319:
320: public static String generateSessionName(PortletInfo info) {
321: String jsp = info.getPortletJsp();
322: if (jsp == null)
323: return info.getPortletName();
324: int pos = jsp.indexOf("?");
325: if (pos > -1)
326: jsp = jsp.substring(0, pos);
327: return encodeSessionName(info.getPortletName() + jsp);
328: }
329:
330: public static String generateSessionName(HttpServletRequest req) {
331: PortletInfo inf = (PortletInfo) req
332: .getAttribute(SalmonPortlet.PORTLET_INFO_TOKEN);
333: if (inf != null)
334: return generateSessionName(inf);
335: else
336: return encodeSessionName(req.getRequestURI());
337: }
338:
339: private static String encodeSessionName(String sesName) {
340: StringBuffer sb = new StringBuffer(sesName);
341: for (int i = 0; i < sb.length(); i++)
342: if (sb.charAt(i) == '/')
343: sb.setCharAt(i, '.');
344: return sb.toString();
345: }
346:
347: /**
348: * This method returns the application that the page is associated with
349: */
350: public String getApplication() {
351: if (_application != null) {
352: return _application;
353: } else {
354: try {
355: String base = URLGenerator
356: .generateServletBaseURL((HttpServletRequest) pageContext
357: .getRequest());
358: if (base == null || base.length() == 0)
359: return "none";
360: int ndx = base.indexOf("/");
361: if (ndx == -1)
362: return base;
363: else
364: return base.substring(0, ndx);
365: } catch (Exception e) {
366: return "none";
367: }
368: }
369: /*
370: else if (_controller == null)
371: return "none";
372: else {
373: int pos = _controller.lastIndexOf(".");
374: if (pos == -1)
375: return "none";
376: else {
377: String retVal = _controller.substring(0, pos);
378: pos = retVal.lastIndexOf(".");
379: if (pos != -1)
380: retVal = retVal.substring(pos + 1);
381: return retVal;
382: }
383: }*/
384: }
385:
386: /**
387: * This method returns the name of the JSP Controller object used by the page
388: */
389: public String getController() {
390: return _controller;
391: }
392:
393: private String getShortenedSessId(String sessid) {
394: String sessID = sessid;
395: int iWmlSessLen = Props.getProps(getApplication(), "")
396: .getIntProperty(Props.WML_SESSION_KEY_LENGTH);
397: if (iWmlSessLen < sessID.length()) {
398: String sTmpSessId = sessID.substring(0, iWmlSessLen);
399: if (_wmlSessions.get(sTmpSessId) == null) {
400: sessID = sTmpSessId;
401: } else {
402: sTmpSessId = sessID.substring(0, iWmlSessLen - 1);
403: for (int i = iWmlSessLen; i < sessID.length(); i++) {
404: sTmpSessId += sessID.charAt(i);
405: if (_wmlSessions.get(sTmpSessId) == null) {
406: sessID = sTmpSessId;
407: break;
408: }
409: }
410: }
411: }
412: return sessID;
413: }
414:
415: private JspController getJSPController() throws Exception {
416: HttpServletRequest req = (HttpServletRequest) pageContext
417: .getRequest();
418: HttpServletResponse res = (HttpServletResponse) pageContext
419: .getResponse();
420: ClassLoader loader = Thread.currentThread()
421: .getContextClassLoader();
422:
423: boolean sessExp = false;
424: HttpSession sess = null;
425: String sessID = null;
426: if (_isWmlMaintained) {
427: sessID = req.getParameter(_sessidentifier);
428: if (sessID != null) {
429: sess = (HttpSession) _wmlSessions.get(sessID);
430: if (sess == null) {
431: sess = req.getSession(true);
432: sessID = sess.getId();
433: sessID = getShortenedSessId(sessID);
434: maintainWmlSession(sessID, sess);
435: }
436: } else {
437: sess = req.getSession(true);
438: sessID = sess.getId();
439: sessID = getShortenedSessId(sessID);
440: maintainWmlSession(sessID, sess);
441: }
442: } else {
443: sessID = req.getRequestedSessionId();
444: boolean sessValid = req.isRequestedSessionIdValid();
445: if (sessID != null && !sessValid)
446: sessExp = true;
447: sess = req.getSession(true);
448: }
449:
450: synchronized (sess) {
451: if (sess.getAttribute("AppServer_SessExp") != null) {
452: sessExp = true;
453: sess.removeAttribute("AppServer_SessExp");
454: }
455:
456: JspServlet.setUpApplicationContext(pageContext
457: .getServletContext(),
458: (HttpServletRequest) pageContext.getRequest());
459: Props p = Props.getProps(getApplication(), null);
460: String cName = _controller;
461: JspController ret = null;
462: JspController sec = null;
463: Object o = null;
464: String sesName = null;
465:
466: _tagContext.setInitializing(false);
467: String sessKey = generateSessionName(req);
468: sesName = "$jsp$" + sessKey;
469:
470: o = sess.getAttribute(sesName);
471:
472: if (o != null && _alwaysCreateNew) {
473: sess.removeAttribute(sesName);
474: o = null;
475: }
476:
477: if (o != null)
478: ret = (JspController) o;
479: else {
480: _tagContext.setInitializing(true);
481: Class c = null;
482: Class c2 = null;
483:
484: //get the primary controller class
485: try {
486: if (cName == null)
487: c = JspController.class;
488: else
489: c = Class.forName(cName, true, loader);
490: } catch (ClassNotFoundException eX) {
491: c = JspController.class;
492: if (!(_tagContext.isPrintingVars() || _tagContext
493: .isGenerateCode()))
494: MessageLog.writeErrorMessage(
495: "Couldn't find controller class:"
496: + cName, eX, this );
497: } catch (LinkageError eX) {
498: MessageLog.writeErrorMessage(
499: "Couldn't find page class:" + cName, eX,
500: this );
501: return null;
502: }
503:
504: //get the secondary controller class
505: try {
506: if (_secondaryController != null)
507: c2 = Class.forName(_secondaryController, true,
508: loader);
509: } catch (ClassNotFoundException eX) {
510: if (!(_tagContext.isPrintingVars() || _tagContext
511: .isGenerateCode()))
512: c2 = JspController.class;
513: MessageLog.writeErrorMessage(
514: "Couldn't find page class:"
515: + _secondaryController, eX, this );
516: } catch (LinkageError eX) {
517: MessageLog.writeErrorMessage(
518: "Couldn't find page class:"
519: + _secondaryController, eX, this );
520: return null;
521: }
522:
523: Object h = sess
524: .getAttribute(HtmlPageBase.APPLICATION_ALIAS_SESSION_KEY);
525: String appAlias = null;
526: String application = getApplication();
527: if (h != null)
528: appAlias = (String) ((Hashtable) h)
529: .get(application);
530: ret = (JspController) c.newInstance();
531:
532: if (c2 != null) {
533: sec = (JspController) c2.newInstance();
534: ret.setSecondaryController(sec);
535: }
536:
537: ret.setOrigApplicationName(application);
538: if (appAlias != null)
539: ret.setApplicationName(appAlias);
540: else
541: ret.setApplicationName(application);
542: ret.setSessionKey(sessKey);
543:
544: String pageName = req.getRequestURI();
545: int pos = pageName.lastIndexOf("/");
546: if (pos > -1)
547: pageName = pageName.substring(pos + 1);
548: ret.setPageName(pageName);
549:
550: ret.setKeepOnSession(BaseTagHelper.stringToBoolean(
551: _keepOnSession, true));
552: ret.setSession(sess);
553: if (ret.getSkin() == null) {
554: String defSkin = p.getProperty(Props.SKIN_DEFAULT);
555: if (defSkin != null) {
556: SkinManager man = SkinManager
557: .getSkinManager(application);
558: Skin sk = new Skin();
559: man.load(defSkin, sk);
560: ret.setSkin(sk);
561: }
562: }
563: ret.loadProperties();
564: if (_sessionKeepAlive != null)
565: ret.setSessionKeepAliveMinutes(BaseTagHelper
566: .stringToInt(_sessionKeepAlive));
567: sess.setAttribute(sesName, ret);
568: }
569:
570: ret.setCurrentRequest(req);
571: ret.setCurrentResponse(res);
572: ret.setSession(sess);
573: ret.setSessionExpired(sessExp);
574: ret.setPageContext(pageContext);
575:
576: if (req.getScheme() == null
577: || req.getScheme().equalsIgnoreCase("http"))
578: ret.setServerURL(URLGenerator.generateServerURL(req));
579: else
580: ret.setServerURL(URLGenerator
581: .generateSecureServerURL(req));
582: ret.setServletBaseURL(URLGenerator
583: .generateServletBaseURL(req));
584: ret.setForwardPerformed(false);
585:
586: PortletInfo pInf = (PortletInfo) req
587: .getAttribute(SalmonPortlet.PORTLET_INFO_TOKEN);
588: if (pInf != null)
589: ret.setDisableRedirect(true);
590: ret.setPortletInfo(pInf);
591: ret.setUpLanguagePreferences();
592:
593: return ret;
594: }
595: }
596:
597: /**
598: * This method returns the name of the Secondary JSP Controller object used by the page
599: */
600: public String getSecondarycontroller() {
601: return _controller;
602: }
603:
604: /**
605: * Releases the resources used by the object
606: */
607:
608: public void release() {
609: _controller = null;
610: _secondaryController = null;
611: _application = null;
612: _keepOnSession = null;
613: _sessionKeepAlive = null;
614: _contenttype = null;
615: _tagContext = null;
616: _isWml = false;
617: _isWmlMaintained = false;
618: _tagContext = null;
619: }
620:
621: /**
622: * Set to true if the object should always create a new controller object when the page is called instead of getting the controller from the session.
623: */
624: public void setAlwaysCreateNewController(boolean alwaysCreate) {
625: _alwaysCreateNew = alwaysCreate;
626:
627: }
628:
629: /**
630: * Set to true if the object should be kept on the session after it is called for the first time.
631: */
632: public void setKeeponsession(String keep) {
633: _keepOnSession = keep;
634: }
635:
636: public void setSessionkeepaliveminutes(String minutes) {
637: _sessionKeepAlive = minutes;
638: }
639:
640: /**
641: * This method sets the application attribute for the page
642: */
643:
644: public void setApplication(String newApplication) {
645: _application = newApplication;
646: }
647:
648: /**
649: * This method sets the controller attribute for the page
650: */
651: public void setController(String newController) {
652: _controller = newController;
653: }
654:
655: /**
656: * This method sets the contenttype attribute for the page
657: */
658: public void setContenttype(String contenttype) {
659: _contenttype = contenttype;
660: }
661:
662: /**
663: * This method sets the secondary controller attribute for the page
664: */
665: public void setSecondarycontroller(String newController) {
666: _secondaryController = newController;
667: }
668:
669: /**
670: * Sets the dreamWeaverMode.
671: * @param dreamWeaverMode The dreamWeaverMode to set
672: */
673: public void setDreamWeaverMode(boolean dreamWeaverMode) {
674: getTagContext();
675: _tagContext.setDreamWeaverMode(dreamWeaverMode);
676: }
677:
678: /**
679: * Returns the controllerClass.
680: * @return JspController
681: */
682: public JspController getControllerObject() {
683: return _tagContext.getControllerObject();
684: }
685:
686: public TagContext getTagContext() {
687: HttpServletRequest req = (HttpServletRequest) pageContext
688: .getRequest();
689: _tagContext = (TagContext) req
690: .getAttribute(TagContext.TAG_CONTEXT_REQ_KEY);
691: if (_tagContext == null) {
692: _tagContext = new TagContext(_controller);
693: req.setAttribute(TagContext.TAG_CONTEXT_REQ_KEY,
694: _tagContext);
695: }
696: return _tagContext;
697: }
698:
699: private void setUpValidators(Vector attList, JspController cont) {
700: try {
701: if (attList != null) {
702: for (int i = 0; i < attList.size(); i++) {
703: ValidatorTag.Attributes att = (ValidatorTag.Attributes) attList
704: .elementAt(i);
705: HtmlValidatorText val = (HtmlValidatorText) cont
706: .getComponent(att.name);
707: if (val == null)
708: throw new NullPointerException(
709: "Could not find validator component:"
710: + att.name);
711: ValidatorTag.setUpValidator(att, val, cont);
712: }
713: }
714: } catch (Exception e) {
715: MessageLog.writeErrorMessage("setUpValidators()", e, this);
716: }
717: }
718: }
|