All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.xml.ws.policy.sourcemodel.PolicyModelTranslator Maven / Gradle / Ivy

There is a newer version: 4.0.4
Show newest version
/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Distribution License v. 1.0, which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

package com.sun.xml.ws.policy.sourcemodel;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

import com.sun.xml.ws.policy.AssertionSet;
import com.sun.xml.ws.policy.Policy;
import com.sun.xml.ws.policy.PolicyAssertion;
import com.sun.xml.ws.policy.PolicyException;
import com.sun.xml.ws.policy.privateutil.LocalizationMessages;
import com.sun.xml.ws.policy.privateutil.PolicyLogger;
import com.sun.xml.ws.policy.privateutil.PolicyUtils;
import com.sun.xml.ws.policy.spi.AssertionCreationException;
import com.sun.xml.ws.policy.spi.PolicyAssertionCreator;
import java.util.ServiceLoader;

/**
 * This class provides a method for translating a {@link PolicySourceModel} structure to a normalized {@link Policy} expression.
 * The resulting Policy is disconnected from its model, thus any additional changes in the model will have no effect on the Policy
 * expression.
 *
 * @author Marek Potociar
 * @author Fabian Ritzmann
 */
public class PolicyModelTranslator {
    
    private static final class ContentDecomposition {
        final List> exactlyOneContents = new LinkedList>();
        final List assertions = new LinkedList();
        
        void reset() {
            exactlyOneContents.clear();
            assertions.clear();
        }
    }
    
    private static final class RawAssertion {
        ModelNode originalNode; // used to initialize nestedPolicy and nestedAssertions in the constructor of RawAlternative
        Collection nestedAlternatives = null;
        final Collection parameters;
        
        RawAssertion(ModelNode originalNode, Collection parameters) {
            this.parameters = parameters;
            this.originalNode = originalNode;
        }
    }
    
    private static final class RawAlternative {
        private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyModelTranslator.RawAlternative.class);
        
        final List allNestedPolicies = new LinkedList(); // used to track the nested policies which need to be normalized
        final Collection nestedAssertions;
        
