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.axis2.context;
021:
022: import org.apache.axis2.AxisFault;
023: import org.apache.axis2.clustering.ClusterManager;
024: import org.apache.axis2.clustering.context.Replicator;
025:
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029:
030: /**
031: * This is the top most level of the Context hierarchy and is a bag of properties.
032: */
033: public abstract class AbstractContext {
034:
035: /**
036: * Property used to indicate copying of properties is needed by context.
037: */
038: public static final String COPY_PROPERTIES = "CopyProperties";
039:
040: protected long lastTouchedTime;
041:
042: protected transient AbstractContext parent;
043: protected transient Map properties;
044: private transient Map propertyDifferences = new HashMap();
045:
046: protected AbstractContext(AbstractContext parent) {
047: this .parent = parent;
048: }
049:
050: protected AbstractContext() {
051: }
052:
053: /**
054: * @return Returns the parent of this context.
055: */
056: public AbstractContext getParent() {
057: return parent;
058: }
059:
060: /**
061: * @return The properties
062: * @deprecated Use {@link #getPropertyNames()}, {@link #getProperty(String)},
063: * {@link #setProperty(String, Object)} & {@link #removeProperty(String)}instead.
064: */
065: public Map getProperties() {
066: if (this .properties == null) {
067: this .properties = new HashMap();
068: }
069: return properties;
070: }
071:
072: /**
073: * An iterator over a collection of <code>String</code> objects, which are the
074: * keys in the properties object.
075: *
076: * @return Iterator over a collection of keys
077: */
078: public Iterator getPropertyNames() {
079: if (properties == null) {
080: properties = new HashMap();
081: }
082: return properties.keySet().iterator();
083: }
084:
085: /**
086: * Retrieves an object given a key.
087: *
088: * @param key - if not found, will return null
089: * @return Returns the property.
090: */
091: public Object getProperty(String key) {
092: Object obj = properties == null ? null : properties.get(key);
093: if ((obj == null) && (parent != null)) {
094: obj = parent.getProperty(key);
095: } else {
096:
097: // Assume that a property is which is read may be updated.
098: // i.e. The object pointed to by 'value' may be modified after it is read
099: addPropertyDifference(key);
100: }
101: return obj;
102: }
103:
104: /**
105: * Retrieves an object given a key. The retrieved property will not be replicated to
106: * other nodes in the clustered scenario.
107: *
108: * @param key - if not found, will return null
109: * @return Returns the property.
110: */
111: public Object getPropertyNonReplicable(String key) {
112: Object obj = properties == null ? null : properties.get(key);
113: if ((obj == null) && (parent != null)) {
114: obj = parent.getPropertyNonReplicable(key);
115: }
116: return obj;
117: }
118:
119: /**
120: * Store a property in this context
121: *
122: * @param key
123: * @param value
124: */
125: public void setProperty(String key, Object value) {
126: if (this .properties == null) {
127: this .properties = new HashMap();
128: }
129: properties.put(key, value);
130: addPropertyDifference(key);
131: }
132:
133: private synchronized void addPropertyDifference(String key) {
134: ConfigurationContext cc = getRootContext();
135: if (cc == null)
136: return;
137:
138: // Add the property differences only if Context replication is enabled,
139: // and there are members in the cluster
140: ClusterManager clusterManager = cc.getAxisConfiguration()
141: .getClusterManager();
142: if (clusterManager != null
143: && clusterManager.getContextManager() != null) {
144: propertyDifferences.put(key, new PropertyDifference(key,
145: false));
146: }
147: }
148:
149: /**
150: * Store a property in this context.
151: * But these properties should not be replicated when Axis2 is clustered.
152: *
153: * @param key
154: * @param value
155: */
156: public void setNonReplicableProperty(String key, Object value) {
157: if (this .properties == null) {
158: this .properties = new HashMap();
159: }
160: properties.put(key, value);
161: }
162:
163: /**
164: * Remove a property. Only properties at this level will be removed.
165: * Properties of the parents cannot be removed using this method.
166: *
167: * @param key
168: */
169: public synchronized void removeProperty(String key) {
170: if (properties != null) {
171: properties.remove(key);
172: }
173: propertyDifferences.put(key, new PropertyDifference(key, true));
174: }
175:
176: /**
177: * Remove a property. Only properties at this level will be removed.
178: * Properties of the parents cannot be removed using this method.
179: * The removal of the property will not be replicated when Axis2 is clustered.
180: *
181: * @param key
182: */
183: public synchronized void removePropertyNonReplicable(String key) {
184: if (properties != null) {
185: properties.remove(key);
186: }
187: }
188:
189: /**
190: * Get the property differences since the last transmission by the clustering
191: * mechanism
192: *
193: * @return The property differences
194: */
195: public synchronized Map getPropertyDifferences() {
196: return propertyDifferences;
197: }
198:
199: /**
200: * Once the clustering mechanism transmits the property differences,
201: * it should call this method to avoid retransmitting stuff that has already
202: * been sent.
203: */
204: public synchronized void clearPropertyDifferences() {
205: propertyDifferences.clear();
206: }
207:
208: /**
209: * @param context
210: */
211: public void setParent(AbstractContext context) {
212: parent = context;
213: }
214:
215: /**
216: * This will set the properties to the context. But in setting that one may need to "copy" all
217: * the properties from the source properties to the target properties. To enable this we introduced
218: * a property ({@link #COPY_PROPERTIES}) so that if set to true, this code
219: * will copy the whole thing, without just referencing to the source.
220: *
221: * @param properties
222: */
223: public void setProperties(Map properties) {
224: if (properties == null) {
225: this .properties = null;
226: } else {
227: Boolean copyProperties = ((Boolean) properties
228: .get(COPY_PROPERTIES));
229:
230: if ((copyProperties != null)
231: && copyProperties.booleanValue()) {
232: mergeProperties(properties);
233: } else {
234: this .properties = properties;
235: }
236: }
237: }
238:
239: /**
240: * This will do a copy of the given properties to the current properties
241: * table.
242: *
243: * @param props The table of properties to copy
244: */
245: public void mergeProperties(Map props) {
246: if (props != null) {
247: if (this .properties == null) {
248: this .properties = new HashMap();
249: }
250: for (Iterator iterator = props.keySet().iterator(); iterator
251: .hasNext();) {
252: Object key = iterator.next();
253: this .properties.put(key, props.get(key));
254: }
255: }
256: }
257:
258: /**
259: * ServiceContext and ServiceGroupContext are not getting automatically garbage collected. And there
260: * is no specific way for some one to go and make it garbage collectible.
261: * So the current solution is to make them time out. So the logic is that, there is a timer task
262: * in each and every service group which will check for the last touched time. And if it has not
263: * been touched for some time, the timer task will remove it from the memory.
264: * The touching logic happens like this. Whenever there is a call to addMessageContext in the operationContext
265: * it will go and update operationCOntext -> serviceContext -> serviceGroupContext.
266: */
267: protected void touch() {
268: lastTouchedTime = System.currentTimeMillis();
269: if (parent != null) {
270: parent.touch();
271: }
272: }
273:
274: public long getLastTouchedTime() {
275: return lastTouchedTime;
276: }
277:
278: public void setLastTouchedTime(long t) {
279: lastTouchedTime = t;
280: }
281:
282: public void flush() throws AxisFault {
283: Replicator.replicate(this );
284: }
285:
286: public abstract ConfigurationContext getRootContext();
287:
288: }
|