src/share/jaxws_classes/com/sun/xml/internal/ws/policy/sourcemodel/PolicyModelTranslator.java

Thu, 12 Oct 2017 19:44:07 +0800

author
aoqi
date
Thu, 12 Oct 2017 19:44:07 +0800
changeset 760
e530533619ec
parent 0
373ffda63c9a
permissions
-rw-r--r--

merge

     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  */
    26 package com.sun.xml.internal.ws.policy.sourcemodel;
    28 import java.util.ArrayList;
    29 import java.util.Collection;
    30 import java.util.Collections;
    31 import java.util.HashMap;
    32 import java.util.LinkedList;
    33 import java.util.List;
    34 import java.util.Map;
    35 import java.util.Queue;
    37 import com.sun.xml.internal.ws.policy.AssertionSet;
    38 import com.sun.xml.internal.ws.policy.Policy;
    39 import com.sun.xml.internal.ws.policy.PolicyAssertion;
    40 import com.sun.xml.internal.ws.policy.PolicyException;
    41 import com.sun.xml.internal.ws.policy.privateutil.LocalizationMessages;
    42 import com.sun.xml.internal.ws.policy.privateutil.PolicyLogger;
    43 import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils;
    44 import com.sun.xml.internal.ws.policy.spi.AssertionCreationException;
    45 import com.sun.xml.internal.ws.policy.spi.PolicyAssertionCreator;
    47 /**
    48  * This class provides a method for translating a {@link PolicySourceModel} structure to a normalized {@link Policy} expression.
    49  * The resulting Policy is disconnected from its model, thus any additional changes in the model will have no effect on the Policy
    50  * expression.
    51  *
    52  * @author Marek Potociar
    53  * @author Fabian Ritzmann
    54  */
    55 public class PolicyModelTranslator {
    57     private static final class ContentDecomposition {
    58         final List<Collection<ModelNode>> exactlyOneContents = new LinkedList<Collection<ModelNode>>();
    59         final List<ModelNode> assertions = new LinkedList<ModelNode>();
    61         void reset() {
    62             exactlyOneContents.clear();
    63             assertions.clear();
    64         }
    65     }
    67     private static final class RawAssertion {
    68         ModelNode originalNode; // used to initialize nestedPolicy and nestedAssertions in the constructor of RawAlternative
    69         Collection<RawAlternative> nestedAlternatives = null;
    70         final Collection<ModelNode> parameters;
    72         RawAssertion(ModelNode originalNode, Collection<ModelNode> parameters) {
    73             this.parameters = parameters;
    74             this.originalNode = originalNode;
    75         }
    76     }
    78     private static final class RawAlternative {
    79         private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyModelTranslator.RawAlternative.class);
    81         final List<RawPolicy> allNestedPolicies = new LinkedList<RawPolicy>(); // used to track the nested policies which need to be normalized
    82         final Collection<RawAssertion> nestedAssertions;
    84         RawAlternative(Collection<ModelNode> assertionNodes) throws PolicyException {
    85             this.nestedAssertions = new LinkedList<RawAssertion>();
    86             for (ModelNode node : assertionNodes) {
    87                 RawAssertion assertion = new RawAssertion(node, new LinkedList<ModelNode>());
    88                 nestedAssertions.add(assertion);
    90                 for (ModelNode assertionNodeChild : assertion.originalNode.getChildren()) {
    91                     switch (assertionNodeChild.getType()) {
    92                         case ASSERTION_PARAMETER_NODE:
    93                             assertion.parameters.add(assertionNodeChild);
    94                             break;
    95                         case POLICY:
    96                         case POLICY_REFERENCE:
    97                             if (assertion.nestedAlternatives == null) {
    98                                 assertion.nestedAlternatives = new LinkedList<RawAlternative>();
    99                                 RawPolicy nestedPolicy;
   100                                 if (assertionNodeChild.getType() == ModelNode.Type.POLICY) {
   101                                     nestedPolicy = new RawPolicy(assertionNodeChild, assertion.nestedAlternatives);
   102                                 } else {
   103                                     nestedPolicy = new RawPolicy(getReferencedModelRootNode(assertionNodeChild), assertion.nestedAlternatives);
   104                                 }
   105                                 this.allNestedPolicies.add(nestedPolicy);
   106                             } else {
   107                                 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0006_UNEXPECTED_MULTIPLE_POLICY_NODES()));
   108                             }
   109                             break;
   110                         default:
   111                             throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0008_UNEXPECTED_CHILD_MODEL_TYPE(assertionNodeChild.getType())));
   112                     }
   113                 }
   114             }
   115         }
   117     }
   119     private static final class RawPolicy {
   120         final Collection<ModelNode> originalContent;
   121         final Collection<RawAlternative> alternatives;
   123         RawPolicy(ModelNode policyNode, Collection<RawAlternative> alternatives) {
   124             originalContent = policyNode.getChildren();
   125             this.alternatives = alternatives;
   126         }
   127     }
   129     private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyModelTranslator.class);
   131     private static final PolicyAssertionCreator defaultCreator = new DefaultPolicyAssertionCreator();
   133     private final Map<String, PolicyAssertionCreator> assertionCreators;
   136     private PolicyModelTranslator() throws PolicyException {
   137         this(null);
   138     }
   140     protected PolicyModelTranslator(final Collection<PolicyAssertionCreator> creators) throws PolicyException {
   141         LOGGER.entering(creators);
   143         final Collection<PolicyAssertionCreator> allCreators = new LinkedList<PolicyAssertionCreator>();
   144         final PolicyAssertionCreator[] discoveredCreators = PolicyUtils.ServiceProvider.load(PolicyAssertionCreator.class);
   145         for (PolicyAssertionCreator creator : discoveredCreators) {
   146             allCreators.add(creator);
   147         }
   148         if (creators != null) {
   149             for (PolicyAssertionCreator creator : creators) {
   150                 allCreators.add(creator);
   151             }
   152         }
   154         final Map<String, PolicyAssertionCreator> pacMap = new HashMap<String, PolicyAssertionCreator>();
   155         for (PolicyAssertionCreator creator : allCreators) {
   156             final String[] supportedURIs = creator.getSupportedDomainNamespaceURIs();
   157             final String creatorClassName = creator.getClass().getName();
   159             if (supportedURIs == null || supportedURIs.length == 0) {
   160                 LOGGER.warning(LocalizationMessages.WSP_0077_ASSERTION_CREATOR_DOES_NOT_SUPPORT_ANY_URI(creatorClassName));
   161                 continue;
   162             }
   164             for (String supportedURI : supportedURIs) {
   165                 LOGGER.config(LocalizationMessages.WSP_0078_ASSERTION_CREATOR_DISCOVERED(creatorClassName, supportedURI));
   166                 if (supportedURI == null || supportedURI.length() == 0) {
   167                     throw LOGGER.logSevereException(new PolicyException(
   168                             LocalizationMessages.WSP_0070_ERROR_REGISTERING_ASSERTION_CREATOR(creatorClassName)));
   169                 }
   171                 final PolicyAssertionCreator oldCreator = pacMap.put(supportedURI, creator);
   172                 if (oldCreator != null) {
   173                     throw LOGGER.logSevereException(new PolicyException(
   174                             LocalizationMessages.WSP_0071_ERROR_MULTIPLE_ASSERTION_CREATORS_FOR_NAMESPACE(
   175                             supportedURI, oldCreator.getClass().getName(), creator.getClass().getName())));
   176                 }
   177             }
   178         }
   180         this.assertionCreators = Collections.unmodifiableMap(pacMap);
   181         LOGGER.exiting();
   182     }
   184     /**
   185      * Method returns thread-safe policy model translator instance.
   186      *
   187      * This method is only intended to be used by code that has no dependencies on
   188      * JAX-WS. Otherwise use com.sun.xml.internal.ws.policy.api.ModelTranslator.
   189      *
   190      * @return A policy model translator instance.
   191      * @throws PolicyException If instantiating a PolicyAssertionCreator failed.
   192      */
   193     public static PolicyModelTranslator getTranslator() throws PolicyException {
   194         return new PolicyModelTranslator();
   195     }
   197     /**
   198      * The method translates {@link PolicySourceModel} structure into normalized {@link Policy} expression. The resulting Policy
   199      * is disconnected from its model, thus any additional changes in model will have no effect on the Policy expression.
   200      *
   201      * @param model the model to be translated into normalized policy expression. Must not be {@code null}.
   202      * @return translated policy expression in it's normalized form.
   203      * @throws PolicyException in case of translation failure
   204      */
   205     public Policy translate(final PolicySourceModel model) throws PolicyException {
   206         LOGGER.entering(model);
   208         if (model == null) {
   209             throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0043_POLICY_MODEL_TRANSLATION_ERROR_INPUT_PARAM_NULL()));
   210         }
   212         PolicySourceModel localPolicyModelCopy;
   213         try {
   214             localPolicyModelCopy = model.clone();
   215         } catch (CloneNotSupportedException e) {
   216             throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0016_UNABLE_TO_CLONE_POLICY_SOURCE_MODEL(), e));
   217         }
   219         final String policyId = localPolicyModelCopy.getPolicyId();
   220         final String policyName = localPolicyModelCopy.getPolicyName();
   222         final Collection<AssertionSet> alternatives = createPolicyAlternatives(localPolicyModelCopy);
   223         LOGGER.finest(LocalizationMessages.WSP_0052_NUMBER_OF_ALTERNATIVE_COMBINATIONS_CREATED(alternatives.size()));
   225         Policy policy = null;
   226         if (alternatives.size() == 0) {
   227             policy = Policy.createNullPolicy(model.getNamespaceVersion(), policyName, policyId);
   228             LOGGER.finest(LocalizationMessages.WSP_0055_NO_ALTERNATIVE_COMBINATIONS_CREATED());
   229         } else if (alternatives.size() == 1 && alternatives.iterator().next().isEmpty()) {
   230             policy = Policy.createEmptyPolicy(model.getNamespaceVersion(), policyName, policyId);
   231             LOGGER.finest(LocalizationMessages.WSP_0026_SINGLE_EMPTY_ALTERNATIVE_COMBINATION_CREATED());
   232         } else {
   233             policy = Policy.createPolicy(model.getNamespaceVersion(), policyName, policyId, alternatives);
   234             LOGGER.finest(LocalizationMessages.WSP_0057_N_ALTERNATIVE_COMBINATIONS_M_POLICY_ALTERNATIVES_CREATED(alternatives.size(), policy.getNumberOfAssertionSets()));
   235         }
   237         LOGGER.exiting(policy);
   238         return policy;
   239     }
   241     /**
   242      * Method creates policy alternatives according to provided model. The model structure is modified in the process.
   243      *
   244      * @return created policy alternatives resulting from policy source model.
   245      */
   246     private Collection<AssertionSet> createPolicyAlternatives(final PolicySourceModel model) throws PolicyException {
   247         // creating global method variables
   248         final ContentDecomposition decomposition = new ContentDecomposition();
   250         // creating processing queue and starting the processing iterations
   251         final Queue<RawPolicy> policyQueue = new LinkedList<RawPolicy>();
   252         final Queue<Collection<ModelNode>> contentQueue = new LinkedList<Collection<ModelNode>>();
   254         final RawPolicy rootPolicy = new RawPolicy(model.getRootNode(), new LinkedList<RawAlternative>());
   255         RawPolicy processedPolicy = rootPolicy;
   256         do {
   257             Collection<ModelNode> processedContent = processedPolicy.originalContent;
   258             do {
   259                 decompose(processedContent, decomposition);
   260                 if (decomposition.exactlyOneContents.isEmpty()) {
   261                     final RawAlternative alternative = new RawAlternative(decomposition.assertions);
   262                     processedPolicy.alternatives.add(alternative);
   263                     if (!alternative.allNestedPolicies.isEmpty()) {
   264                         policyQueue.addAll(alternative.allNestedPolicies);
   265                     }
   266                 } else { // we have a non-empty collection of exactly ones
   267                     final Collection<Collection<ModelNode>> combinations = PolicyUtils.Collections.combine(decomposition.assertions, decomposition.exactlyOneContents, false);
   268                     if (combinations != null && !combinations.isEmpty()) {
   269                         // processed alternative was split into some new alternatives, which we need to process
   270                         contentQueue.addAll(combinations);
   271                     }
   272                 }
   273             } while ((processedContent = contentQueue.poll()) != null);
   274         } while ((processedPolicy = policyQueue.poll()) != null);
   276         // normalize nested policies to contain single alternative only
   277         final Collection<AssertionSet> assertionSets = new LinkedList<AssertionSet>();
   278         for (RawAlternative rootAlternative : rootPolicy.alternatives) {
   279             final Collection<AssertionSet> normalizedAlternatives = normalizeRawAlternative(rootAlternative);
   280             assertionSets.addAll(normalizedAlternatives);
   281         }
   283         return assertionSets;
   284     }
   286     /**
   287      * Decomposes the unprocessed alternative content into two different collections:
   288      * <p/>
   289      * Content of 'EXACTLY_ONE' child nodes is expanded and placed in one list and
   290      * 'ASSERTION' nodes are placed into other list. Direct 'ALL' and 'POLICY' child nodes are 'dissolved' in the process.
   291      *
   292      * Method reuses precreated ContentDecomposition object, which is reset before reuse.
   293      */
   294     private void decompose(final Collection<ModelNode> content, final ContentDecomposition decomposition) throws PolicyException {
   295         decomposition.reset();
   297         final Queue<ModelNode> allContentQueue = new LinkedList<ModelNode>(content);
   298         ModelNode node;
   299         while ((node = allContentQueue.poll()) != null) {
   300             // dissolving direct 'POLICY', 'POLICY_REFERENCE' and 'ALL' child nodes
   301             switch (node.getType()) {
   302                 case POLICY :
   303                 case ALL :
   304                     allContentQueue.addAll(node.getChildren());
   305                     break;
   306                 case POLICY_REFERENCE :
   307                     allContentQueue.addAll(getReferencedModelRootNode(node).getChildren());
   308                     break;
   309                 case EXACTLY_ONE :
   310                     decomposition.exactlyOneContents.add(expandsExactlyOneContent(node.getChildren()));
   311                     break;
   312                 case ASSERTION :
   313                     decomposition.assertions.add(node);
   314                     break;
   315                 default :
   316                     throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0007_UNEXPECTED_MODEL_NODE_TYPE_FOUND(node.getType())));
   317             }
   318         }
   319     }
   321     private static ModelNode getReferencedModelRootNode(final ModelNode policyReferenceNode) throws PolicyException {
   322         final PolicySourceModel referencedModel = policyReferenceNode.getReferencedModel();
   323         if (referencedModel == null) {
   324             final PolicyReferenceData refData = policyReferenceNode.getPolicyReferenceData();
   325             if (refData == null) {
   326                 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0041_POLICY_REFERENCE_NODE_FOUND_WITH_NO_POLICY_REFERENCE_IN_IT()));
   327             } else {
   328                 throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0010_UNEXPANDED_POLICY_REFERENCE_NODE_FOUND_REFERENCING(refData.getReferencedModelUri())));
   329             }
   330         } else {
   331             return referencedModel.getRootNode();
   332         }
   333     }
   335     /**
   336      * Expands content of 'EXACTLY_ONE' node. Direct 'EXACTLY_ONE' child nodes are dissolved in the process.
   337      */
   338     private Collection<ModelNode> expandsExactlyOneContent(final Collection<ModelNode> content) throws PolicyException {
   339         final Collection<ModelNode> result = new LinkedList<ModelNode>();
   341         final Queue<ModelNode> eoContentQueue = new LinkedList<ModelNode>(content);
   342         ModelNode node;
   343         while ((node = eoContentQueue.poll()) != null) {
   344             // dissolving direct 'EXACTLY_ONE' child nodes
   345             switch (node.getType()) {
   346                 case POLICY :
   347                 case ALL :
   348                 case ASSERTION :
   349                     result.add(node);
   350                     break;
   351                 case POLICY_REFERENCE :
   352                     result.add(getReferencedModelRootNode(node));
   353                     break;
   354                 case EXACTLY_ONE :
   355                     eoContentQueue.addAll(node.getChildren());
   356                     break;
   357                 default :
   358                     throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0001_UNSUPPORTED_MODEL_NODE_TYPE(node.getType())));
   359             }
   360         }
   362         return result;
   363     }
   365     private List<AssertionSet> normalizeRawAlternative(final RawAlternative alternative) throws AssertionCreationException, PolicyException {
   366         final List<PolicyAssertion> normalizedContentBase = new LinkedList<PolicyAssertion>();
   367         final Collection<List<PolicyAssertion>> normalizedContentOptions = new LinkedList<List<PolicyAssertion>>();
   368         if (!alternative.nestedAssertions.isEmpty()) {
   369             final Queue<RawAssertion> nestedAssertionsQueue = new LinkedList<RawAssertion>(alternative.nestedAssertions);
   370             RawAssertion rawAssertion;
   371             while((rawAssertion = nestedAssertionsQueue.poll()) != null) {
   372                 final List<PolicyAssertion> normalized = normalizeRawAssertion(rawAssertion);
   373                 // if there is only a single result, we can add it direclty to the content base collection
   374                 // more elements in the result indicate that we will have to create combinations
   375                 if (normalized.size() == 1) {
   376                     normalizedContentBase.addAll(normalized);
   377                 } else {
   378                     normalizedContentOptions.add(normalized);
   379                 }
   380             }
   381         }
   383         final List<AssertionSet> options = new LinkedList<AssertionSet>();
   384         if (normalizedContentOptions.isEmpty()) {
   385             // we do not have any options to combine => returning this assertion
   386             options.add(AssertionSet.createAssertionSet(normalizedContentBase));
   387         } else {
   388             // we have some options to combine => creating assertion options based on content combinations
   389             final Collection<Collection<PolicyAssertion>> contentCombinations = PolicyUtils.Collections.combine(normalizedContentBase, normalizedContentOptions, true);
   390             for (Collection<PolicyAssertion> contentOption : contentCombinations) {
   391                 options.add(AssertionSet.createAssertionSet(contentOption));
   392             }
   393         }
   394         return options;
   395     }
   397     private List<PolicyAssertion> normalizeRawAssertion(final RawAssertion assertion) throws AssertionCreationException, PolicyException {
   398         List<PolicyAssertion> parameters;
   399         if (assertion.parameters.isEmpty()) {
   400             parameters = null;
   401         } else {
   402             parameters = new ArrayList<PolicyAssertion>(assertion.parameters.size());
   403             for (ModelNode parameterNode : assertion.parameters) {
   404                 parameters.add(createPolicyAssertionParameter(parameterNode));
   405             }
   406         }
   408         final List<AssertionSet> nestedAlternatives = new LinkedList<AssertionSet>();
   409         if (assertion.nestedAlternatives != null && !assertion.nestedAlternatives.isEmpty()) {
   410             final Queue<RawAlternative> nestedAlternativeQueue = new LinkedList<RawAlternative>(assertion.nestedAlternatives);
   411             RawAlternative rawAlternative;
   412             while((rawAlternative = nestedAlternativeQueue.poll()) != null) {
   413                 nestedAlternatives.addAll(normalizeRawAlternative(rawAlternative));
   414             }
   415             // if there is only a single result, we can add it direclty to the content base collection
   416             // more elements in the result indicate that we will have to create combinations
   417         }
   419         final List<PolicyAssertion> assertionOptions = new LinkedList<PolicyAssertion>();
   420         final boolean nestedAlternativesAvailable = !nestedAlternatives.isEmpty();
   421         if (nestedAlternativesAvailable) {
   422             for (AssertionSet nestedAlternative : nestedAlternatives) {
   423                 assertionOptions.add(createPolicyAssertion(assertion.originalNode.getNodeData(), parameters, nestedAlternative));
   424             }
   425         } else {
   426             assertionOptions.add(createPolicyAssertion(assertion.originalNode.getNodeData(), parameters, null));
   427         }
   428         return assertionOptions;
   429     }
   431     private PolicyAssertion createPolicyAssertionParameter(final ModelNode parameterNode) throws AssertionCreationException, PolicyException {
   432         if (parameterNode.getType() != ModelNode.Type.ASSERTION_PARAMETER_NODE) {
   433             throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0065_INCONSISTENCY_IN_POLICY_SOURCE_MODEL(parameterNode.getType())));
   434         }
   436         List<PolicyAssertion> childParameters = null;
   437         if (parameterNode.hasChildren()) {
   438             childParameters = new ArrayList<PolicyAssertion>(parameterNode.childrenSize());
   439             for (ModelNode childParameterNode : parameterNode) {
   440                 childParameters.add(createPolicyAssertionParameter(childParameterNode));
   441             }
   442         }
   444         return createPolicyAssertion(parameterNode.getNodeData(), childParameters, null /* parameters do not have any nested alternatives */);
   445     }
   447     private PolicyAssertion createPolicyAssertion(final AssertionData data, final Collection<PolicyAssertion> assertionParameters, final AssertionSet nestedAlternative) throws AssertionCreationException {
   448         final String assertionNamespace = data.getName().getNamespaceURI();
   449         final PolicyAssertionCreator domainSpecificPAC = assertionCreators.get(assertionNamespace);
   452         if (domainSpecificPAC == null) {
   453             return defaultCreator.createAssertion(data, assertionParameters, nestedAlternative, null);
   454         } else {
   455             return domainSpecificPAC.createAssertion(data, assertionParameters, nestedAlternative, defaultCreator);
   456         }
   457     }
   459 }

mercurial