/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.tuscany.sca.policy.xml; import static javax.xml.stream.XMLStreamConstants.END_ELEMENT; import static javax.xml.stream.XMLStreamConstants.START_ELEMENT; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.StringTokenizer; import javax.xml.namespace.QName; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.stream.XMLStreamWriter; import org.apache.tuscany.sca.contribution.processor.BaseStAXArtifactProcessor; import org.apache.tuscany.sca.contribution.processor.ContributionReadException; import org.apache.tuscany.sca.contribution.processor.ContributionResolveException; import org.apache.tuscany.sca.contribution.processor.ContributionWriteException; import org.apache.tuscany.sca.contribution.processor.ProcessorContext; import org.apache.tuscany.sca.contribution.processor.StAXArtifactProcessor; import org.apache.tuscany.sca.contribution.resolver.ModelResolver; import org.apache.tuscany.sca.core.FactoryExtensionPoint; import org.apache.tuscany.sca.monitor.Monitor; import org.apache.tuscany.sca.monitor.Problem; import org.apache.tuscany.sca.monitor.Problem.Severity; import org.apache.tuscany.sca.policy.ExtensionType; import org.apache.tuscany.sca.policy.Intent; import org.apache.tuscany.sca.policy.PolicyFactory; import org.apache.tuscany.sca.policy.Intent.Type; /** * Processor for handling XML models of PolicyIntent definitions * * @version $Rev$ $Date$ */ public class IntentProcessor extends BaseStAXArtifactProcessor implements StAXArtifactProcessor<Intent>, PolicyConstants { private PolicyFactory policyFactory; public IntentProcessor(FactoryExtensionPoint modelFactories) { this.policyFactory = modelFactories.getFactory(PolicyFactory.class); } public IntentProcessor(PolicyFactory policyFactory) { this.policyFactory = policyFactory; } /** * Report a error. * * @param problems * @param message * @param model */ private void error(Monitor monitor, String message, Object model, Object... messageParameters) { if (monitor != null) { Problem problem = monitor.createProblem(this.getClass().getName(), Messages.RESOURCE_BUNDLE, Severity.ERROR, model, message, messageParameters); monitor.problem(problem); } } private void warn(Monitor monitor, String message, Object model, Object... messageParameters) { if (monitor != null) { Problem problem = monitor.createProblem(this.getClass().getName(), Messages.RESOURCE_BUNDLE, Severity.WARNING, model, message, messageParameters); monitor.problem(problem); } } public Intent read(XMLStreamReader reader, ProcessorContext context) throws ContributionReadException, XMLStreamException { Intent intent = null; String intentLocalName = reader.getAttributeValue(null, NAME); if (intentLocalName == null) { error(context.getMonitor(), "IntentNameMissing", reader); return null; } String intentType = reader.getAttributeValue(null, INTENT_TYPE); if (intentType == null) { intentType = Intent.Type.interaction.name(); } intent = policyFactory.createIntent(); // [rfeng] the target namespace is not available, set the local part for now // This will be changed in the definitions processor intent.setName(new QName(intentLocalName)); intent.setType(Type.valueOf(intentType)); readRequiredIntents(intent, reader, context); readExcludedIntents(intent, reader); readConstrainedTypes(intent, reader); String mutuallyExclusiveString = reader.getAttributeValue(null, MUTUALLY_EXCLUSIVE); if (mutuallyExclusiveString != null && mutuallyExclusiveString.equals("true")){ intent.setMutuallyExclusive(true); } else { intent.setMutuallyExclusive(false); } Intent current = intent; int event = reader.getEventType(); QName name = null; while (reader.hasNext()) { event = reader.getEventType(); switch (event) { case START_ELEMENT: { name = reader.getName(); if (DESCRIPTION_QNAME.equals(name)) { String text = reader.getElementText(); if (text != null) { text = text.trim(); } current.setDescription(text); } else if (INTENT_QUALIFIER_QNAME.equals(name)) { String qualifierName = reader.getAttributeValue(null, NAME); String defaultQ = reader.getAttributeValue(null, DEFAULT); boolean isDefault = defaultQ == null ? false : Boolean.parseBoolean(defaultQ); String qualifiedIntentName = intentLocalName + QUALIFIER + qualifierName; Intent qualified = policyFactory.createIntent(); qualified.setUnresolved(false); qualified.setType(intent.getType()); qualified.setName(new QName(qualifiedIntentName)); if (isDefault) { if (intent.getDefaultQualifiedIntent() == null){ intent.setDefaultQualifiedIntent(qualified); } else { Monitor.error(context.getMonitor(), this, Messages.RESOURCE_BUNDLE, "MultipleDefaultQualifiers", intent.getName().toString()); } } // check that the qualifier is unique if ( !intent.getQualifiedIntents().contains(qualified)){ intent.getQualifiedIntents().add(qualified); } else { Monitor.error(context.getMonitor(), this, Messages.RESOURCE_BUNDLE, "QualifierIsNotUnique", intent.getName().toString(), qualifierName); } qualified.setQualifiableIntent(intent); current = qualified; } break; } case END_ELEMENT: { name = reader.getName(); if (INTENT_QUALIFIER_QNAME.equals(name)) { current = intent; } break; } } if (event == END_ELEMENT && POLICY_INTENT_QNAME.equals(reader.getName())) { break; } //Read the next element if (reader.hasNext()) { reader.next(); } } // REVIEW: [rfeng] What's going to happen if there is only one qualified intent if (intent.getQualifiedIntents().size() == 1) { intent.setDefaultQualifiedIntent(intent.getQualifiedIntents().get(0)); } // set all qualified intents as excluding one another if the qualifiable // intent is set to be mutually exclusive if (intent.isMutuallyExclusive()){ for (Intent qualifiedIntent : intent.getQualifiedIntents()){ for (Intent excludedIntent : intent.getQualifiedIntents()){ if (qualifiedIntent != excludedIntent){ qualifiedIntent.getExcludedIntents().add(excludedIntent); } } } } return intent; } public void write(Intent intent, XMLStreamWriter writer, ProcessorContext context) throws ContributionWriteException, XMLStreamException { // Write an <sca:intent> writer.writeStartElement(PolicyConstants.SCA11_NS, INTENT); writer.writeNamespace(intent.getName().getPrefix(), intent.getName().getNamespaceURI()); writer.writeAttribute(PolicyConstants.NAME, intent.getName().getPrefix() + COLON + intent.getName().getLocalPart()); if (intent.getRequiredIntents() != null && intent.getRequiredIntents().size() > 0) { StringBuffer sb = new StringBuffer(); for (Intent requiredIntents : intent.getRequiredIntents()) { sb.append(requiredIntents.getName()); sb.append(" "); } writer.writeAttribute(PolicyConstants.REQUIRES, sb.toString()); } if (intent.getExcludedIntents() != null && intent.getExcludedIntents().size() > 0) { StringBuffer sb = new StringBuffer(); for (Intent excludedIntents : intent.getExcludedIntents()) { sb.append(excludedIntents.getName()); sb.append(" "); } writer.writeAttribute(PolicyConstants.EXCLUDES, sb.toString()); } if (intent.getConstrainedTypes() != null && intent.getConstrainedTypes().size() > 0) { StringBuffer sb = new StringBuffer(); for (ExtensionType contrainedArtifact : intent.getConstrainedTypes()) { sb.append(contrainedArtifact.getType().getPrefix()); sb.append(':').append(contrainedArtifact.getType().getLocalPart()); sb.append(" "); } writer.writeAttribute(CONSTRAINS, sb.toString()); } if (intent.getDescription() != null && intent.getDescription().length() > 0) { writer.writeStartElement(PolicyConstants.SCA11_NS, DESCRIPTION); writer.writeCData(intent.getDescription()); writer.writeEndElement(); } writer.writeEndElement(); } private void resolveContrainedTypes(Intent intent, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { Collection<ExtensionType> resolvedTypes = new HashSet<ExtensionType>(); for (ExtensionType extensionType : intent.getConstrainedTypes()) { if (ExtensionType.BINDING_BASE.equals(extensionType.getType()) || ExtensionType.IMPLEMENTATION_BASE .equals(extensionType.getType())) { // HACK: Mark sca:binding and sca:implementation as resolved extensionType.setUnresolved(false); resolvedTypes.add(extensionType); } else { ExtensionType resolved = resolver.resolveModel(ExtensionType.class, extensionType, context); if (!resolved.isUnresolved() || resolved != extensionType) { resolvedTypes.add(resolved); } else { warn(context.getMonitor(), "ConstrainedTypeNotFound", intent, extensionType, intent); } } } intent.getConstrainedTypes().clear(); intent.getConstrainedTypes().addAll(resolvedTypes); } private void resolveProfileIntent(Intent intent, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { Monitor monitor = context.getMonitor(); // FIXME: Need to check for cyclic references first i.e an A requiring B // and then B requiring A... if (intent != null && !intent.getRequiredIntents().isEmpty()) { // resolve all required intents List<Intent> requiredIntents = new ArrayList<Intent>(); for (Intent required : intent.getRequiredIntents()) { if (required.isUnresolved()) { Intent resolved = resolver.resolveModel(Intent.class, required, context); // At this point, when the required intent is not resolved, it does not mean // its undeclared, chances are that their dependency are not resolved yet. // Lets try to resolve them first. if (resolved.isUnresolved()) { if (((resolved).getRequiredIntents()).contains(intent)) { error(monitor, "CyclicReferenceFound", resolver, required, intent); return; } } if (!resolved.isUnresolved() || resolved != required) { requiredIntents.add(resolved); } else { error(monitor, "RequiredIntentNotFound", resolver, required, intent); return; //throw new ContributionResolveException("Required Intent - " + requiredIntent //+ " not found for Intent " + policyIntent); } } else { requiredIntents.add(required); } } intent.getRequiredIntents().clear(); intent.getRequiredIntents().addAll(requiredIntents); } } private void resolveQualifiedIntent(Intent qualifed, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { if (qualifed != null) { //resolve the qualifiable intent Intent parent = qualifed.getQualifiableIntent(); if (parent == null) { return; } if (parent.isUnresolved()) { Intent resolved = resolver.resolveModel(Intent.class, parent, context); // At this point, when the qualifiable intent is not resolved, it does not mean // its undeclared, chances are that their dependency are not resolved yet. // Lets try to resolve them first. if (!resolved.isUnresolved() || resolved != qualifed) { qualifed.setQualifiableIntent(resolved); } else { error(context.getMonitor(), "QualifiableIntentNotFound", resolver, parent, qualifed); //throw new ContributionResolveException("Qualifiable Intent - " + qualifiableIntent //+ " not found for Intent " + policyIntent); } } } } public void resolve(Intent intent, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { if (intent != null && intent.isUnresolved()) { resolveProfileIntent(intent, resolver, context); resolveExcludedIntents(intent, resolver, context); resolveQualifiedIntent(intent, resolver, context); resolveContrainedTypes(intent, resolver, context); intent.setUnresolved(false); } } public QName getArtifactType() { return POLICY_INTENT_QNAME; } private void readConstrainedTypes(Intent policyIntent, XMLStreamReader reader) throws ContributionReadException { String value = reader.getAttributeValue(null, CONSTRAINS); if (value != null) { List<ExtensionType> constrainedTypes = policyIntent.getConstrainedTypes(); for (StringTokenizer tokens = new StringTokenizer(value); tokens.hasMoreTokens();) { QName qname = getQNameValue(reader, tokens.nextToken()); ExtensionType extensionType = policyFactory.createExtensionType(); extensionType.setType(qname); constrainedTypes.add(extensionType); } } } private void readRequiredIntents(Intent intent, XMLStreamReader reader, ProcessorContext context) { String value = reader.getAttributeValue(null, REQUIRES); if (value != null) { List<Intent> requiredIntents = intent.getRequiredIntents(); for (StringTokenizer tokens = new StringTokenizer(value); tokens.hasMoreTokens();) { QName qname = getQNameValue(reader, tokens.nextToken()); Intent required = policyFactory.createIntent(); required.setName(qname); required.setUnresolved(true); requiredIntents.add(required); } // Check that a profile intent does not have "." in its name if (requiredIntents.size() > 0) { if (intent.getName().getLocalPart().contains(".")){ Monitor.error(context.getMonitor(), this, Messages.RESOURCE_BUNDLE, "ProfileIntentNameWithPeriod", intent.getName().toString()); } } } } private void readExcludedIntents(Intent intent, XMLStreamReader reader) { String value = reader.getAttributeValue(null, EXCLUDES); if (value != null) { List<Intent> excludedIntents = intent.getExcludedIntents(); for (StringTokenizer tokens = new StringTokenizer(value); tokens.hasMoreTokens();) { QName qname = getQNameValue(reader, tokens.nextToken()); Intent excluded = policyFactory.createIntent(); excluded.setName(qname); excluded.setUnresolved(true); excludedIntents.add(excluded); } } } private void resolveExcludedIntents(Intent policyIntent, ModelResolver resolver, ProcessorContext context) throws ContributionResolveException { if (policyIntent != null) { // resolve all excluded intents List<Intent> excludedIntents = new ArrayList<Intent>(); for (Intent excludedIntent : policyIntent.getExcludedIntents()) { if (excludedIntent.isUnresolved()) { Intent resolvedExcludedIntent = resolver.resolveModel(Intent.class, excludedIntent, context); if (!resolvedExcludedIntent.isUnresolved() || resolvedExcludedIntent != excludedIntent) { excludedIntents.add(resolvedExcludedIntent); } else { error(context.getMonitor(), "ExcludedIntentNotFound", resolver, excludedIntent, policyIntent); return; //throw new ContributionResolveException("Excluded Intent " + excludedIntent //+ " not found for intent " + policyIntent); } } else { excludedIntents.add(excludedIntent); } } policyIntent.getExcludedIntents().clear(); policyIntent.getExcludedIntents().addAll(excludedIntents); } } public Class<Intent> getModelType() { return Intent.class; } }