001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.webflow.conversation.impl;
017:
018: import java.io.IOException;
019: import java.io.ObjectInputStream;
020: import java.io.ObjectOutputStream;
021: import java.io.Serializable;
022: import java.util.HashMap;
023: import java.util.Map;
024:
025: import org.apache.commons.logging.Log;
026: import org.apache.commons.logging.LogFactory;
027: import org.springframework.webflow.context.ExternalContextHolder;
028: import org.springframework.webflow.conversation.Conversation;
029: import org.springframework.webflow.conversation.ConversationId;
030: import org.springframework.webflow.core.collection.SharedAttributeMap;
031:
032: /**
033: * Internal {@link Conversation} implementation used by the conversation
034: * container.
035: * <p>
036: * This is an internal helper class of the {@link SessionBindingConversationManager}.
037: *
038: * @author Erwin Vervaet
039: */
040: class ContainedConversation implements Conversation, Serializable {
041:
042: private static final Log logger = LogFactory
043: .getLog(SessionBindingConversationManager.class);
044:
045: private ConversationContainer container;
046:
047: private ConversationId id;
048:
049: private transient ConversationLock lock;
050:
051: private Map attributes;
052:
053: /**
054: * Create a new contained conversation.
055: * @param container the container containing the conversation
056: * @param id the unique id assigned to the conversation
057: */
058: public ContainedConversation(ConversationContainer container,
059: ConversationId id) {
060: this .container = container;
061: this .id = id;
062: this .lock = ConversationLockFactory.createLock();
063: this .attributes = new HashMap();
064: }
065:
066: public ConversationId getId() {
067: return id;
068: }
069:
070: public void lock() {
071: if (logger.isDebugEnabled()) {
072: logger.debug("Locking conversation " + id);
073: }
074: lock.lock();
075: }
076:
077: public Object getAttribute(Object name) {
078: return attributes.get(name);
079: }
080:
081: public void putAttribute(Object name, Object value) {
082: if (logger.isDebugEnabled()) {
083: logger.debug("Putting conversation attribute '" + name
084: + "' with value " + value);
085: }
086: attributes.put(name, value);
087: }
088:
089: public void removeAttribute(Object name) {
090: if (logger.isDebugEnabled()) {
091: logger.debug("Removing conversation attribute '" + name
092: + "'");
093: }
094: attributes.remove(name);
095: }
096:
097: public void end() {
098: if (logger.isDebugEnabled()) {
099: logger.debug("Ending conversation " + id);
100: }
101: container.removeConversation(getId());
102: }
103:
104: public void unlock() {
105: if (logger.isDebugEnabled()) {
106: logger.debug("Unlocking conversation " + id);
107: }
108: lock.unlock();
109:
110: // re-bind the conversation container in the session
111: // this is required to make session replication work correctly in
112: // a clustered environment
113: // we do this after releasing the lock since we're no longer
114: // manipulating the contents of the conversation
115: SharedAttributeMap sessionMap = ExternalContextHolder
116: .getExternalContext().getSessionMap();
117: synchronized (sessionMap.getMutex()) {
118: sessionMap.put(container.getSessionKey(), container);
119: }
120: }
121:
122: public String toString() {
123: return getId().toString();
124: }
125:
126: // id based equality
127:
128: public boolean equals(Object obj) {
129: if (!(obj instanceof ContainedConversation)) {
130: return false;
131: }
132: return id.equals(((ContainedConversation) obj).id);
133: }
134:
135: public int hashCode() {
136: return id.hashCode();
137: }
138:
139: // custom serialisation
140:
141: private void writeObject(ObjectOutputStream out) throws IOException {
142: out.defaultWriteObject();
143: }
144:
145: private void readObject(ObjectInputStream in) throws IOException,
146: ClassNotFoundException {
147: in.defaultReadObject();
148: lock = ConversationLockFactory.createLock();
149: }
150: }
|