/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.catalina.ha.session; /** * This class is used to track the series of actions that happens when * a request is executed. These actions will then translate into invokations of methods * on the actual session. * This class is NOT thread safe. One DeltaRequest per session * @author <a href="mailto:fhanik@apache.org">Filip Hanik</a> * @version 1.0 */ import java.io.Externalizable; import java.security.Principal; import java.util.LinkedList; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.util.StringManager; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class DeltaRequest implements Externalizable { public static org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( DeltaRequest.class ); /** * The string manager for this package. */ protected static StringManager sm = StringManager .getManager(Constants.Package); public static final int TYPE_ATTRIBUTE = 0; public static final int TYPE_PRINCIPAL = 1; public static final int TYPE_ISNEW = 2; public static final int TYPE_MAXINTERVAL = 3; public static final int TYPE_AUTHTYPE = 4; public static final int ACTION_SET = 0; public static final int ACTION_REMOVE = 1; public static final String NAME_PRINCIPAL = "__SET__PRINCIPAL__"; public static final String NAME_MAXINTERVAL = "__SET__MAXINTERVAL__"; public static final String NAME_ISNEW = "__SET__ISNEW__"; public static final String NAME_AUTHTYPE = "__SET__AUTHTYPE__"; private String sessionId; private LinkedList actions = new LinkedList(); private LinkedList actionPool = new LinkedList(); private boolean recordAllActions = false; public DeltaRequest() { } public DeltaRequest(String sessionId, boolean recordAllActions) { this.recordAllActions=recordAllActions; if(sessionId != null) setSessionId(sessionId); } public void setAttribute(String name, Object value) { int action = (value==null)?ACTION_REMOVE:ACTION_SET; addAction(TYPE_ATTRIBUTE,action,name,value); } public void removeAttribute(String name) { int action = ACTION_REMOVE; addAction(TYPE_ATTRIBUTE,action,name,null); } public void setMaxInactiveInterval(int interval) { int action = ACTION_SET; addAction(TYPE_MAXINTERVAL,action,NAME_MAXINTERVAL,new Integer(interval)); } /** * convert principal at SerializablePrincipal for backup nodes. * Only support principals from type {@link GenericPrincipal GenericPrincipal} * @param p Session principal * @see GenericPrincipal */ public void setPrincipal(Principal p) { int action = (p==null)?ACTION_REMOVE:ACTION_SET; SerializablePrincipal sp = null; if ( p != null ) { if(p instanceof GenericPrincipal) { sp = SerializablePrincipal.createPrincipal((GenericPrincipal)p); if(log.isDebugEnabled()) log.debug(sm.getString("deltaRequest.showPrincipal", p.getName() , getSessionId())); } else log.error(sm.getString("deltaRequest.wrongPrincipalClass",p.getClass().getName())); } addAction(TYPE_PRINCIPAL,action,NAME_PRINCIPAL,sp); } public void setNew(boolean n) { int action = ACTION_SET; addAction(TYPE_ISNEW,action,NAME_ISNEW,new Boolean(n)); } public void setAuthType(String authType) { int action = (authType==null)?ACTION_REMOVE:ACTION_SET; addAction(TYPE_AUTHTYPE,action,NAME_AUTHTYPE, authType); } protected void addAction(int type, int action, String name, Object value) { AttributeInfo info = null; if ( this.actionPool.size() > 0 ) { try { info = (AttributeInfo) actionPool.removeFirst(); }catch ( Exception x ) { log.error("Unable to remove element:",x); info = new AttributeInfo(type, action, name, value); } info.init(type,action,name,value); } else { info = new AttributeInfo(type, action, name, value); } //if we have already done something to this attribute, make sure //we don't send multiple actions across the wire if ( !recordAllActions) { try { actions.remove(info); } catch (java.util.NoSuchElementException x) { //do nothing, we wanted to remove it anyway } } //add the action actions.addLast(info); } public void execute(DeltaSession session) { execute(session,true); } public void execute(DeltaSession session, boolean notifyListeners) { if ( !this.sessionId.equals( session.getId() ) ) throw new java.lang.IllegalArgumentException("Session id mismatch, not executing the delta request"); session.access(); for ( int i=0; i<actions.size(); i++ ) { AttributeInfo info = (AttributeInfo)actions.get(i); switch ( info.getType() ) { case TYPE_ATTRIBUTE: { if ( info.getAction() == ACTION_SET ) { if ( log.isTraceEnabled() ) log.trace("Session.setAttribute('"+info.getName()+"', '"+info.getValue()+"')"); session.setAttribute(info.getName(), info.getValue(),notifyListeners,false); } else { if ( log.isTraceEnabled() ) log.trace("Session.removeAttribute('"+info.getName()+"')"); session.removeAttribute(info.getName(),notifyListeners,false); } break; }//case case TYPE_ISNEW: { if ( log.isTraceEnabled() ) log.trace("Session.setNew('"+info.getValue()+"')"); session.setNew(((Boolean)info.getValue()).booleanValue(),false); break; }//case case TYPE_MAXINTERVAL: { if ( log.isTraceEnabled() ) log.trace("Session.setMaxInactiveInterval('"+info.getValue()+"')"); session.setMaxInactiveInterval(((Integer)info.getValue()).intValue(),false); break; }//case case TYPE_PRINCIPAL: { Principal p = null; if ( info.getAction() == ACTION_SET ) { SerializablePrincipal sp = (SerializablePrincipal)info.getValue(); p = (Principal)sp.getPrincipal(session.getManager().getContainer().getRealm()); } session.setPrincipal(p,false); break; }//case case TYPE_AUTHTYPE: { String authType = null; if ( info.getAction() == ACTION_SET ) { authType = (String)info.getValue(); } session.setAuthType(authType,false); break; }//case default : throw new java.lang.IllegalArgumentException("Invalid attribute info type="+info); }//switch }//for session.endAccess(); reset(); } public void reset() { while ( actions.size() > 0 ) { try { AttributeInfo info = (AttributeInfo) actions.removeFirst(); info.recycle(); actionPool.addLast(info); }catch ( Exception x ) { log.error("Unable to remove element",x); } } actions.clear(); } public String getSessionId() { return sessionId; } public void setSessionId(String sessionId) { this.sessionId = sessionId; if ( sessionId == null ) { new Exception("Session Id is null for setSessionId").fillInStackTrace().printStackTrace(); } } public int getSize() { return actions.size(); } public void clear() { actions.clear(); actionPool.clear(); } public void readExternal(java.io.ObjectInput in) throws IOException,ClassNotFoundException { //sessionId - String //recordAll - boolean //size - int //AttributeInfo - in an array reset(); sessionId = in.readUTF(); recordAllActions = in.readBoolean(); int cnt = in.readInt(); if (actions == null) actions = new LinkedList(); else actions.clear(); for (int i = 0; i < cnt; i++) { AttributeInfo info = null; if (this.actionPool.size() > 0) { try { info = (AttributeInfo) actionPool.removeFirst(); } catch ( Exception x ) { log.error("Unable to remove element",x); info = new AttributeInfo(-1,-1,null,null); } } else { info = new AttributeInfo(-1,-1,null,null); } info.readExternal(in); actions.addLast(info); }//for } public void writeExternal(java.io.ObjectOutput out ) throws java.io.IOException { //sessionId - String //recordAll - boolean //size - int //AttributeInfo - in an array out.writeUTF(getSessionId()); out.writeBoolean(recordAllActions); out.writeInt(getSize()); for ( int i=0; i<getSize(); i++ ) { AttributeInfo info = (AttributeInfo)actions.get(i); info.writeExternal(out); } } /** * serialize DeltaRequest * @see DeltaRequest#writeExternal(java.io.ObjectOutput) * * @return serialized delta request * @throws IOException */ protected byte[] serialize() throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); writeExternal(oos); oos.flush(); oos.close(); return bos.toByteArray(); } private static class AttributeInfo implements java.io.Externalizable { private String name = null; private Object value = null; private int action; private int type; public AttributeInfo() {} public AttributeInfo(int type, int action, String name, Object value) { super(); init(type,action,name,value); } public void init(int type, int action, String name, Object value) { this.name = name; this.value = value; this.action = action; this.type = type; } public int getType() { return type; } public int getAction() { return action; } public Object getValue() { return value; } public int hashCode() { return name.hashCode(); } public String getName() { return name; } public void recycle() { name = null; value = null; type=-1; action=-1; } public boolean equals(Object o) { if ( ! (o instanceof AttributeInfo ) ) return false; AttributeInfo other = (AttributeInfo)o; return other.getName().equals(this.getName()); } public void readExternal(java.io.ObjectInput in ) throws IOException,ClassNotFoundException { //type - int //action - int //name - String //hasvalue - boolean //value - object type = in.readInt(); action = in.readInt(); name = in.readUTF(); boolean hasValue = in.readBoolean(); if ( hasValue ) value = in.readObject(); } public void writeExternal(java.io.ObjectOutput out) throws IOException { //type - int //action - int //name - String //hasvalue - boolean //value - object out.writeInt(getType()); out.writeInt(getAction()); out.writeUTF(getName()); out.writeBoolean(getValue()!=null); if (getValue()!=null) out.writeObject(getValue()); } public String toString() { StringBuffer buf = new StringBuffer("AttributeInfo[type="); buf.append(getType()).append(", action=").append(getAction()); buf.append(", name=").append(getName()).append(", value=").append(getValue()); buf.append(", addr=").append(super.toString()).append("]"); return buf.toString(); } } }