View Javadoc
1   /*
2    * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package com.sun.xml.internal.ws.policy;
27  
28  import com.sun.xml.internal.ws.policy.privateutil.LocalizationMessages;
29  import com.sun.xml.internal.ws.policy.privateutil.PolicyLogger;
30  import java.util.ArrayList;
31  import java.util.Collection;
32  import java.util.HashMap;
33  import java.util.Iterator;
34  import java.util.LinkedList;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.NoSuchElementException;
38  import java.util.Set;
39  import javax.xml.namespace.QName;
40  
41  /**
42   * A PolicyMap holds all policies for a scope.
43   *
44   * This map is modeled around WSDL 1.1 policy scopes according to WS-PolicyAttachment. The map holds an information about
45   * every scope for service, endpoint, operation, and input/output/fault message. It also provide accessibility methods for
46   * computing and obtaining effective policy on each scope.
47   *
48   * TODO: rename createWsdlMessageScopeKey to createWsdlInputOutputMessageScopeKey
49   *
50   * @author Fabian Ritzmann
51   */
52  public final class PolicyMap implements Iterable<Policy> {
53     private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyMap.class);
54  
55      private static final PolicyMapKeyHandler serviceKeyHandler = new PolicyMapKeyHandler() {
56          public boolean areEqual(final PolicyMapKey key1, final PolicyMapKey key2) {
57              return key1.getService().equals(key2.getService());
58          }
59  
60          public int generateHashCode(final PolicyMapKey key) {
61              int result = 17;
62  
63              result = 37 * result + key.getService().hashCode();
64  
65              return result;
66          }
67      };
68  
69      private static final PolicyMapKeyHandler endpointKeyHandler = new PolicyMapKeyHandler() {
70          public boolean areEqual(final PolicyMapKey key1, final PolicyMapKey key2) {
71              boolean retVal = true;
72  
73              retVal = retVal && key1.getService().equals(key2.getService());
74              retVal = retVal && ((key1.getPort() == null) ? key2.getPort() == null : key1.getPort().equals(key2.getPort()));
75  
76              return retVal;
77          }
78  
79          public int generateHashCode(final PolicyMapKey key) {
80              int result = 17;
81  
82              result = 37 * result + key.getService().hashCode();
83              result = 37 * result + ((key.getPort() == null) ? 0 : key.getPort().hashCode());
84  
85              return result;
86          }
87      };
88  
89      private static final PolicyMapKeyHandler operationAndInputOutputMessageKeyHandler = new PolicyMapKeyHandler() {
90          // we use the same algorithm to handle operation and input/output message keys
91  
92          public boolean areEqual(final PolicyMapKey key1, final PolicyMapKey key2) {
93              boolean retVal = true;
94  
95              retVal = retVal && key1.getService().equals(key2.getService());
96              retVal = retVal && ((key1.getPort() == null) ? key2.getPort() == null : key1.getPort().equals(key2.getPort()));
97              retVal = retVal && ((key1.getOperation() == null) ? key2.getOperation() == null : key1.getOperation().equals(key2.getOperation()));
98  
99              return retVal;
100         }
101 
102         public int generateHashCode(final PolicyMapKey key) {
103             int result = 17;
104 
105             result = 37 * result + key.getService().hashCode();
106             result = 37 * result + ((key.getPort() == null) ? 0 : key.getPort().hashCode());
107             result = 37 * result + ((key.getOperation() == null) ? 0 : key.getOperation().hashCode());
108 
109             return result;
110         }
111     };
112 
113     private static final PolicyMapKeyHandler faultMessageHandler = new PolicyMapKeyHandler() {
114         public boolean areEqual(final PolicyMapKey key1, final PolicyMapKey key2) {
115             boolean retVal = true;
116 
117             retVal = retVal && key1.getService().equals(key2.getService());
118             retVal = retVal && ((key1.getPort() == null) ? key2.getPort() == null : key1.getPort().equals(key2.getPort()));
119             retVal = retVal && ((key1.getOperation() == null) ? key2.getOperation() == null : key1.getOperation().equals(key2.getOperation()));
120             retVal = retVal && ((key1.getFaultMessage() == null) ? key2.getFaultMessage() == null : key1.getFaultMessage().equals(key2.getFaultMessage()));
121 
122             return retVal;
123         }
124 
125         public int generateHashCode(final PolicyMapKey key) {
126             int result = 17;
127 
128             result = 37 * result + key.getService().hashCode();
129             result = 37 * result + ((key.getPort() == null) ? 0 : key.getPort().hashCode());
130             result = 37 * result + ((key.getOperation() == null) ? 0 : key.getOperation().hashCode());
131             result = 37 * result + ((key.getFaultMessage() == null) ? 0 : key.getFaultMessage().hashCode());
132 
133             return result;
134         }
135     };
136 
137 
138     static enum ScopeType {
139         SERVICE,
140         ENDPOINT,
141         OPERATION,
142         INPUT_MESSAGE,
143         OUTPUT_MESSAGE,
144         FAULT_MESSAGE
145     }
146 
147     private static final class ScopeMap implements Iterable<Policy> {
148         private final Map<PolicyMapKey, PolicyScope> internalMap = new HashMap<PolicyMapKey, PolicyScope>();
149         private final PolicyMapKeyHandler scopeKeyHandler;
150         private final PolicyMerger merger;
151 
152         ScopeMap(final PolicyMerger merger, final PolicyMapKeyHandler scopeKeyHandler) {
153             this.merger = merger;
154             this.scopeKeyHandler = scopeKeyHandler;
155         }
156 
157         Policy getEffectivePolicy(final PolicyMapKey key) throws PolicyException {
158             final PolicyScope scope = internalMap.get(createLocalCopy(key));
159             return (scope == null) ? null : scope.getEffectivePolicy(merger);
160         }
161 
162         void putSubject(final PolicyMapKey key, final PolicySubject subject) {
163             final PolicyMapKey localKey = createLocalCopy(key);
164             final PolicyScope scope = internalMap.get(localKey);
165             if (scope == null) {
166                 final List<PolicySubject> list = new LinkedList<PolicySubject>();
167                 list.add(subject);
168                 internalMap.put(localKey, new PolicyScope(list));
169             } else {
170                 scope.attach(subject);
171             }
172         }
173 
174         void setNewEffectivePolicy(final PolicyMapKey key, final Policy newEffectivePolicy) {
175             // we add this policy map as a subject, because there is nothing reasonable we could add there, since
176             // this is an artificial policy subject
177             final PolicySubject subject = new PolicySubject(key, newEffectivePolicy);
178 
179             final PolicyMapKey localKey = createLocalCopy(key);
180             final PolicyScope scope = internalMap.get(localKey);
181             if (scope == null) {
182                 final List<PolicySubject> list = new LinkedList<PolicySubject>();
183                 list.add(subject);
184                 internalMap.put(localKey, new PolicyScope(list));
185             } else {
186                 scope.dettachAllSubjects();
187                 scope.attach(subject);
188             }
189         }
190 
191         Collection<PolicyScope> getStoredScopes() {
192             return internalMap.values();
193         }
194 
195         Set<PolicyMapKey> getAllKeys() {
196             return internalMap.keySet();
197         }
198 
199         private PolicyMapKey createLocalCopy(final PolicyMapKey key) {
200             if (key == null) {
201                 throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0045_POLICY_MAP_KEY_MUST_NOT_BE_NULL()));
202             }
203 
204             final PolicyMapKey localKeyCopy = new PolicyMapKey(key);
205             localKeyCopy.setHandler(scopeKeyHandler);
206 
207             return localKeyCopy;
208         }
209 
210         public Iterator<Policy> iterator() {
211             return new Iterator<Policy> () {
212                 private final Iterator<PolicyMapKey> keysIterator = internalMap.keySet().iterator();
213 
214                 public boolean hasNext() {
215                     return keysIterator.hasNext();
216                 }
217 
218                 public Policy next() {
219                     final PolicyMapKey key = keysIterator.next();
220                     try {
221                         return getEffectivePolicy(key);
222                     } catch (PolicyException e) {
223                         throw LOGGER.logSevereException(new IllegalStateException(LocalizationMessages.WSP_0069_EXCEPTION_WHILE_RETRIEVING_EFFECTIVE_POLICY_FOR_KEY(key), e));
224                     }
225                 }
226 
227                 public void remove() {
228                     throw LOGGER.logSevereException(new UnsupportedOperationException(LocalizationMessages.WSP_0034_REMOVE_OPERATION_NOT_SUPPORTED()));
229                 }
230             };
231         }
232 
233         public boolean isEmpty() {
234             return internalMap.isEmpty();
235         }
236 
237         @Override
238         public String toString() {
239             return internalMap.toString();
240         }
241     }
242 
243     private static final PolicyMerger merger = PolicyMerger.getMerger();
244 
245     private final ScopeMap serviceMap = new ScopeMap(merger, serviceKeyHandler);
246     private final ScopeMap endpointMap = new ScopeMap(merger, endpointKeyHandler);
247     private final ScopeMap operationMap = new ScopeMap(merger, operationAndInputOutputMessageKeyHandler);
248     private final ScopeMap inputMessageMap = new ScopeMap(merger, operationAndInputOutputMessageKeyHandler);
249     private final ScopeMap outputMessageMap = new ScopeMap(merger, operationAndInputOutputMessageKeyHandler);
250     private final ScopeMap faultMessageMap = new ScopeMap(merger, faultMessageHandler);
251 
252     /**
253      * This constructor is private to prevent direct instantiation from outside of the class
254      */
255     private PolicyMap() {
256         // nothing to initialize
257     }
258 
259     /**
260      * Creates new policy map instance and connects provided collection of policy map mutators to the created policy map.
261      *
262      * @param mutators collection of mutators that should be connected to the newly created map.
263      * @return new policy map instance (mutable via provided collection of mutators).
264      */
265     public static PolicyMap createPolicyMap(final Collection<? extends PolicyMapMutator> mutators) {
266         final PolicyMap result = new PolicyMap();
267 
268         if (mutators != null && !mutators.isEmpty()) {
269             for (PolicyMapMutator mutator : mutators) {
270                 mutator.connect(result);
271             }
272         }
273 
274         return result;
275     }
276 
277     public Policy getServiceEffectivePolicy(final PolicyMapKey key) throws PolicyException {
278         return serviceMap.getEffectivePolicy(key);
279     }
280 
281     public Policy getEndpointEffectivePolicy(final PolicyMapKey key) throws PolicyException {
282         return endpointMap.getEffectivePolicy(key);
283     }
284 
285     public Policy getOperationEffectivePolicy(final PolicyMapKey key) throws PolicyException {
286         return operationMap.getEffectivePolicy(key);
287     }
288 
289     public Policy getInputMessageEffectivePolicy(final PolicyMapKey key) throws PolicyException {
290         return inputMessageMap.getEffectivePolicy(key);
291     }
292 
293     public Policy getOutputMessageEffectivePolicy(final PolicyMapKey key) throws PolicyException {
294         return outputMessageMap.getEffectivePolicy(key);
295     }
296 
297     public Policy getFaultMessageEffectivePolicy(final PolicyMapKey key) throws PolicyException {
298         return faultMessageMap.getEffectivePolicy(key);
299     }
300 
301     /**
302      * Returns all service scope keys stored in this policy map
303      *
304      * @return collection of service scope policy map keys stored in the map.
305      */
306     public Collection<PolicyMapKey> getAllServiceScopeKeys() {
307         return serviceMap.getAllKeys();
308     }
309 
310     /**
311      * Returns all endpoint scope keys stored in this policy map
312      *
313      * @return collection of endpoint scope policy map keys stored in the map.
314      */
315     public Collection<PolicyMapKey> getAllEndpointScopeKeys() {
316         return endpointMap.getAllKeys();
317     }
318 
319     /**
320      * Returns all operation scope keys stored in this policy map
321      *
322      * @return collection of operation scope policy map keys stored in the map.
323      */
324     public Collection<PolicyMapKey> getAllOperationScopeKeys() {
325         return operationMap.getAllKeys();
326     }
327 
328     /**
329      * Returns all input message scope keys stored in this policy map
330      *
331      * @return collection of input message scope policy map keys stored in the map.
332      */
333     public Collection<PolicyMapKey> getAllInputMessageScopeKeys() {
334         return inputMessageMap.getAllKeys();
335     }
336 
337     /**
338      * Returns all output message scope keys stored in this policy map
339      *
340      * @return collection of output message scope policy map keys stored in the map.
341      */
342     public Collection<PolicyMapKey> getAllOutputMessageScopeKeys() {
343         return outputMessageMap.getAllKeys();
344     }
345 
346     /**
347      * Returns all fault message scope keys stored in this policy map
348      *
349      * @return collection of input message scope policy map keys stored in the map.
350      */
351     public Collection<PolicyMapKey> getAllFaultMessageScopeKeys() {
352         return faultMessageMap.getAllKeys();
353     }
354 
355     /**
356      * Places new subject into policy map under the scope identified by it's type and policy map key.
357      *
358      * @param scopeType the type of the scope the subject belongs to
359      * @param key a policy map key to be used to store the subject
360      * @param subject actual policy subject to be stored in the policy map
361      *
362      * @throw IllegalArgumentException in case the scope type is not recognized.
363      */
364     void putSubject(final ScopeType scopeType, final PolicyMapKey key, final PolicySubject subject) {
365         switch (scopeType) {
366             case SERVICE:
367                 serviceMap.putSubject(key, subject);
368                 break;
369             case ENDPOINT:
370                 endpointMap.putSubject(key, subject);
371                 break;
372             case OPERATION:
373                 operationMap.putSubject(key, subject);
374                 break;
375             case INPUT_MESSAGE:
376                 inputMessageMap.putSubject(key, subject);
377                 break;
378             case OUTPUT_MESSAGE:
379                 outputMessageMap.putSubject(key, subject);
380                 break;
381             case FAULT_MESSAGE:
382                 faultMessageMap.putSubject(key, subject);
383                 break;
384             default:
385                 throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0002_UNRECOGNIZED_SCOPE_TYPE(scopeType)));
386         }
387     }
388 
389     /**
390      * Replaces current effective policy on given scope (identified by a {@code key} parameter) with the new efective
391      * policy provided as a second input parameter. If no policy was defined for the presented key, the new policy is simply
392      * stored with the key.
393      *
394      * @param scopeType the type of the scope the subject belongs to. Must not be {@code null}.
395      * @param key identifier of the scope the effective policy should be replaced with the new one. Must not be {@code null}.
396      * @param newEffectivePolicy the new policy to replace the old effective policy of the scope. Must not be {@code null}.
397      *
398      * @throw IllegalArgumentException in case any of the input parameters is {@code null}
399      *        or in case the scope type is not recognized.
400      */
401     void setNewEffectivePolicyForScope(final ScopeType scopeType, final PolicyMapKey key, final Policy newEffectivePolicy) throws IllegalArgumentException {
402         if (scopeType == null || key == null || newEffectivePolicy == null) {
403             throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0062_INPUT_PARAMS_MUST_NOT_BE_NULL()));
404         }
405 
406         switch (scopeType) {
407             case SERVICE :
408                 serviceMap.setNewEffectivePolicy(key, newEffectivePolicy);
409                 break;
410             case ENDPOINT :
411                 endpointMap.setNewEffectivePolicy(key, newEffectivePolicy);
412                 break;
413             case OPERATION :
414                 operationMap.setNewEffectivePolicy(key, newEffectivePolicy);
415                 break;
416             case INPUT_MESSAGE :
417                 inputMessageMap.setNewEffectivePolicy(key, newEffectivePolicy);
418                 break;
419             case OUTPUT_MESSAGE :
420                 outputMessageMap.setNewEffectivePolicy(key, newEffectivePolicy);
421                 break;
422             case FAULT_MESSAGE :
423                 faultMessageMap.setNewEffectivePolicy(key, newEffectivePolicy);
424                 break;
425             default:
426                 throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0002_UNRECOGNIZED_SCOPE_TYPE(scopeType)));
427         }
428     }
429 
430     /**
431      * Returns all policy subjects contained by this map.
432      *
433      * @return All policy subjects contained by this map
434      */
435     public Collection<PolicySubject> getPolicySubjects() {
436         final List<PolicySubject> subjects = new LinkedList<PolicySubject>();
437         addSubjects(subjects, serviceMap);
438         addSubjects(subjects, endpointMap);
439         addSubjects(subjects, operationMap);
440         addSubjects(subjects, inputMessageMap);
441         addSubjects(subjects, outputMessageMap);
442         addSubjects(subjects, faultMessageMap);
443         return subjects;
444     }
445 
446     /*
447      * TODO: reconsider this QUICK HACK
448      */
449     public boolean isInputMessageSubject(final PolicySubject subject) {
450         for (PolicyScope scope : inputMessageMap.getStoredScopes()) {
451             if (scope.getPolicySubjects().contains(subject)) {
452                 return true;
453             }
454         }
455         return false;
456     }
457 
458     /*
459      * TODO: reconsider this QUICK HACK
460      */
461     public boolean isOutputMessageSubject(final PolicySubject subject) {
462         for (PolicyScope scope : outputMessageMap.getStoredScopes()) {
463             if (scope.getPolicySubjects().contains(subject)) {
464                 return true;
465             }
466         }
467         return false;
468     }
469 
470 
471     /*
472      * TODO: reconsider this QUICK HACK
473      */
474     public boolean isFaultMessageSubject(final PolicySubject subject) {
475         for (PolicyScope scope : faultMessageMap.getStoredScopes()) {
476             if (scope.getPolicySubjects().contains(subject)) {
477                 return true;
478             }
479         }
480         return false;
481     }
482 
483 
484     /**
485      * Returns true if this map contains no key - policy pairs
486      *
487      * A null object key or policy constitutes a non-empty map.
488      *
489      * @return true if this map contains no key - policy pairs
490      */
491     public boolean isEmpty() {
492         return serviceMap.isEmpty() && endpointMap.isEmpty() &&
493                 operationMap.isEmpty() && inputMessageMap.isEmpty() &&
494                 outputMessageMap.isEmpty() && faultMessageMap.isEmpty();
495     }
496 
497 
498     /**
499      * Add all subjects in the given map to the collection
500      *
501      * @param subjects A collection that should hold subjects. The new subjects are added to the collection. Must not be {@code null}.
502      * @param scopeMap A scope map that holds policy scopes. The subjects are retrieved from the scope objects.
503      */
504     private void addSubjects(final Collection<PolicySubject> subjects, final ScopeMap scopeMap) {
505         for (PolicyScope scope : scopeMap.getStoredScopes()) {
506             final Collection<PolicySubject> scopedSubjects = scope.getPolicySubjects();
507             subjects.addAll(scopedSubjects);
508         }
509     }
510 
511     /**
512      * Creates a service policy scope <emph>locator</emph> object, that serves as a access key into
513      * a {@code PolicyMap} where actual service policy scope for given service can be retrieved.
514      *
515      * @param service qualified name of the service. Must not be {@code null}.
516      * @throws IllegalArgumentException in case service, port or operation parameter is {@code null}.
517      */
518     public static PolicyMapKey createWsdlServiceScopeKey(final QName service) throws IllegalArgumentException {
519         if (service == null) {
520             throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0031_SERVICE_PARAM_MUST_NOT_BE_NULL()));
521         }
522         return new PolicyMapKey(service, null, null, serviceKeyHandler);
523     }
524 
525     /**
526      * Creates an endpoint policy scope <emph>locator</emph> object, that serves as a access key into
527      * a {@code PolicyMap} where actual endpoint policy scope for given endpoint can be retrieved.
528      *
529      * @param service qualified name of the service. Must not be {@code null}.
530      * @param port qualified name of the endpoint. Must not be {@code null}.
531      * @throws IllegalArgumentException in case service, port or operation parameter is {@code null}.
532      */
533     public static PolicyMapKey createWsdlEndpointScopeKey(final QName service, final QName port) throws IllegalArgumentException {
534         if (service == null || port == null) {
535             throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0033_SERVICE_AND_PORT_PARAM_MUST_NOT_BE_NULL(service, port)));
536         }
537         return new PolicyMapKey(service, port, null, endpointKeyHandler);
538     }
539 
540     /**
541      * Creates an operation policy scope <emph>locator</emph> object, that serves as a access key into
542      * a {@code PolicyMap} where actual operation policy scope for given bound operation can be retrieved.
543      *
544      * @param service qualified name of the service. Must not be {@code null}.
545      * @param port qualified name of the endpoint. Must not be {@code null}.
546      * @param operation qualified name of the operation. Must not be {@code null}.
547      * @throws IllegalArgumentException in case service, port or operation parameter is {@code null}.
548      */
549     public static PolicyMapKey createWsdlOperationScopeKey(final QName service, final QName port, final QName operation) throws IllegalArgumentException {
550         return createOperationOrInputOutputMessageKey(service, port, operation);
551     }
552 
553     /**
554      * Creates an input/output message policy scope <emph>locator</emph> object identified by a bound operation, that serves as a
555      * access key into {@code PolicyMap} where actual input/output message policy scope for given input message of a bound operation
556      * can be retrieved.
557      * <p/>
558      * The method returns a key that is compliant with <emph>WSDL 1.1 Basic Profile Specification</emph>, according to which there
559      * should be no two operations with the same name in a single port type definition.
560      *
561      * @param service qualified name of the service. Must not be {@code null}.
562      * @param port qualified name of the endpoint. Must not be {@code null}.
563      * @param operation qualified name of the operation. Must not be {@code null}.
564      * @throws IllegalArgumentException in case service, port or operation parameter is {@code null}.
565      *
566      */
567     public static PolicyMapKey createWsdlMessageScopeKey(final QName service, final QName port, final QName operation) throws IllegalArgumentException {
568         return createOperationOrInputOutputMessageKey(service, port, operation);
569     }
570 
571     /**
572      * Creates a fault message policy scope <emph>locator</emph> object identified by a bound operation, that serves as a
573      * access key into {@code PolicyMap} where the actual fault message policy scope for one of the faults of a bound operation
574      * can be retrieved.
575      * <p/>
576      * The method returns a key that is compliant with the <emph>WSDL 1.1 Basic Profile Specification</emph>, according to which there
577      * should be no two operations with the same name in a single port type definition.
578      *
579      * @param service qualified name of the service. Must not be {@code null}.
580      * @param port qualified name of the endpoint. Must not be {@code null}.
581      * @param operation qualified name of the operation. Must not be {@code null}.
582      * @param fault qualified name of the fault. Do not confuse this with the name of the actual message. This parameter
583      * takes the wsdl:binding/wsdl:operation/wsdl:fault name and not the wsdl:message name. Must not be {@code null}.
584      * @throws IllegalArgumentException in case service, port or operation parameter is {@code null}.
585      *
586      */
587     public static PolicyMapKey createWsdlFaultMessageScopeKey(final QName service, final QName port, final QName operation, final QName fault) throws IllegalArgumentException {
588         if (service == null || port == null || operation == null || fault == null) {
589             throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0030_SERVICE_PORT_OPERATION_FAULT_MSG_PARAM_MUST_NOT_BE_NULL(service, port, operation, fault)));
590         }
591 
592         return new PolicyMapKey(service, port, operation, fault, faultMessageHandler);
593     }
594 
595     private static PolicyMapKey createOperationOrInputOutputMessageKey(final QName service, final QName port, final QName operation) {
596         if (service == null || port == null || operation == null) {
597             throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0029_SERVICE_PORT_OPERATION_PARAM_MUST_NOT_BE_NULL(service, port, operation)));
598         }
599 
600         return new PolicyMapKey(service, port, operation, operationAndInputOutputMessageKeyHandler);
601     }
602 
603     @Override
604     public String toString(){
605         // TODO
606         final StringBuffer result = new StringBuffer();
607         if(null!=this.serviceMap) {
608             result.append("\nServiceMap=").append(this.serviceMap);
609         }
610         if(null!=this.endpointMap) {
611             result.append("\nEndpointMap=").append(this.endpointMap);
612         }
613         if(null!=this.operationMap) {
614             result.append("\nOperationMap=").append(this.operationMap);
615         }
616         if(null!=this.inputMessageMap) {
617             result.append("\nInputMessageMap=").append(this.inputMessageMap);
618         }
619         if(null!=this.outputMessageMap) {
620             result.append("\nOutputMessageMap=").append(this.outputMessageMap);
621         }
622         if(null!=this.faultMessageMap) {
623             result.append("\nFaultMessageMap=").append(this.faultMessageMap);
624         }
625         return result.toString();
626     }
627 
628     public Iterator<Policy> iterator() {
629         return new Iterator<Policy> () {
630             private final Iterator<Iterator<Policy>> mainIterator;
631             private Iterator<Policy> currentScopeIterator;
632 
633             { // instance initialization
634                 final Collection<Iterator<Policy>> scopeIterators = new ArrayList<Iterator<Policy>>(6);
635                 scopeIterators.add(serviceMap.iterator());
636                 scopeIterators.add(endpointMap.iterator());
637                 scopeIterators.add(operationMap.iterator());
638                 scopeIterators.add(inputMessageMap.iterator());
639                 scopeIterators.add(outputMessageMap.iterator());
640                 scopeIterators.add(faultMessageMap.iterator());
641 
642                 mainIterator = scopeIterators.iterator();
643                 currentScopeIterator = mainIterator.next();
644             }
645 
646             public boolean hasNext() {
647                 while (!currentScopeIterator.hasNext()) {
648                     if (mainIterator.hasNext()) {
649                         currentScopeIterator = mainIterator.next();
650                     } else {
651                         return false;
652                     }
653                 }
654 
655                 return true;
656             }
657 
658             public Policy next() {
659                 if (hasNext()) {
660                     return currentScopeIterator.next();
661                 }
662                 throw LOGGER.logSevereException(new NoSuchElementException(LocalizationMessages.WSP_0054_NO_MORE_ELEMS_IN_POLICY_MAP()));
663             }
664 
665             public void remove() {
666                 throw LOGGER.logSevereException(new UnsupportedOperationException(LocalizationMessages.WSP_0034_REMOVE_OPERATION_NOT_SUPPORTED()));
667             }
668         };
669     }
670 
671 }