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: package org.apache.axis2.jaxws.spi.migrator;
020:
021: import org.apache.axis2.context.ConfigurationContext;
022: import org.apache.axis2.jaxws.ExceptionFactory;
023: import org.apache.axis2.jaxws.core.MessageContext;
024: import org.apache.axis2.jaxws.description.ServiceDescription;
025: import org.apache.axis2.jaxws.handler.MEPContext;
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028:
029: import javax.xml.ws.handler.MessageContext.Scope;
030:
031: import java.util.AbstractSet;
032: import java.util.Collection;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.LinkedList;
036: import java.util.List;
037: import java.util.ListIterator;
038: import java.util.Map;
039: import java.util.Set;
040: import java.util.Map.Entry;
041:
042: public class ApplicationContextMigratorUtil {
043:
044: private static final Log log = LogFactory
045: .getLog(ApplicationContextMigrator.class);
046:
047: /**
048: * Register a new ContextPropertyMigrator.
049: *
050: * @param configurationContext
051: * @param contextMigratorListID The name of the property in the ConfigurationContext that
052: * contains the list of migrators.
053: * @param migrator
054: */
055: public static void addApplicationContextMigrator(
056: ConfigurationContext configurationContext,
057: String contextMigratorListID,
058: ApplicationContextMigrator migrator) {
059: List<ApplicationContextMigrator> migratorList = (List<ApplicationContextMigrator>) configurationContext
060: .getProperty(contextMigratorListID);
061:
062: if (migratorList == null) {
063: migratorList = new LinkedList<ApplicationContextMigrator>();
064: configurationContext.setProperty(contextMigratorListID,
065: migratorList);
066: }
067:
068: synchronized (migratorList) {
069: // Check to make sure we haven't already added this migrator to the
070: // list.
071: ListIterator<ApplicationContextMigrator> itr = migratorList
072: .listIterator();
073: while (itr.hasNext()) {
074: ApplicationContextMigrator m = itr.next();
075: if (m.getClass().equals(migrator.getClass())) {
076: return;
077: }
078: }
079:
080: if (log.isDebugEnabled()) {
081: log.debug("Adding ApplicationContextMigrator: "
082: + migrator.getClass().getName());
083: }
084: migratorList.add(migrator);
085: }
086: }
087:
088: /**
089: * @param contextMigratorListID
090: * @param requestContext
091: * @param messageContext
092: */
093: public static void performMigrationToMessageContext(
094: String contextMigratorListID,
095: Map<String, Object> requestContext,
096: MessageContext messageContext) {
097: if (messageContext == null) {
098: throw ExceptionFactory
099: .makeWebServiceException("Null MessageContext");
100: }
101:
102: ServiceDescription sd = messageContext.getEndpointDescription()
103: .getServiceDescription();
104: if (sd != null) {
105: ConfigurationContext configCtx = sd.getAxisConfigContext();
106: List<ApplicationContextMigrator> migratorList = (List<ApplicationContextMigrator>) configCtx
107: .getProperty(contextMigratorListID);
108: synchronized (migratorList) {
109: if (migratorList != null) {
110: ListIterator<ApplicationContextMigrator> itr = migratorList
111: .listIterator();
112: while (itr.hasNext()) {
113: ApplicationContextMigrator cpm = itr.next();
114: if (log.isDebugEnabled()) {
115: log
116: .debug("migrator: "
117: + cpm.getClass().getName()
118: + ".migratePropertiesToMessageContext");
119: }
120: cpm.migratePropertiesToMessageContext(
121: new ApplicationPropertyMapReader(
122: requestContext, messageContext
123: .getMEPContext()),
124: messageContext);
125: }
126: }
127: }
128: }
129: }
130:
131: /**
132: * @param contextMigratorListID
133: * @param responseContext
134: * @param messageContext
135: */
136: public static void performMigrationFromMessageContext(
137: String contextMigratorListID,
138: Map<String, Object> responseContext,
139: MessageContext messageContext) {
140: if (messageContext == null) {
141: throw ExceptionFactory
142: .makeWebServiceException("Null MessageContext");
143: }
144:
145: ServiceDescription sd = messageContext.getEndpointDescription()
146: .getServiceDescription();
147: if (sd != null) {
148: ConfigurationContext configCtx = sd.getAxisConfigContext();
149: List<ApplicationContextMigrator> migratorList = (List<ApplicationContextMigrator>) configCtx
150: .getProperty(contextMigratorListID);
151:
152: synchronized (migratorList) {
153: if (migratorList != null) {
154: ListIterator<ApplicationContextMigrator> itr = migratorList
155: .listIterator();
156: while (itr.hasNext()) {
157: ApplicationContextMigrator cpm = itr.next();
158: if (log.isDebugEnabled()) {
159: log
160: .debug("migrator: "
161: + cpm.getClass().getName()
162: + ".migratePropertiesFromMessageContext");
163: }
164: cpm.migratePropertiesFromMessageContext(
165: new ApplicationPropertyMapWriter(
166: responseContext, messageContext
167: .getMEPContext()),
168: messageContext);
169: }
170: }
171: }
172: }
173: }
174:
175: /**
176: *
177: * ApplicationPropertyMapReader is a wrapper for the SOURCE property map passed to individual
178: * property migrators. When a property migrator copies properties from a request context map
179: * to a JAXWS MessageContext object, all of those properties should be marked APPLICATION
180: * scope so they can later be retrieved from the request context or response context
181: * in the client application.
182: *
183: * We override the EntrySet and Iterator to make sure the scope is properly set in the
184: * "request context to JAXWS message context" case where the property migrator uses
185: * get(String key) or putAll(Map source). This is not guaranteed to be correct, however,
186: * because a property migrator could simply be doing a get(String key) to observe properties
187: * rather than copy them. This just means we might be setting scope for a property that
188: * never actually makes its way into the JAXWS message context. If someone (a hander,
189: * perhaps) later sets a property with the same key, its scope may be "pre-set" and
190: * therefore incorrect.
191: *
192: * TODO: find solution to above problem. The MEPContext.put sets an explicit scope whenever
193: * a property is and a scope is not already present for that property. An example
194: * of where this idea would produce unexpected results is where a scope was set to APPLICATION
195: * in the property migrator for key/value pair "myKey/someValue", but myKey never actually made
196: * it into the messagecontext. Later a handler might put a "myKey/theHandlerValue". In this
197: * case the scope was already set to APPLICATION and would therefore not be set by the
198: * MEPContext.put and therefore be incorrect.
199: *
200: * ApplicationPropertyMapReader only sets the scope if a migrator calls "get" on this map or
201: * iterates over the entrySet, which may occur explicitly in the migrator, or implicitly when
202: * this map is the source for a call such as otherMap.putAll(Map source).
203: *
204: * @author rott
205: *
206: */
207: private static class ApplicationPropertyMapReader extends
208: HashMap<String, Object> {
209:
210: private Map<String, Object> userMap;
211: private MEPContext mepCtx;
212:
213: public ApplicationPropertyMapReader(
214: Map<String, Object> userMap, MEPContext mepCtx) {
215: this .userMap = userMap;
216: this .mepCtx = mepCtx;
217: }
218:
219: @Override
220: public Object put(String key, Object value) {
221: //mepCtx.setScope(key, Scope.APPLICATION);
222: return userMap.put(key, value);
223: }
224:
225: @Override
226: public void putAll(Map<? extends String, ? extends Object> m) {
227: // we need to take advantage of the smarter put(String, Object)
228: for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
229: Entry entry = (Entry) it.next();
230: put((String) entry.getKey(), entry.getValue());
231: }
232: }
233:
234: @Override
235: public boolean containsKey(Object key) {
236: return userMap.containsKey(key);
237: }
238:
239: @Override
240: public boolean containsValue(Object value) {
241: return userMap.containsValue(value);
242: }
243:
244: @Override
245: public Set entrySet() {
246: return new ApplicationPropertyMapEntrySet(userMap
247: .entrySet(), mepCtx);
248: }
249:
250: @Override
251: public Object get(Object key) {
252: // WARNING: there's no real guarantee that the reason a migrator is getting
253: // a property is due to it being put on the MessageContext.
254: // We would therefore be setting scope for a property that never actually makes
255: // its way into the messageContext.
256: Object obj = userMap.get(key);
257: if (obj != null) {
258: mepCtx.setScope((String) key, Scope.APPLICATION);
259: }
260: return obj;
261: }
262:
263: @Override
264: public boolean isEmpty() {
265: return userMap.isEmpty();
266: }
267:
268: @Override
269: public Set keySet() {
270: return userMap.keySet();
271: }
272:
273: @Override
274: public Object remove(Object key) {
275: return userMap.remove(key);
276: }
277:
278: @Override
279: public int size() {
280: return userMap.size();
281: }
282:
283: @Override
284: public Collection values() {
285: return userMap.values();
286: }
287:
288: private class ApplicationPropertyMapEntrySet extends
289: AbstractSet {
290:
291: Set containedSet;
292: MEPContext mepCtx;
293:
294: public ApplicationPropertyMapEntrySet(Set set,
295: MEPContext mepCtx) {
296: containedSet = set;
297: this .mepCtx = mepCtx;
298: }
299:
300: @Override
301: public EntrySetIterator iterator() {
302: return new EntrySetIterator(containedSet.iterator(),
303: mepCtx);
304: }
305:
306: @Override
307: public int size() {
308: return containedSet.size();
309: }
310:
311: }
312:
313: private class EntrySetIterator implements Iterator {
314:
315: private Iterator containedIterator;
316: private MEPContext mepCtx;
317:
318: private EntrySetIterator(Iterator containedIterator,
319: MEPContext mepCtx) {
320: this .containedIterator = containedIterator;
321: this .mepCtx = mepCtx;
322: }
323:
324: // override remove() to make this Iterator class read-only
325: public void remove() {
326: throw new UnsupportedOperationException();
327: }
328:
329: public boolean hasNext() {
330: return containedIterator.hasNext();
331: }
332:
333: public Object next() {
334: // WARNING: there's no real guarantee that the reason a migrator is iterating
335: // over the properties is due to this being the source object for a putAll(source)
336: // We would therefore be setting scope for a property that never actually makes
337: // its way into the messageContext
338: Entry entry = (Entry) containedIterator.next();
339: mepCtx.setScope((String) entry.getKey(),
340: Scope.APPLICATION);
341: return entry;
342: }
343: }
344: }
345:
346: /**
347: * ApplicationPropertyMapWriter is similar to the ApplicationPropertyMapReader in that it
348: * observes scope to determine what can be returned to a property migrator. Individual
349: * property migrators should only be allowed to retrieve APPLICATION-scoped properties.
350: *
351: * TODO: There's quite a bit of expensive logic that would need to go into this to be
352: * fully correct. For example, if a migrator calls size, we cannot simply return
353: * userMap.size(). Rather, we would have to count only the APPLICATION scoped properties
354: * and return those.
355: *
356: * @author rott
357: *
358: */
359: private static class ApplicationPropertyMapWriter extends
360: HashMap<String, Object> {
361:
362: private Map<String, Object> userMap;
363: private MEPContext mepCtx;
364:
365: public ApplicationPropertyMapWriter(
366: Map<String, Object> userMap, MEPContext mepCtx) {
367: this .userMap = userMap;
368: this .mepCtx = mepCtx;
369: }
370:
371: @Override
372: public Object put(String key, Object value) {
373: // notice the logic here! We won't put a property on the userMap that is not APPLICATION scoped
374: if (mepCtx.getScope(key) == Scope.APPLICATION) {
375: return userMap.put(key, value);
376: }
377: return null;
378: }
379:
380: @Override
381: public void putAll(Map<? extends String, ? extends Object> m) {
382: // we need to take advantage of the smarter put(String, Object)
383: for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
384: Entry entry = (Entry) it.next();
385: put((String) entry.getKey(), entry.getValue());
386: }
387: }
388:
389: @Override
390: public boolean containsKey(Object key) {
391: if (mepCtx.getScope((String) key) == Scope.APPLICATION) {
392: return userMap.containsKey(key);
393: }
394: return false;
395: }
396:
397: @Override
398: public boolean containsValue(Object value) {
399: return userMap.containsValue(value);
400: }
401:
402: @Override
403: public Set entrySet() {
404: return userMap.entrySet();
405: }
406:
407: @Override
408: public Object get(Object key) {
409: return userMap.get(key);
410: }
411:
412: @Override
413: public boolean isEmpty() {
414: return userMap.isEmpty();
415: }
416:
417: @Override
418: public Set keySet() {
419: return userMap.keySet();
420: }
421:
422: @Override
423: public Object remove(Object key) {
424: return userMap.remove(key);
425: }
426:
427: @Override
428: public int size() {
429: return userMap.size();
430: }
431:
432: @Override
433: public Collection values() {
434: return userMap.values();
435: }
436: }
437: }
|