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:
018: package org.apache.catalina.ha.session;
019:
020: /**
021: * This class is used to track the series of actions that happens when
022: * a request is executed. These actions will then translate into invokations of methods
023: * on the actual session.
024: * This class is NOT thread safe. One DeltaRequest per session
025: * @author <a href="mailto:fhanik@apache.org">Filip Hanik</a>
026: * @version 1.0
027: */
028:
029: import java.io.Externalizable;
030: import java.security.Principal;
031: import java.util.LinkedList;
032:
033: import org.apache.catalina.realm.GenericPrincipal;
034: import org.apache.catalina.util.StringManager;
035: import java.io.ByteArrayOutputStream;
036: import java.io.IOException;
037: import java.io.ObjectOutputStream;
038:
039: public class DeltaRequest implements Externalizable {
040:
041: public static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
042: .getLog(DeltaRequest.class);
043:
044: /**
045: * The string manager for this package.
046: */
047: protected static StringManager sm = StringManager
048: .getManager(Constants.Package);
049:
050: public static final int TYPE_ATTRIBUTE = 0;
051: public static final int TYPE_PRINCIPAL = 1;
052: public static final int TYPE_ISNEW = 2;
053: public static final int TYPE_MAXINTERVAL = 3;
054:
055: public static final int ACTION_SET = 0;
056: public static final int ACTION_REMOVE = 1;
057:
058: public static final String NAME_PRINCIPAL = "__SET__PRINCIPAL__";
059: public static final String NAME_MAXINTERVAL = "__SET__MAXINTERVAL__";
060: public static final String NAME_ISNEW = "__SET__ISNEW__";
061:
062: private String sessionId;
063: private LinkedList actions = new LinkedList();
064: private LinkedList actionPool = new LinkedList();
065:
066: private boolean recordAllActions = false;
067:
068: public DeltaRequest() {
069:
070: }
071:
072: public DeltaRequest(String sessionId, boolean recordAllActions) {
073: this .recordAllActions = recordAllActions;
074: if (sessionId != null)
075: setSessionId(sessionId);
076: }
077:
078: public void setAttribute(String name, Object value) {
079: int action = (value == null) ? ACTION_REMOVE : ACTION_SET;
080: addAction(TYPE_ATTRIBUTE, action, name, value);
081: }
082:
083: public void removeAttribute(String name) {
084: int action = ACTION_REMOVE;
085: addAction(TYPE_ATTRIBUTE, action, name, null);
086: }
087:
088: public void setMaxInactiveInterval(int interval) {
089: int action = ACTION_SET;
090: addAction(TYPE_MAXINTERVAL, action, NAME_MAXINTERVAL,
091: new Integer(interval));
092: }
093:
094: /**
095: * convert principal at SerializablePrincipal for backup nodes.
096: * Only support principals from type {@link GenericPrincipal GenericPrincipal}
097: * @param p Session principal
098: * @see GenericPrincipal
099: */
100: public void setPrincipal(Principal p) {
101: int action = (p == null) ? ACTION_REMOVE : ACTION_SET;
102: SerializablePrincipal sp = null;
103: if (p != null) {
104: if (p instanceof GenericPrincipal) {
105: sp = SerializablePrincipal
106: .createPrincipal((GenericPrincipal) p);
107: if (log.isDebugEnabled())
108: log.debug(sm.getString(
109: "deltaRequest.showPrincipal", p.getName(),
110: getSessionId()));
111: } else
112: log.error(sm.getString(
113: "deltaRequest.wrongPrincipalClass", p
114: .getClass().getName()));
115: }
116: addAction(TYPE_PRINCIPAL, action, NAME_PRINCIPAL, sp);
117: }
118:
119: public void setNew(boolean n) {
120: int action = ACTION_SET;
121: addAction(TYPE_ISNEW, action, NAME_ISNEW, new Boolean(n));
122: }
123:
124: protected synchronized void addAction(int type, int action,
125: String name, Object value) {
126: AttributeInfo info = null;
127: if (this .actionPool.size() > 0) {
128: try {
129: info = (AttributeInfo) actionPool.removeFirst();
130: } catch (Exception x) {
131: log.error("Unable to remove element:", x);
132: info = new AttributeInfo(type, action, name, value);
133: }
134: info.init(type, action, name, value);
135: } else {
136: info = new AttributeInfo(type, action, name, value);
137: }
138: //if we have already done something to this attribute, make sure
139: //we don't send multiple actions across the wire
140: if (!recordAllActions) {
141: try {
142: actions.remove(info);
143: } catch (java.util.NoSuchElementException x) {
144: //do nothing, we wanted to remove it anyway
145: }
146: }
147: //add the action
148: actions.addLast(info);
149: }
150:
151: public void execute(DeltaSession session) {
152: execute(session, true);
153: }
154:
155: public synchronized void execute(DeltaSession session,
156: boolean notifyListeners) {
157: if (!this .sessionId.equals(session.getId()))
158: throw new java.lang.IllegalArgumentException(
159: "Session id mismatch, not executing the delta request");
160: session.access();
161: for (int i = 0; i < actions.size(); i++) {
162: AttributeInfo info = (AttributeInfo) actions.get(i);
163: switch (info.getType()) {
164: case TYPE_ATTRIBUTE: {
165: if (info.getAction() == ACTION_SET) {
166: if (log.isTraceEnabled())
167: log.trace("Session.setAttribute('"
168: + info.getName() + "', '"
169: + info.getValue() + "')");
170: session.setAttribute(info.getName(), info
171: .getValue(), notifyListeners, false);
172: } else {
173: if (log.isTraceEnabled())
174: log.trace("Session.removeAttribute('"
175: + info.getName() + "')");
176: session.removeAttribute(info.getName(),
177: notifyListeners, false);
178: }
179:
180: break;
181: }//case
182: case TYPE_ISNEW: {
183: if (log.isTraceEnabled())
184: log.trace("Session.setNew('" + info.getValue()
185: + "')");
186: session.setNew(((Boolean) info.getValue())
187: .booleanValue(), false);
188: break;
189: }//case
190: case TYPE_MAXINTERVAL: {
191: if (log.isTraceEnabled())
192: log.trace("Session.setMaxInactiveInterval('"
193: + info.getValue() + "')");
194: session.setMaxInactiveInterval(((Integer) info
195: .getValue()).intValue(), false);
196: break;
197: }//case
198: case TYPE_PRINCIPAL: {
199: Principal p = null;
200: if (info.getAction() == ACTION_SET) {
201: SerializablePrincipal sp = (SerializablePrincipal) info
202: .getValue();
203: p = (Principal) sp.getPrincipal(session
204: .getManager().getContainer().getRealm());
205: }
206: session.setPrincipal(p, false);
207: break;
208: }//case
209: default:
210: throw new java.lang.IllegalArgumentException(
211: "Invalid attribute info type=" + info);
212: }//switch
213: }//for
214: session.endAccess();
215: reset();
216: }
217:
218: public synchronized void reset() {
219: while (actions.size() > 0) {
220: try {
221: AttributeInfo info = (AttributeInfo) actions
222: .removeFirst();
223: info.recycle();
224: actionPool.addLast(info);
225: } catch (Exception x) {
226: log.error("Unable to remove element", x);
227: }
228: }
229: actions.clear();
230: }
231:
232: public String getSessionId() {
233: return sessionId;
234: }
235:
236: public void setSessionId(String sessionId) {
237: this .sessionId = sessionId;
238: if (sessionId == null) {
239: new Exception("Session Id is null for setSessionId")
240: .fillInStackTrace().printStackTrace();
241: }
242: }
243:
244: public int getSize() {
245: return actions.size();
246: }
247:
248: public synchronized void clear() {
249: actions.clear();
250: actionPool.clear();
251: }
252:
253: public synchronized void readExternal(java.io.ObjectInput in)
254: throws IOException, ClassNotFoundException {
255: //sessionId - String
256: //recordAll - boolean
257: //size - int
258: //AttributeInfo - in an array
259: reset();
260: sessionId = in.readUTF();
261: recordAllActions = in.readBoolean();
262: int cnt = in.readInt();
263: if (actions == null)
264: actions = new LinkedList();
265: else
266: actions.clear();
267: for (int i = 0; i < cnt; i++) {
268: AttributeInfo info = null;
269: if (this .actionPool.size() > 0) {
270: try {
271: info = (AttributeInfo) actionPool.removeFirst();
272: } catch (Exception x) {
273: log.error("Unable to remove element", x);
274: info = new AttributeInfo(-1, -1, null, null);
275: }
276: } else {
277: info = new AttributeInfo(-1, -1, null, null);
278: }
279: info.readExternal(in);
280: actions.addLast(info);
281: }//for
282: }
283:
284: public synchronized void writeExternal(java.io.ObjectOutput out)
285: throws java.io.IOException {
286: //sessionId - String
287: //recordAll - boolean
288: //size - int
289: //AttributeInfo - in an array
290: out.writeUTF(getSessionId());
291: out.writeBoolean(recordAllActions);
292: out.writeInt(getSize());
293: for (int i = 0; i < getSize(); i++) {
294: AttributeInfo info = (AttributeInfo) actions.get(i);
295: info.writeExternal(out);
296: }
297: }
298:
299: /**
300: * serialize DeltaRequest
301: * @see DeltaRequest#writeExternal(java.io.ObjectOutput)
302: *
303: * @param deltaRequest
304: * @return serialized delta request
305: * @throws IOException
306: */
307: protected byte[] serialize() throws IOException {
308: ByteArrayOutputStream bos = new ByteArrayOutputStream();
309: ObjectOutputStream oos = new ObjectOutputStream(bos);
310: writeExternal(oos);
311: oos.flush();
312: oos.close();
313: return bos.toByteArray();
314: }
315:
316: private static class AttributeInfo implements
317: java.io.Externalizable {
318: private String name = null;
319: private Object value = null;
320: private int action;
321: private int type;
322:
323: public AttributeInfo() {
324: }
325:
326: public AttributeInfo(int type, int action, String name,
327: Object value) {
328: super ();
329: init(type, action, name, value);
330: }
331:
332: public void init(int type, int action, String name, Object value) {
333: this .name = name;
334: this .value = value;
335: this .action = action;
336: this .type = type;
337: }
338:
339: public int getType() {
340: return type;
341: }
342:
343: public int getAction() {
344: return action;
345: }
346:
347: public Object getValue() {
348: return value;
349: }
350:
351: public int hashCode() {
352: return name.hashCode();
353: }
354:
355: public String getName() {
356: return name;
357: }
358:
359: public void recycle() {
360: name = null;
361: value = null;
362: type = -1;
363: action = -1;
364: }
365:
366: public boolean equals(Object o) {
367: if (!(o instanceof AttributeInfo))
368: return false;
369: AttributeInfo other = (AttributeInfo) o;
370: return other.getName().equals(this .getName());
371: }
372:
373: public synchronized void readExternal(java.io.ObjectInput in)
374: throws IOException, ClassNotFoundException {
375: //type - int
376: //action - int
377: //name - String
378: //hasvalue - boolean
379: //value - object
380: type = in.readInt();
381: action = in.readInt();
382: name = in.readUTF();
383: boolean hasValue = in.readBoolean();
384: if (hasValue)
385: value = in.readObject();
386: }
387:
388: public synchronized void writeExternal(java.io.ObjectOutput out)
389: throws IOException {
390: //type - int
391: //action - int
392: //name - String
393: //hasvalue - boolean
394: //value - object
395: out.writeInt(getType());
396: out.writeInt(getAction());
397: out.writeUTF(getName());
398: out.writeBoolean(getValue() != null);
399: if (getValue() != null)
400: out.writeObject(getValue());
401: }
402:
403: public String toString() {
404: StringBuffer buf = new StringBuffer("AttributeInfo[type=");
405: buf.append(getType()).append(", action=").append(
406: getAction());
407: buf.append(", name=").append(getName()).append(", value=")
408: .append(getValue());
409: buf.append(", addr=").append(super .toString()).append("]");
410: return buf.toString();
411: }
412:
413: }
414:
415: }
|