001/* 002 * Copyright (c) 2013 Nu Echo Inc. All rights reserved. 003 */ 004 005package com.nuecho.rivr.core.servlet.session; 006 007import javax.servlet.http.*; 008 009import com.nuecho.rivr.core.channel.*; 010import com.nuecho.rivr.core.channel.synchronous.*; 011import com.nuecho.rivr.core.dialogue.*; 012import com.nuecho.rivr.core.servlet.*; 013import com.nuecho.rivr.core.util.*; 014 015/** 016 * Contains everything that is required for the dialogue to run in a 017 * {@link DialogueServlet} controller. 018 * <p> 019 * NOTE: a Rivr {@link Session} can be linked with an {@link HttpSession}. This 020 * can be useful to maintain server stickyness in a clustered environment with 021 * load balancers. Web container generates JSESSIONID cookies for session 022 * tracking purpose but this information is also used by load balancer equipment 023 * between the HTTP user agent and the server to preserve server stickyness. 024 * 025 * @param <F> type of {@link FirstTurn} 026 * @param <L> type of {@link LastTurn} 027 * @param <O> type of {@link OutputTurn} 028 * @param <I> type of {@link InputTurn} 029 * @param <C> type of {@link DialogueContext} 030 * @see DialogueServlet 031 * @see SessionContainer 032 * @author Nu Echo Inc. 033 */ 034public final class Session<I extends InputTurn, O extends OutputTurn, F extends FirstTurn, L extends LastTurn, C extends DialogueContext<I, O>> 035 implements DialogueChannelListener<I, O> { 036 private SynchronousDialogueChannel<I, O, F, L, C> mDialogueChannel; 037 038 private C mDialogueContext; 039 040 private final SessionContainer<I, O, F, L, C> mContainer; 041 private final String mId; 042 private HttpSession mAssociatedHttpSession; 043 044 public Session(SessionContainer<I, O, F, L, C> container, String sessionId) { 045 mContainer = container; 046 mId = sessionId; 047 } 048 049 @Override 050 public void onStart(DialogueChannel<I, O> dialogueChannel) {} 051 052 @Override 053 public void onStop(DialogueChannel<I, O> dialogueChannel) { 054 stop(); 055 } 056 057 public synchronized void stop() { 058 if (mDialogueChannel != null && mDialogueChannel.isDialogueActive()) { 059 mDialogueChannel.stop(); 060 } 061 062 mContainer.removeSession(mId); 063 064 if (mAssociatedHttpSession != null) { 065 try { 066 mAssociatedHttpSession.invalidate(); 067 } catch (IllegalStateException exception) { 068 //already invalidated 069 } 070 mAssociatedHttpSession = null; 071 } 072 } 073 074 public void keepAlive() { 075 if (mAssociatedHttpSession != null) { 076 mAssociatedHttpSession.getAttributeNames(); 077 } 078 } 079 080 public String getId() { 081 return mId; 082 } 083 084 public SynchronousDialogueChannel<I, O, F, L, C> getDialogueChannel() { 085 return mDialogueChannel; 086 } 087 088 public void setDialogueChannel(SynchronousDialogueChannel<I, O, F, L, C> dialogueChannel) { 089 mDialogueChannel = dialogueChannel; 090 mDialogueChannel.addListener(this); 091 } 092 093 public C getDialogueContext() { 094 return mDialogueContext; 095 } 096 097 public void setDialogueContext(C dialogueContext) { 098 mDialogueContext = dialogueContext; 099 } 100 101 public void setAssociatedHttpSession(HttpSession associatedHttpSession) { 102 mAssociatedHttpSession = associatedHttpSession; 103 } 104 105 @Override 106 public String toString() { 107 ToStringBuilder builder = new ToStringBuilder(this); 108 builder.appendItem("mDialogueChannel", mDialogueChannel); 109 builder.appendItem("mDialogueContext", mDialogueContext); 110 builder.appendItem("mId", mId); 111 return builder.getString(); 112 } 113}