1/*
2 * Copyright (c) 1997, 2012, 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
26package com.sun.xml.internal.ws.policy;
27
28import com.sun.xml.internal.ws.policy.privateutil.LocalizationMessages;
29import com.sun.xml.internal.ws.policy.privateutil.PolicyLogger;
30import java.util.ArrayList;
31import java.util.Collection;
32import java.util.HashMap;
33import java.util.Iterator;
34import java.util.LinkedList;
35import java.util.List;
36import java.util.Map;
37import java.util.NoSuchElementException;
38import java.util.Set;
39import 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 */
52public 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}
672