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.PolicyLogger; 29import java.util.Collection; 30import java.util.LinkedList; 31import java.util.List; 32import java.util.Queue; 33import com.sun.xml.internal.ws.policy.privateutil.LocalizationMessages; 34import com.sun.xml.internal.ws.policy.sourcemodel.wspolicy.NamespaceVersion; 35import java.util.ArrayList; 36 37/** 38 * The instance of this class is intended to provide policy intersection mechanism. 39 * 40 * @author Marek Potociar (marek.potociar@sun.com) 41 */ 42public final class PolicyIntersector { 43 static enum CompatibilityMode { 44 STRICT, 45 LAX 46 } 47 48 private static final PolicyIntersector STRICT_INTERSECTOR = new PolicyIntersector(CompatibilityMode.STRICT); 49 private static final PolicyIntersector LAX_INTERSECTOR = new PolicyIntersector(CompatibilityMode.LAX); 50 private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyIntersector.class); 51 52 private CompatibilityMode mode; 53 54 /** 55 * Prevents direct instantiation of this class from outside 56 * @param intersectionMode intersection mode 57 */ 58 private PolicyIntersector(CompatibilityMode intersectionMode) { 59 this.mode = intersectionMode; 60 } 61 62 /** 63 * Returns a strict policy intersector that can be used to intersect group of policies. 64 * 65 * @return policy intersector instance. 66 */ 67 public static PolicyIntersector createStrictPolicyIntersector() { 68 return PolicyIntersector.STRICT_INTERSECTOR; 69 } 70 71 /** 72 * Returns a strict policy intersector that can be used to intersect group of policies. 73 * 74 * @return policy intersector instance. 75 */ 76 public static PolicyIntersector createLaxPolicyIntersector() { 77 return PolicyIntersector.LAX_INTERSECTOR; 78 } 79 80 /** 81 * Performs intersection on the input collection of policies and returns the resulting (intersected) policy. If input policy 82 * collection contains only a single policy instance, no intersection is performed and the instance is directly returned 83 * as a method call result. 84 * 85 * @param policies collection of policies to be intersected. Must not be {@code null} nor empty, otherwise exception is thrown. 86 * @return intersected policy as a result of perfromed policy intersection. A {@code null} value is never returned. 87 * 88 * @throws IllegalArgumentException in case {@code policies} argument is either {@code null} or empty collection. 89 */ 90 public Policy intersect(final Policy... policies) { 91 if (policies == null || policies.length == 0) { 92 throw LOGGER.logSevereException(new IllegalArgumentException(LocalizationMessages.WSP_0056_NEITHER_NULL_NOR_EMPTY_POLICY_COLLECTION_EXPECTED())); 93 } else if (policies.length == 1) { 94 return policies[0]; 95 } 96 97 // check for "null" and "empty" policy: if such policy is found return "null" policy, 98 // or if all policies are "empty", return "empty" policy 99 boolean found = false; 100 boolean allPoliciesEmpty = true; 101 NamespaceVersion latestVersion = null; 102 for (Policy tested : policies) { 103 if (tested.isEmpty()) { 104 found = true; 105 } else { 106 if (tested.isNull()) { 107 found = true; 108 } 109 allPoliciesEmpty = false; 110 } 111 if (latestVersion == null) { 112 latestVersion = tested.getNamespaceVersion(); 113 } else if (latestVersion.compareTo(tested.getNamespaceVersion()) < 0) { 114 latestVersion = tested.getNamespaceVersion(); 115 } 116 117 if (found && !allPoliciesEmpty) { 118 return Policy.createNullPolicy(latestVersion, null, null); 119 } 120 } 121 latestVersion = (latestVersion != null) ? latestVersion : NamespaceVersion.getLatestVersion(); 122 if (allPoliciesEmpty) { 123 return Policy.createEmptyPolicy(latestVersion, null, null); 124 } 125 126 // simple tests didn't lead to final answer => let's performe some intersecting ;) 127 final List<AssertionSet> finalAlternatives = new LinkedList<AssertionSet>(policies[0].getContent()); 128 final Queue<AssertionSet> testedAlternatives = new LinkedList<AssertionSet>(); 129 final List<AssertionSet> alternativesToMerge = new ArrayList<AssertionSet>(2); 130 for (int i = 1; i < policies.length; i++) { 131 final Collection<AssertionSet> currentAlternatives = policies[i].getContent(); 132 133 testedAlternatives.clear(); 134 testedAlternatives.addAll(finalAlternatives); 135 finalAlternatives.clear(); 136 137 AssertionSet testedAlternative; 138 while ((testedAlternative = testedAlternatives.poll()) != null) { 139 for (AssertionSet currentAlternative : currentAlternatives) { 140 if (testedAlternative.isCompatibleWith(currentAlternative, this.mode)) { 141 alternativesToMerge.add(testedAlternative); 142 alternativesToMerge.add(currentAlternative); 143 finalAlternatives.add(AssertionSet.createMergedAssertionSet(alternativesToMerge)); 144 alternativesToMerge.clear(); 145 } 146 } 147 } 148 } 149 150 return Policy.createPolicy(latestVersion, null, null, finalAlternatives); 151 } 152} 153