        RawAlternative(Collection assertionNodes) throws PolicyException {
            this.nestedAssertions = new LinkedList();
            for (ModelNode node : assertionNodes) {
                RawAssertion assertion = new RawAssertion(node, new LinkedList());
                nestedAssertions.add(assertion);
                
                for (ModelNode assertionNodeChild : assertion.originalNode.getChildren()) {
                    switch (assertionNodeChild.getType()) {
                        case ASSERTION_PARAMETER_NODE:
                            assertion.parameters.add(assertionNodeChild);
                            break;
                        case POLICY:
                        case POLICY_REFERENCE:
                            if (assertion.nestedAlternatives == null) {
                                assertion.nestedAlternatives = new LinkedList();
                                RawPolicy nestedPolicy;
                                if (assertionNodeChild.getType() == ModelNode.Type.POLICY) {
                                    nestedPolicy = new RawPolicy(assertionNodeChild, assertion.nestedAlternatives);
                                } else {
                                    nestedPolicy = new RawPolicy(getReferencedModelRootNode(assertionNodeChild), assertion.nestedAlternatives);
                                }
                                this.allNestedPolicies.add(nestedPolicy);
                            } else {
                                throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0006_UNEXPECTED_MULTIPLE_POLICY_NODES()));
                            }
                            break;
                        default:
                            throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0008_UNEXPECTED_CHILD_MODEL_TYPE(assertionNodeChild.getType())));
                    }
                }
            }
        }
        
    }
    
    private static final class RawPolicy {
        final Collection originalContent;
        final Collection alternatives;
        
        RawPolicy(ModelNode policyNode, Collection alternatives) {
            originalContent = policyNode.getChildren();
            this.alternatives = alternatives;
        }
    }
    
    private static final PolicyLogger LOGGER = PolicyLogger.getLogger(PolicyModelTranslator.class);
    
    private static final PolicyAssertionCreator defaultCreator = new DefaultPolicyAssertionCreator();

    private final Map assertionCreators;
    

    private PolicyModelTranslator() throws PolicyException {
        this(null);
    }

    protected PolicyModelTranslator(final Collection creators) throws PolicyException {
        LOGGER.entering(creators);

        final Collection allCreators = new LinkedList();
        for (PolicyAssertionCreator creator : ServiceLoader.load(PolicyAssertionCreator.class)) {
            allCreators.add(creator);
        }
        if (creators != null) {
            for (PolicyAssertionCreator creator : creators) {
                allCreators.add(creator);
            }
        }

        final Map pacMap = new HashMap();
        for (PolicyAssertionCreator creator : allCreators) {
            final String[] supportedURIs = creator.getSupportedDomainNamespaceURIs();
            final String creatorClassName = creator.getClass().getName();

            if (supportedURIs == null || supportedURIs.length == 0) {
                LOGGER.warning(LocalizationMessages.WSP_0077_ASSERTION_CREATOR_DOES_NOT_SUPPORT_ANY_URI(creatorClassName));
                continue;
            }

            for (String supportedURI : supportedURIs) {
                LOGGER.config(LocalizationMessages.WSP_0078_ASSERTION_CREATOR_DISCOVERED(creatorClassName, supportedURI));
                if (supportedURI == null || supportedURI.length() == 0) {
                    throw LOGGER.logSevereException(new PolicyException(
                            LocalizationMessages.WSP_0070_ERROR_REGISTERING_ASSERTION_CREATOR(creatorClassName)));
                }

                final PolicyAssertionCreator oldCreator = pacMap.put(supportedURI, creator);
                if (oldCreator != null) {
                    throw LOGGER.logSevereException(new PolicyException(
                            LocalizationMessages.WSP_0071_ERROR_MULTIPLE_ASSERTION_CREATORS_FOR_NAMESPACE(
                            supportedURI, oldCreator.getClass().getName(), creator.getClass().getName())));
                }
            }
        }

        this.assertionCreators = Collections.unmodifiableMap(pacMap);
        LOGGER.exiting();
    }

    /**
     * Method returns thread-safe policy model translator instance.
     *
     * This method is only intended to be used by code that has no dependencies on
     * JAX-WS. Otherwise use com.sun.xml.ws.policy.api.ModelTranslator.
     *
     * @return A policy model translator instance.
     * @throws PolicyException If instantiating a PolicyAssertionCreator failed.
     */
    public static PolicyModelTranslator getTranslator() throws PolicyException {
        return new PolicyModelTranslator();
    }
    
    /**
     * The method translates {@link PolicySourceModel} structure into normalized {@link Policy} expression. The resulting Policy
     * is disconnected from its model, thus any additional changes in model will have no effect on the Policy expression.
     *
     * @param model the model to be translated into normalized policy expression. Must not be {@code null}.
     * @return translated policy expression in it's normalized form.
     * @throws PolicyException in case of translation failure
     */
    public Policy translate(final PolicySourceModel model) throws PolicyException {
        LOGGER.entering(model);
        
        if (model == null) {
            throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0043_POLICY_MODEL_TRANSLATION_ERROR_INPUT_PARAM_NULL()));
        }
        
        PolicySourceModel localPolicyModelCopy;
        try {
            localPolicyModelCopy = model.clone();
        } catch (CloneNotSupportedException e) {
            throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0016_UNABLE_TO_CLONE_POLICY_SOURCE_MODEL(), e));
        }
        
        final String policyId = localPolicyModelCopy.getPolicyId();
        final String policyName = localPolicyModelCopy.getPolicyName();
        
        final Collection alternatives = createPolicyAlternatives(localPolicyModelCopy);
        LOGGER.finest(LocalizationMessages.WSP_0052_NUMBER_OF_ALTERNATIVE_COMBINATIONS_CREATED(alternatives.size()));
        
        Policy policy = null;
        if (alternatives.size() == 0) {
            policy = Policy.createNullPolicy(model.getNamespaceVersion(), policyName, policyId);
            LOGGER.finest(LocalizationMessages.WSP_0055_NO_ALTERNATIVE_COMBINATIONS_CREATED());
        } else if (alternatives.size() == 1 && alternatives.iterator().next().isEmpty()) {
            policy = Policy.createEmptyPolicy(model.getNamespaceVersion(), policyName, policyId);
            LOGGER.finest(LocalizationMessages.WSP_0026_SINGLE_EMPTY_ALTERNATIVE_COMBINATION_CREATED());
        } else {
            policy = Policy.createPolicy(model.getNamespaceVersion(), policyName, policyId, alternatives);
            LOGGER.finest(LocalizationMessages.WSP_0057_N_ALTERNATIVE_COMBINATIONS_M_POLICY_ALTERNATIVES_CREATED(alternatives.size(), policy.getNumberOfAssertionSets()));
        }
        
        LOGGER.exiting(policy);
        return policy;
    }
    
    /**
     * Method creates policy alternatives according to provided model. The model structure is modified in the process.
     *
     * @return created policy alternatives resulting from policy source model.
     */
    private Collection createPolicyAlternatives(final PolicySourceModel model) throws PolicyException {
        // creating global method variables
        final ContentDecomposition decomposition = new ContentDecomposition();
        
        // creating processing queue and starting the processing iterations
        final Queue policyQueue = new LinkedList();
        final Queue> contentQueue = new LinkedList>();
        
        final RawPolicy rootPolicy = new RawPolicy(model.getRootNode(), new LinkedList());
        RawPolicy processedPolicy = rootPolicy;
        do {
            Collection processedContent = processedPolicy.originalContent;
            do {
                decompose(processedContent, decomposition);
                if (decomposition.exactlyOneContents.isEmpty()) {
                    final RawAlternative alternative = new RawAlternative(decomposition.assertions);
                    processedPolicy.alternatives.add(alternative);
                    if (!alternative.allNestedPolicies.isEmpty()) {
                        policyQueue.addAll(alternative.allNestedPolicies);
                    }
                } else { // we have a non-empty collection of exactly ones
                    final Collection> combinations = PolicyUtils.Collections.combine(decomposition.assertions, decomposition.exactlyOneContents, false);
                    if (combinations != null && !combinations.isEmpty()) {
                        // processed alternative was split into some new alternatives, which we need to process
                        contentQueue.addAll(combinations);
                    }
                }
            } while ((processedContent = contentQueue.poll()) != null);
        } while ((processedPolicy = policyQueue.poll()) != null);
        
        // normalize nested policies to contain single alternative only
        final Collection assertionSets = new LinkedList();
        for (RawAlternative rootAlternative : rootPolicy.alternatives) {
            final Collection normalizedAlternatives = normalizeRawAlternative(rootAlternative);
            assertionSets.addAll(normalizedAlternatives);
        }
        
        return assertionSets;
    }
    
    /**
     * Decomposes the unprocessed alternative content into two different collections:
     * 
* Content of 'EXACTLY_ONE' child nodes is expanded and placed in one list and * 'ASSERTION' nodes are placed into other list. Direct 'ALL' and 'POLICY' child nodes are 'dissolved' in the process. * * Method reuses precreated ContentDecomposition object, which is reset before reuse. */ private void decompose(final Collection content, final ContentDecomposition decomposition) throws PolicyException { decomposition.reset(); final Queue allContentQueue = new LinkedList(content); ModelNode node; while ((node = allContentQueue.poll()) != null) { // dissolving direct 'POLICY', 'POLICY_REFERENCE' and 'ALL' child nodes switch (node.getType()) { case POLICY : case ALL : allContentQueue.addAll(node.getChildren()); break; case POLICY_REFERENCE : allContentQueue.addAll(getReferencedModelRootNode(node).getChildren()); break; case EXACTLY_ONE : decomposition.exactlyOneContents.add(expandsExactlyOneContent(node.getChildren())); break; case ASSERTION : decomposition.assertions.add(node); break; default : throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0007_UNEXPECTED_MODEL_NODE_TYPE_FOUND(node.getType()))); } } } private static ModelNode getReferencedModelRootNode(final ModelNode policyReferenceNode) throws PolicyException { final PolicySourceModel referencedModel = policyReferenceNode.getReferencedModel(); if (referencedModel == null) { final PolicyReferenceData refData = policyReferenceNode.getPolicyReferenceData(); if (refData == null) { throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0041_POLICY_REFERENCE_NODE_FOUND_WITH_NO_POLICY_REFERENCE_IN_IT())); } else { throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0010_UNEXPANDED_POLICY_REFERENCE_NODE_FOUND_REFERENCING(refData.getReferencedModelUri()))); } } else { return referencedModel.getRootNode(); } } /** * Expands content of 'EXACTLY_ONE' node. Direct 'EXACTLY_ONE' child nodes are dissolved in the process. */ private Collection expandsExactlyOneContent(final Collection content) throws PolicyException { final Collection result = new LinkedList(); final Queue eoContentQueue = new LinkedList(content); ModelNode node; while ((node = eoContentQueue.poll()) != null) { // dissolving direct 'EXACTLY_ONE' child nodes switch (node.getType()) { case POLICY : case ALL : case ASSERTION : result.add(node); break; case POLICY_REFERENCE : result.add(getReferencedModelRootNode(node)); break; case EXACTLY_ONE : eoContentQueue.addAll(node.getChildren()); break; default : throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0001_UNSUPPORTED_MODEL_NODE_TYPE(node.getType()))); } } return result; } private List normalizeRawAlternative(final RawAlternative alternative) throws AssertionCreationException, PolicyException { final List normalizedContentBase = new LinkedList(); final Collection> normalizedContentOptions = new LinkedList>(); if (!alternative.nestedAssertions.isEmpty()) { final Queue nestedAssertionsQueue = new LinkedList(alternative.nestedAssertions); RawAssertion rawAssertion; while((rawAssertion = nestedAssertionsQueue.poll()) != null) { final List normalized = normalizeRawAssertion(rawAssertion); // if there is only a single result, we can add it direclty to the content base collection // more elements in the result indicate that we will have to create combinations if (normalized.size() == 1) { normalizedContentBase.addAll(normalized); } else { normalizedContentOptions.add(normalized); } } } final List options = new LinkedList(); if (normalizedContentOptions.isEmpty()) { // we do not have any options to combine => returning this assertion options.add(AssertionSet.createAssertionSet(normalizedContentBase)); } else { // we have some options to combine => creating assertion options based on content combinations final Collection> contentCombinations = PolicyUtils.Collections.combine(normalizedContentBase, normalizedContentOptions, true); for (Collection contentOption : contentCombinations) { options.add(AssertionSet.createAssertionSet(contentOption)); } } return options; } private List normalizeRawAssertion(final RawAssertion assertion) throws AssertionCreationException, PolicyException { List parameters; if (assertion.parameters.isEmpty()) { parameters = null; } else { parameters = new ArrayList(assertion.parameters.size()); for (ModelNode parameterNode : assertion.parameters) { parameters.add(createPolicyAssertionParameter(parameterNode)); } } final List nestedAlternatives = new LinkedList(); if (assertion.nestedAlternatives != null && !assertion.nestedAlternatives.isEmpty()) { final Queue nestedAlternativeQueue = new LinkedList(assertion.nestedAlternatives); RawAlternative rawAlternative; while((rawAlternative = nestedAlternativeQueue.poll()) != null) { nestedAlternatives.addAll(normalizeRawAlternative(rawAlternative)); } // if there is only a single result, we can add it direclty to the content base collection // more elements in the result indicate that we will have to create combinations } final List assertionOptions = new LinkedList(); final boolean nestedAlternativesAvailable = !nestedAlternatives.isEmpty(); if (nestedAlternativesAvailable) { for (AssertionSet nestedAlternative : nestedAlternatives) { assertionOptions.add(createPolicyAssertion(assertion.originalNode.getNodeData(), parameters, nestedAlternative)); } } else { assertionOptions.add(createPolicyAssertion(assertion.originalNode.getNodeData(), parameters, null)); } return assertionOptions; } private PolicyAssertion createPolicyAssertionParameter(final ModelNode parameterNode) throws AssertionCreationException, PolicyException { if (parameterNode.getType() != ModelNode.Type.ASSERTION_PARAMETER_NODE) { throw LOGGER.logSevereException(new PolicyException(LocalizationMessages.WSP_0065_INCONSISTENCY_IN_POLICY_SOURCE_MODEL(parameterNode.getType()))); } List childParameters = null; if (parameterNode.hasChildren()) { childParameters = new ArrayList(parameterNode.childrenSize()); for (ModelNode childParameterNode : parameterNode) { childParameters.add(createPolicyAssertionParameter(childParameterNode)); } } return createPolicyAssertion(parameterNode.getNodeData(), childParameters, null /* parameters do not have any nested alternatives */); } private PolicyAssertion createPolicyAssertion(final AssertionData data, final Collection assertionParameters, final AssertionSet nestedAlternative) throws AssertionCreationException { final String assertionNamespace = data.getName().getNamespaceURI(); final PolicyAssertionCreator domainSpecificPAC = assertionCreators.get(assertionNamespace); if (domainSpecificPAC == null) { return defaultCreator.createAssertion(data, assertionParameters, nestedAlternative, null); } else { return domainSpecificPAC.createAssertion(data, assertionParameters, nestedAlternative, defaultCreator); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy