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 com.sun.xml.internal.ws.policy.privateutil.LocalizationMessages; 30import com.sun.xml.internal.ws.policy.spi.PolicyAssertionValidator.Fitness; 31import java.util.Collection; 32import java.util.LinkedList; 33 34/** 35 * Contains static methods for policy alternative selection. Given policy map is changed so that 36 * each effective policy contains at most one policy alternative. Uses domain 37 * specific @see com.sun.xml.internal.ws.policy.spi.PolicySelector 38 * to find out whether particular policy assertion is actually supported. 39 * 40 * If you are using JAX-WS, use the com.sun.xml.internal.ws.api.policy.AlternativeSelector 41 * instead of this class. 42 * 43 * @author Jakub Podlesak (jakub.podlesak at sun.com) 44 * @author Fabian Ritzmann 45 */ 46public class EffectiveAlternativeSelector { 47 private enum AlternativeFitness { 48 UNEVALUATED { 49 AlternativeFitness combine(final Fitness assertionFitness) { 50 switch (assertionFitness) { 51 case UNKNOWN: 52 return UNKNOWN; 53 case UNSUPPORTED: 54 return UNSUPPORTED; 55 case SUPPORTED: 56 return SUPPORTED; 57 case INVALID: 58 return INVALID; 59 default: 60 return UNEVALUATED; 61 } 62 } 63 }, 64 INVALID { 65 AlternativeFitness combine(final Fitness assertionFitness) { 66 return INVALID; 67 } 68 }, 69 UNKNOWN { 70 AlternativeFitness combine(final Fitness assertionFitness) { 71 switch (assertionFitness) { 72 case UNKNOWN: 73 return UNKNOWN; 74 case UNSUPPORTED: 75 return UNSUPPORTED; 76 case SUPPORTED: 77 return PARTIALLY_SUPPORTED; 78 case INVALID: 79 return INVALID; 80 default: 81 return UNEVALUATED; 82 } 83 } 84 }, 85 UNSUPPORTED { 86 AlternativeFitness combine(final Fitness assertionFitness) { 87 switch (assertionFitness) { 88 case UNKNOWN: 89 case UNSUPPORTED: 90 return UNSUPPORTED; 91 case SUPPORTED: 92 return PARTIALLY_SUPPORTED; 93 case INVALID: 94 return INVALID; 95 default: 96 return UNEVALUATED; 97 } 98 } 99 }, 100 PARTIALLY_SUPPORTED { 101 AlternativeFitness combine(final Fitness assertionFitness) { 102 switch (assertionFitness) { 103 case UNKNOWN: 104 case UNSUPPORTED: 105 case SUPPORTED: 106 return PARTIALLY_SUPPORTED; 107 case INVALID: 108 return INVALID; 109 default: 110 return UNEVALUATED; 111 } 112 } 113 }, 114 SUPPORTED_EMPTY { 115 AlternativeFitness combine(final Fitness assertionFitness) { 116 // will not localize - this exception may not occur if there is no programatic error in this class 117 throw new UnsupportedOperationException("Combine operation was called unexpectedly on 'SUPPORTED_EMPTY' alternative fitness enumeration state."); 118 } 119 }, 120 SUPPORTED { 121 AlternativeFitness combine(final Fitness assertionFitness) { 122 switch (assertionFitness) { 123 case UNKNOWN: 124 case UNSUPPORTED: 125 return PARTIALLY_SUPPORTED; 126 case SUPPORTED: 127 return SUPPORTED; 128 case INVALID: 129 return INVALID; 130 default: 131 return UNEVALUATED; 132 } 133 } 134 }; 135 136 abstract AlternativeFitness combine(Fitness assertionFitness); 137 } 138 139 private static final PolicyLogger LOGGER = PolicyLogger.getLogger(EffectiveAlternativeSelector.class); 140 141 /** 142 * Does the selection for policy map bound to given modifier. 143 * 144 * If you are using JAX-WS, use the com.sun.xml.internal.ws.api.policy.AlternativeSelector 145 * instead of this class. 146 * 147 * @param modifier Holds the policy map 148 * @throws PolicyException Most likely an internal error if a policy could not be read or set on the policy map 149 * @see EffectivePolicyModifier which the map is bound to 150 */ 151 public static void doSelection(final EffectivePolicyModifier modifier) throws PolicyException { 152 final AssertionValidationProcessor validationProcessor = AssertionValidationProcessor.getInstance(); 153 selectAlternatives(modifier, validationProcessor); 154 } 155 156 /** 157 * This method is intended to be called by extension classes that need to 158 * override the behavior of {@link #doSelection}. 159 * 160 * @param modifier 161 * @param validationProcessor 162 * @throws PolicyException 163 */ 164 protected static void selectAlternatives(final EffectivePolicyModifier modifier, 165 final AssertionValidationProcessor validationProcessor) 166 throws PolicyException { 167 final PolicyMap map = modifier.getMap(); 168 for (PolicyMapKey mapKey : map.getAllServiceScopeKeys()) { 169 final Policy oldPolicy = map.getServiceEffectivePolicy(mapKey); 170 modifier.setNewEffectivePolicyForServiceScope(mapKey, selectBestAlternative(oldPolicy, validationProcessor)); 171 } 172 for (PolicyMapKey mapKey : map.getAllEndpointScopeKeys()) { 173 final Policy oldPolicy = map.getEndpointEffectivePolicy(mapKey); 174 modifier.setNewEffectivePolicyForEndpointScope(mapKey, selectBestAlternative(oldPolicy, validationProcessor)); 175 } 176 for (PolicyMapKey mapKey : map.getAllOperationScopeKeys()) { 177 final Policy oldPolicy = map.getOperationEffectivePolicy(mapKey); 178 modifier.setNewEffectivePolicyForOperationScope(mapKey, selectBestAlternative(oldPolicy, validationProcessor)); 179 } 180 for (PolicyMapKey mapKey : map.getAllInputMessageScopeKeys()) { 181 final Policy oldPolicy = map.getInputMessageEffectivePolicy(mapKey); 182 modifier.setNewEffectivePolicyForInputMessageScope(mapKey, selectBestAlternative(oldPolicy, validationProcessor)); 183 } 184 for (PolicyMapKey mapKey : map.getAllOutputMessageScopeKeys()) { 185 final Policy oldPolicy = map.getOutputMessageEffectivePolicy(mapKey); 186 modifier.setNewEffectivePolicyForOutputMessageScope(mapKey, selectBestAlternative(oldPolicy, validationProcessor)); 187 } 188 for (PolicyMapKey mapKey : map.getAllFaultMessageScopeKeys()) { 189 final Policy oldPolicy = map.getFaultMessageEffectivePolicy(mapKey); 190 modifier.setNewEffectivePolicyForFaultMessageScope(mapKey, selectBestAlternative(oldPolicy, validationProcessor)); 191 } 192 } 193 194 private static Policy selectBestAlternative(final Policy policy, final AssertionValidationProcessor validationProcessor) throws PolicyException { 195 AssertionSet bestAlternative = null; 196 AlternativeFitness bestAlternativeFitness = AlternativeFitness.UNEVALUATED; 197 for (AssertionSet alternative : policy) { 198 AlternativeFitness alternativeFitness = (alternative.isEmpty()) ? AlternativeFitness.SUPPORTED_EMPTY : AlternativeFitness.UNEVALUATED; 199 for ( PolicyAssertion assertion : alternative ) { 200 201 final Fitness assertionFitness = validationProcessor.validateClientSide(assertion); 202 switch(assertionFitness) { 203 case UNKNOWN: 204 case UNSUPPORTED: 205 case INVALID: 206 LOGGER.warning(LocalizationMessages.WSP_0075_PROBLEMATIC_ASSERTION_STATE(assertion.getName(), assertionFitness)); 207 break; 208 default: 209 break; 210 } 211 212 alternativeFitness = alternativeFitness.combine(assertionFitness); 213 } 214 215 if (bestAlternativeFitness.compareTo(alternativeFitness) < 0) { 216 // better alternative found 217 bestAlternative = alternative; 218 bestAlternativeFitness = alternativeFitness; 219 } 220 221 if (bestAlternativeFitness == AlternativeFitness.SUPPORTED) { 222 // all assertions supported by at least one selector 223 break; 224 } 225 } 226 227 switch (bestAlternativeFitness) { 228 case INVALID: 229 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0053_INVALID_CLIENT_SIDE_ALTERNATIVE())); 230 case UNKNOWN: 231 case UNSUPPORTED: 232 case PARTIALLY_SUPPORTED: 233 LOGGER.warning(LocalizationMessages.WSP_0019_SUBOPTIMAL_ALTERNATIVE_SELECTED(bestAlternativeFitness)); 234 break; 235 default: 236 break; 237 } 238 239 Collection<AssertionSet> alternativeSet = null; 240 if (bestAlternative != null) { 241 // return a policy containing just the picked alternative 242 alternativeSet = new LinkedList<AssertionSet>(); 243 alternativeSet.add(bestAlternative); 244 } 245 return Policy.createPolicy(policy.getNamespaceVersion(), policy.getName(), policy.getId(), alternativeSet); 246 } 247} 248