001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.acting;
018:
019: import org.apache.avalon.framework.configuration.Configuration;
020: import org.apache.avalon.framework.configuration.ConfigurationException;
021: import org.apache.avalon.framework.parameters.Parameters;
022: import org.apache.avalon.framework.thread.ThreadSafe;
023: import org.apache.cocoon.environment.ObjectModelHelper;
024: import org.apache.cocoon.environment.Redirector;
025: import org.apache.cocoon.environment.Request;
026: import org.apache.cocoon.environment.Session;
027: import org.apache.cocoon.environment.SourceResolver;
028:
029: import java.util.HashMap;
030: import java.util.Map;
031:
032: /**
033: * Store the session's current state in a session attribute.
034: *
035: * <p> To keep track of the state of a user's session, a string is
036: * stored in a session attribute in order to allow to chose between
037: * different pipelines in the sitemap accordingly.</p>
038: *
039: * <p> For added flexibility it is possible to use sub states as
040: * well. For this declare your own name for the session state
041: * attribute and give the number of sublevels plus the level to
042: * modify. (This is <b>one</b> based!) Sub states below the current
043: * one are removed from the session so that the default sub state will
044: * be reentered when the user returns. If you don't like this
045: * behaviour and prefer independent sub states, use this action
046: * several times with different attribute names rather than sub
047: * levels. </p>
048: *
049: * <p><b>Global and local parameters:</b></p>
050: *
051: * <table border="1">
052: * <tr>
053: * <td><code>state-key-prefix</code></td>
054: * <td>String that identifies the attribute that stores the session state in the
055: * session object. When sublevels are used, this is a prefix ie. the
056: * number of the level is appended to the prefix. Example prefix is
057: * "<code>__sessionState</code>", sub-levels is 2, attributes
058: * "<code>__sessionState1</code>", "<code>__sessionState2</code>", and
059: * "<code>__sessionState3</code>" will be used to store the
060: * information.
061: * </td>
062: * </tr>
063: * <tr>
064: * <td><code>new-state</code></td>
065: * <td>String that identifies the current state</td>
066: * </tr>
067: * <tr>
068: * <td><code>sub-levels</code></td>
069: * <td>Number of sub levels to use</td>
070: * </tr>
071: * <tr>
072: * <td><code>state-level</code></td>
073: * <td>Sub level to modify, this is <b>one</b> based</td>
074: * </tr>
075: * </table>
076: *
077: * @see org.apache.cocoon.matching.WildcardSessionAttributeMatcher
078: * @see org.apache.cocoon.selection.SessionAttributeSelector
079: *
080: * @author <a href="mailto:haul@apache.org">Christian Haul</a>
081: * @version CVS $Id: SessionStateAction.java 433543 2006-08-22 06:22:54Z crossley $
082: */
083: public class SessionStateAction extends AbstractConfigurableAction
084: implements ThreadSafe {
085:
086: protected String statekey = "org.apache.cocoon.SessionState";
087: protected String newstate = null;
088: protected int sublevels = 0;
089: protected int mylevel = 0;
090:
091: /**
092: * Configures the Action.
093: */
094: public void configure(Configuration conf)
095: throws ConfigurationException {
096: super .configure(conf);
097:
098: if (settings.containsKey("state-key-prefix")) {
099: statekey = (String) settings.get("state-key-prefix");
100: }
101: if (settings.containsKey("new-state")) {
102: newstate = (String) settings.get("new-state");
103: }
104: if (settings.containsKey("sub-levels")) {
105: sublevels = Integer.parseInt((String) settings
106: .get("sub-levels"));
107: }
108: if (settings.containsKey("state-level")) {
109: mylevel = Integer.parseInt((String) settings
110: .get("state-level"));
111: }
112: }
113:
114: public Map act(Redirector redirector, SourceResolver resolver,
115: Map objectModel, String src, Parameters par)
116: throws Exception {
117:
118: Request request = ObjectModelHelper.getRequest(objectModel);
119:
120: // read local settings
121: String newstate = par.getParameter("new-state", this .newstate);
122: String statekey = par.getParameter("state-key", this .statekey);
123: int sublevels = par.getParameterAsInteger("sublevels",
124: this .sublevels);
125: int mylevel = par.getParameterAsInteger("state-level",
126: this .mylevel);
127:
128: if (newstate == null) {
129: if (this .getLogger().isDebugEnabled()) {
130: getLogger().error("new-state is null");
131: }
132: return null;
133: }
134:
135: if (request != null) {
136: Session session = request.getSession(false);
137:
138: if (session != null && request.isRequestedSessionIdValid()) {
139: String oldstate = null;
140: if (sublevels == 0) {
141: oldstate = (String) session.getAttribute(statekey);
142: session.setAttribute(statekey, newstate);
143: if (this .getLogger().isDebugEnabled()) {
144: getLogger().debug(statekey + "=" + newstate);
145: }
146:
147: } else { // sublevels != 0
148: oldstate = (String) session.getAttribute(statekey
149: + mylevel);
150: for (int i = mylevel + 1; i <= sublevels; i++) {
151: session.removeAttribute(statekey + i);
152: if (this .getLogger().isDebugEnabled()) {
153: getLogger().debug("Remove " + statekey + i);
154: }
155: }
156: session.setAttribute(statekey + mylevel, newstate);
157: if (this .getLogger().isDebugEnabled()) {
158: getLogger().debug(
159: statekey + mylevel + "=" + newstate);
160: }
161: }
162: if (this .getLogger().isDebugEnabled()) {
163: getLogger().debug(
164: "Transition " + oldstate + " -> "
165: + newstate);
166: }
167:
168: HashMap map = new HashMap(1);
169: map.put("newstate", newstate);
170: return map;
171: } else {
172: getLogger()
173: .warn(
174: "A session object was not present or no longer valid");
175: return null;
176: }
177: } else {
178: getLogger().warn("No request object");
179: return null;
180: }
181: }
182: }
|