001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 *
019 */
020 package org.apache.directory.shared.ldap.message;
021
022 import java.util.Collections;
023 import java.util.HashMap;
024 import java.util.Iterator;
025 import java.util.Map;
026
027 import javax.naming.ldap.Control;
028
029
030
031 /**
032 * Abstract message base class.
033 *
034 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
035 * @version $Rev: 764131 $
036 */
037 public abstract class InternalAbstractMessage implements InternalMessage
038 {
039 static final long serialVersionUID = 7601738291101182094L;
040
041 /** Map of message controls using OID Strings for keys and Control values */
042 private final Map<String, Control> controls;
043
044 /** The session unique message sequence identifier */
045 private final int id;
046
047 /** The message type enumeration */
048 private final MessageTypeEnum type;
049
050 /** Transient Message Parameter Hash */
051 private final Map<Object, Object> parameters;
052
053
054 /**
055 * Completes the instantiation of a Message.
056 *
057 * @param id
058 * the seq id of the message
059 * @param type
060 * the type of the message
061 */
062 protected InternalAbstractMessage( final int id, final MessageTypeEnum type )
063 {
064 this.id = id;
065 this.type = type;
066 controls = new HashMap<String, Control>();
067 parameters = new HashMap<Object, Object>();
068 }
069
070
071 /**
072 * Gets the session unique message sequence id for this message. Requests
073 * and their responses if any have the same message id. Clients at the
074 * initialization of a session start with the first message's id set to 1
075 * and increment it with each transaction.
076 *
077 * @return the session unique message id.
078 */
079 public int getMessageId()
080 {
081 return id;
082 }
083
084
085 /**
086 * Gets the controls associated with this message mapped by OID.
087 *
088 * @return Map of OID strings to Control object instances.
089 * @see InternalControl
090 */
091 public Map<String, Control> getControls()
092 {
093 return Collections.unmodifiableMap( controls );
094 }
095
096
097 /**
098 * @see org.apache.directory.shared.ldap.message.InternalMessage#hasControl(java.lang.String)
099 */
100 public boolean hasControl( String oid )
101 {
102 return controls.containsKey( oid );
103 }
104
105
106 /**
107 * Adds a control to this Message.
108 *
109 * @param control
110 * the control to add.
111 * @throws MessageException
112 * if controls cannot be added to this Message or the control is
113 * not known etc.
114 */
115 public void add( Control control ) throws MessageException
116 {
117 controls.put( control.getID(), control );
118 }
119
120
121 /**
122 * Deletes a control removing it from this Message.
123 *
124 * @param control
125 * the control to remove.
126 * @throws MessageException
127 * if controls cannot be added to this Message or the control is
128 * not known etc.
129 */
130 public void remove( Control control ) throws MessageException
131 {
132 controls.remove( control.getID() );
133 }
134
135
136 /**
137 * Gets the LDAP message type code associated with this Message. Each
138 * request and response type has a unique message type code defined by the
139 * protocol in <a href="http://www.faqs.org/rfcs/rfc2251.html">RFC 2251</a>.
140 *
141 * @return the message type code.
142 */
143 public MessageTypeEnum getType()
144 {
145 return type;
146 }
147
148
149 /**
150 * Gets a message scope parameter. Message scope parameters are temporary
151 * variables associated with a message and are set locally to be used to
152 * associate housekeeping information with a request or its processing.
153 * These parameters are never transmitted nor recieved, think of them as
154 * transient data associated with the message or its processing. These
155 * transient parameters are not locked down so modifications can occur
156 * without firing LockExceptions even when this Lockable is in the locked
157 * state.
158 *
159 * @param key
160 * the key used to access a message parameter.
161 * @return the transient message parameter value.
162 */
163 public Object get( Object key )
164 {
165 return parameters.get( key );
166 }
167
168
169 /**
170 * Sets a message scope parameter. These transient parameters are not locked
171 * down so modifications can occur without firing LockExceptions even when
172 * this Lockable is in the locked state.
173 *
174 * @param key
175 * the parameter key
176 * @param value
177 * the parameter value
178 * @return the old value or null
179 */
180 public Object put( Object key, Object value )
181 {
182 return parameters.put( key, value );
183 }
184
185
186 /**
187 * Checks to see if two messages are equivalent. Messages equivalence does
188 * not factor in parameters accessible through the get() and put()
189 * operations, nor do they factor in the Lockable properties of the Message.
190 * Only the type, controls, and the messageId are evaluated for equality.
191 *
192 * @param obj
193 * the object to compare this Message to for equality
194 */
195 public boolean equals( Object obj )
196 {
197 if ( obj == this )
198 {
199 return true;
200 }
201
202 if ( ( obj == null ) || !( obj instanceof InternalMessage ) )
203 {
204 return false;
205 }
206
207 InternalMessage msg = ( InternalMessage ) obj;
208
209 if ( msg.getMessageId() != id )
210 {
211 return false;
212 }
213
214 if ( msg.getType() != type )
215 {
216 return false;
217 }
218
219 Map<String, Control> controls = msg.getControls();
220
221 if ( controls.size() != this.controls.size() )
222 {
223 return false;
224 }
225
226 Iterator<String> list = this.controls.keySet().iterator();
227
228 while ( list.hasNext() )
229 {
230 if ( !controls.containsKey( list.next() ) )
231 {
232 return false;
233 }
234 }
235
236 return true;
237 }
238
239 /**
240 * @see Object#hashCode()
241 * @return the instance's hash code
242 */
243 public int hashCode()
244 {
245 int hash = 37;
246 hash = hash*17 + id;
247 hash = hash*17 + ( type == null ? 0 : type.hashCode() );
248 hash = hash*17 + ( parameters == null ? 0 : parameters.hashCode() );
249 hash = hash*17 + ( controls == null ? 0 : controls.hashCode() );
250
251 return hash;
252 }
253
254
255 public void addAll( Control[] controls ) throws MessageException
256 {
257 for ( Control c : controls )
258 {
259 this.controls.put( c.getID(), c );
260 }
261 }
262 }