blob: 68475a208ba20377f0fca85591ba691c62f171ec [file] [log] [blame]
/*
* 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 static org.apache.tuscany.sca.policy.xml.PolicyConstants.SCA11_NS;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import org.apache.tuscany.sca.common.xml.xpath.XPathHelper;
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.ExtensionPointRegistry;
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.Intent;
import org.apache.tuscany.sca.policy.IntentMap;
import org.apache.tuscany.sca.policy.PolicyExpression;
import org.apache.tuscany.sca.policy.PolicyFactory;
import org.apache.tuscany.sca.policy.PolicySet;
import org.apache.tuscany.sca.policy.Qualifier;
/**
* Processor for handling XML models of PolicySet definitions
*
* @version $Rev$ $Date$
*/
public class PolicySetProcessor extends BaseStAXArtifactProcessor implements StAXArtifactProcessor<PolicySet>,
PolicyConstants {
private PolicyFactory policyFactory;
private StAXArtifactProcessor<Object> extensionProcessor;
private XPathHelper xpathHelper;
// private XPathFactory xpathFactory;
public PolicySetProcessor(ExtensionPointRegistry registry, StAXArtifactProcessor<Object> extensionProcessor) {
FactoryExtensionPoint modelFactories = registry.getExtensionPoint(FactoryExtensionPoint.class);
this.policyFactory = modelFactories.getFactory(PolicyFactory.class);
this.extensionProcessor = extensionProcessor;
this.xpathHelper = XPathHelper.getInstance(registry);
}
/**
* Report a exception.
*
* @param problems
* @param message
* @param model
*/
private void error(Monitor monitor, String message, Object model, Exception ex) {
if (monitor != null) {
Problem problem =
monitor.createProblem(this.getClass().getName(),
Messages.RESOURCE_BUNDLE,
Severity.ERROR,
model,
message,
ex);
monitor.problem(problem);
}
}
/**
* 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,
(Object[])messageParameters);
monitor.problem(problem);
}
}
public PolicySet read(XMLStreamReader reader, ProcessorContext context) throws ContributionReadException,
XMLStreamException {
PolicySet policySet = null;
Monitor monitor = context.getMonitor();
String policySetName = reader.getAttributeValue(null, NAME);
String appliesTo = reader.getAttributeValue(null, APPLIES_TO);
if (policySetName == null || appliesTo == null) {
if (policySetName == null)
error(monitor, "PolicySetNameMissing", reader);
if (appliesTo == null)
error(monitor, "PolicySetAppliesToMissing", reader);
return policySet;
}
policySet = policyFactory.createPolicySet();
policySet.setName(new QName(policySetName));
//TODO: with 1.0 version of specs the applies to xpath is given related to the immediate
//parent whereas the runtime evaluates the xpath aginst the composite element. What the runtime
//is doing is what the future version of the specs could be tending towards. When that happens
//this 'if' must be deleted
if (appliesTo != null && !appliesTo.startsWith("/")) {
appliesTo = "//" + appliesTo;
}
policySet.setAppliesTo(appliesTo);
if (appliesTo != null) {
try {
XPath path = xpathHelper.newXPath();
NamespaceContext nsContext = xpathHelper.getNamespaceContext(appliesTo, reader.getNamespaceContext());
// path.setXPathFunctionResolver(new PolicyXPathFunctionResolver(context));
XPathExpression expression = xpathHelper.compile(path, nsContext, appliesTo);
policySet.setAppliesToXPathExpression(expression);
} catch (XPathExpressionException e) {
ContributionReadException ce = new ContributionReadException(e);
error(monitor, "ContributionReadException", policySet, ce);
//throw ce;
}
}
String attachTo = reader.getAttributeValue(null, ATTACH_TO);
if (attachTo != null) {
try {
XPath path = xpathHelper.newXPath();
NamespaceContext nsContext = xpathHelper.getNamespaceContext(attachTo, reader.getNamespaceContext());
path.setXPathFunctionResolver(new PolicyXPathFunctionResolver(nsContext));
attachTo = PolicyXPathFunction.normalize(attachTo,getSCAPrefix(nsContext));
XPathExpression expression = xpathHelper.compile(path, nsContext, attachTo);
policySet.setAttachTo(attachTo);
policySet.setAttachToXPathExpression(expression);
} catch (XPathExpressionException e) {
ContributionReadException ce = new ContributionReadException(e);
error(monitor, "ContributionReadException", policySet, ce);
//throw ce;
}
}
readProvidedIntents(policySet, reader);
int event = reader.getEventType();
QName name = null;
reader.next();
while (reader.hasNext()) {
event = reader.getEventType();
switch (event) {
case START_ELEMENT: {
name = reader.getName();
if (POLICY_INTENT_MAP_QNAME.equals(name)) {
Intent mappedIntent = policyFactory.createIntent();
String provides = reader.getAttributeValue(null, PROVIDES);
if (provides != null) {
mappedIntent.setName(getQName(reader, PROVIDES));
if (policySet.getProvidedIntents().contains(mappedIntent)) {
readIntentMap(reader, policySet, mappedIntent, context);
} else {
error(monitor, "IntentNotSpecified", policySet, policySetName);
}
} else {
error(monitor, "IntentMapProvidesMissing", reader, policySetName);
}
} else if (POLICY_SET_REFERENCE_QNAME.equals(name)) {
PolicySet referredPolicySet = policyFactory.createPolicySet();
String referencename = reader.getAttributeValue(null, NAME);
if (referencename != null) {
referredPolicySet.setName(getQName(reader, NAME));
policySet.getReferencedPolicySets().add(referredPolicySet);
} else {
error(monitor, "PolicySetReferenceNameMissing", reader, policySetName);
}
} /*else if ( WS_POLICY_QNAME.equals(name) ) {
OMElement policyElement = loadElement(reader);
org.apache.neethi.Policy wsPolicy = PolicyEngine.getPolicy(policyElement);
policySet.getPolicies().add(wsPolicy);
} */else {
Object extension = extensionProcessor.read(reader, context);
if (extension != null) {
PolicyExpression exp = policyFactory.createPolicyExpression();
exp.setName(name);
exp.setPolicy(extension);
// check that all the policies in the policy set are
// expressed in the same language. Compare against the
// first expression we added
if ((policySet.getPolicies().size() > 0) && (!policySet.getPolicies().get(0).getName()
.equals(name))) {
error(monitor, "PolicyLanguageMissmatch", reader, policySet.getName(), policySet
.getPolicies().get(0).getName(), name);
} else {
policySet.getPolicies().add(exp);
}
}
}
break;
}
}
if (event == END_ELEMENT) {
if (POLICY_SET_QNAME.equals(reader.getName())) {
break;
}
}
//Read the next element
if (reader.hasNext()) {
reader.next();
}
}
return policySet;
}
private String getSCAPrefix(NamespaceContext nsContext) {
Iterator<String> iter = nsContext.getPrefixes(SCA11_NS);
while (iter.hasNext()) {
String prefix = iter.next();
if (!prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return prefix;
}
}
return "__sca";
}
public void readIntentMap(XMLStreamReader reader, PolicySet policySet, Intent mappedIntent, ProcessorContext context)
throws ContributionReadException {
Monitor monitor = context.getMonitor();
QName name = reader.getName();
if (POLICY_INTENT_MAP_QNAME.equals(name)) {
IntentMap intentMap = policyFactory.createIntentMap();
QName intentName = getQName(reader, INTENT_MAP);
intentMap.setProvidedIntent(mappedIntent);
if (!policySet.getIntentMaps().contains(intentMap)) {
policySet.getIntentMaps().add(intentMap);
} else {
Monitor.error(context.getMonitor(), this, Messages.RESOURCE_BUNDLE, "IntentMapIsNotUnique", policySet
.getName().toString(), mappedIntent.getName().getLocalPart());
}
String qualifierName = null;
String qualfiedIntentName = null;
Intent qualifiedIntent = null;
Qualifier qualifier = null;
int event = reader.getEventType();
try {
reader.next();
while (reader.hasNext()) {
event = reader.getEventType();
switch (event) {
case START_ELEMENT: {
name = reader.getName();
if (POLICY_INTENT_MAP_QUALIFIER_QNAME.equals(name)) {
qualifierName = getString(reader, NAME);
if (qualifierName != null) {
qualfiedIntentName =
mappedIntent.getName().getLocalPart() + QUALIFIER + qualifierName;
qualifiedIntent = policyFactory.createIntent();
qualifiedIntent.setName(new QName(mappedIntent.getName().getNamespaceURI(),
qualfiedIntentName));
qualifier = policyFactory.createQualifier();
qualifier.setIntent(qualifiedIntent);
intentMap.getQualifiers().add(qualifier);
} else {
error(monitor, "QualifierNameMissing", reader, policySet.getName());
}
} else if (POLICY_INTENT_MAP_QNAME.equals(name)) {
QName providedIntent = getQName(reader, PROVIDES);
if (qualifierName.equals(providedIntent.getLocalPart())) {
readIntentMap(reader, policySet, qualifiedIntent, context);
} else {
error(monitor,
"IntentMapDoesNotMatch",
providedIntent,
providedIntent,
qualifierName,
policySet);
//throw new ContributionReadException("Intent provided by IntentMap " +
//providedIntent + " does not match parent qualifier " + qualifierName +
//" in policyset - " + policySet);
}
} else {
Object extension = extensionProcessor.read(reader, context);
if (extension != null && qualifier != null) {
PolicyExpression exp = policyFactory.createPolicyExpression();
exp.setName(name);
exp.setPolicy(extension);
qualifier.getPolicies().add(exp);
}
}
break;
}
}
if (event == END_ELEMENT && POLICY_INTENT_MAP_QNAME.equals(reader.getName())) {
break;
}
//Read the next element
if (reader.hasNext()) {
reader.next();
}
}
} catch (XMLStreamException e) {
ContributionReadException ce = new ContributionReadException(e);
error(monitor, "ContributionReadException", reader, ce);
throw ce;
}
}
}
public void write(PolicySet policySet, XMLStreamWriter writer, ProcessorContext context)
throws ContributionWriteException, XMLStreamException {
// Write an <sca:policySet>
writer.writeStartElement(SCA11_NS, POLICY_SET);
writer.writeNamespace(policySet.getName().getPrefix(), policySet.getName().getNamespaceURI());
writer.writeAttribute(NAME, policySet.getName().getPrefix() + COLON + policySet.getName().getLocalPart());
writer.writeAttribute(APPLIES_TO, policySet.getAppliesTo());
writer.writeAttribute(ATTACH_TO, policySet.getAttachTo());
writeProvidedIntents(policySet, writer);
writer.writeEndElement();
}
private void readProvidedIntents(PolicySet policySet, XMLStreamReader reader) {
String value = reader.getAttributeValue(null, PROVIDES);
if (value != null) {
List<Intent> providedIntents = policySet.getProvidedIntents();
for (StringTokenizer tokens = new StringTokenizer(value); tokens.hasMoreTokens();) {
QName qname = getQNameValue(reader, tokens.nextToken());
Intent intent = policyFactory.createIntent();
intent.setName(qname);
providedIntents.add(intent);
}
}
}
private void writeProvidedIntents(PolicySet policySet, XMLStreamWriter writer) throws XMLStreamException {
if (!policySet.getProvidedIntents().isEmpty()) {
StringBuffer sb = new StringBuffer();
for (Intent providedIntents : policySet.getProvidedIntents()) {
sb.append(getQualifiedName(providedIntents.getName(), writer));
sb.append(" ");
}
// Remove the last space
sb.deleteCharAt(sb.length() - 1);
writer.writeAttribute(PolicyConstants.PROVIDES, sb.toString());
}
}
private String getQualifiedName(QName name, XMLStreamWriter writer) throws XMLStreamException {
String local = name.getLocalPart();
String prefix = writer.getPrefix(name.getNamespaceURI());
if (prefix != null && prefix.length() > 0) {
return prefix + ':' + local;
} else {
return local;
}
}
private void resolvePolicies(PolicySet policySet, ModelResolver resolver, ProcessorContext context)
throws ContributionResolveException {
boolean unresolved = false;
if (policySet != null) {
for (Object o : policySet.getPolicies()) {
extensionProcessor.resolve(o, resolver, context);
/*if ( o instanceof Policy && ((Policy)o).isUnresolved() ) {
unresolved = true;
}*/
}
policySet.setUnresolved(unresolved);
}
}
public QName getArtifactType() {
return POLICY_SET_QNAME;
}
public Class<PolicySet> getModelType() {
return PolicySet.class;
}
private void resolveProvidedIntents(PolicySet policySet, ModelResolver resolver, ProcessorContext context)
throws ContributionResolveException {
if (policySet != null) {
//resolve all provided intents
List<Intent> providedIntents = new ArrayList<Intent>();
for (Intent providedIntent : policySet.getProvidedIntents()) {
if (providedIntent.isUnresolved()) {
Intent resolved = resolver.resolveModel(Intent.class, providedIntent, context);
if (!resolved.isUnresolved() || resolved != providedIntent) {
providedIntents.add(resolved);
} else {
error(context.getMonitor(), "ProvidedIntentNotFound", policySet, providedIntent, policySet);
return;
//throw new ContributionResolveException("Provided Intent - " + providedIntent
//+ " not found for PolicySet " + policySet);
}
} else {
providedIntents.add(providedIntent);
}
}
policySet.getProvidedIntents().clear();
policySet.getProvidedIntents().addAll(providedIntents);
}
}
private void resolveIntentsInMappedPolicies(PolicySet policySet, ModelResolver resolver, ProcessorContext context)
throws ContributionResolveException {
Monitor monitor = context.getMonitor();
for (IntentMap intentMap : policySet.getIntentMaps()) {
Intent intent = intentMap.getProvidedIntent();
if (intent.isUnresolved()) {
Intent resolved = resolver.resolveModel(Intent.class, intent, context);
if (!resolved.isUnresolved() || resolved != intent) {
intentMap.setProvidedIntent(resolved);
} else {
error(monitor, "MappedIntentNotFound", policySet, intent, policySet);
return;
//throw new ContributionResolveException("Mapped Intent - " + mappedIntent
//+ " not found for PolicySet " + policySet);
}
}
for (Qualifier qualifier : intentMap.getQualifiers()) {
intent = qualifier.getIntent();
if (intent.isUnresolved()) {
Intent resolved = resolver.resolveModel(Intent.class, intent, context);
if (!resolved.isUnresolved() || resolved != intent) {
qualifier.setIntent(resolved);
} else {
error(monitor, "MappedIntentNotFound", policySet, intent, policySet);
return;
//throw new ContributionResolveException("Mapped Intent - " + mappedIntent
//+ " not found for PolicySet " + policySet);
}
}
for (PolicyExpression exp : qualifier.getPolicies()) {
// FIXME: How to resolve the policies?
}
}
// validate that the intent map has a qualifier for each
// intent qualifier. The above code has already checked that the
// qualifiers that are there are resolved
Intent providedIntent = intentMap.getProvidedIntent();
if (intentMap.getQualifiers().size() != providedIntent.getQualifiedIntents().size()) {
String missingQualifiers = "";
for (Intent loopQualifiedIntent : providedIntent.getQualifiedIntents()) {
boolean found = false;
for (Qualifier loopQualifier : intentMap.getQualifiers()) {
if (loopQualifier.getIntent().getName().equals(loopQualifiedIntent.getName())) {
found = true;
break;
}
}
if (!found) {
missingQualifiers += loopQualifiedIntent.getName().getLocalPart() + " ";
}
}
if (missingQualifiers.length() > 0) {
Monitor.error(context.getMonitor(),
this,
Messages.RESOURCE_BUNDLE,
"IntentMapMissingQualifiers",
policySet.getName().toString(),
providedIntent.getName().getLocalPart(),
missingQualifiers);
}
}
}
}
private void resolveReferredPolicySets(PolicySet policySet, ModelResolver resolver, ProcessorContext context)
throws ContributionResolveException {
List<PolicySet> referredPolicySets = new ArrayList<PolicySet>();
for (PolicySet referredPolicySet : policySet.getReferencedPolicySets()) {
if (referredPolicySet.isUnresolved()) {
PolicySet resolved = resolver.resolveModel(PolicySet.class, referredPolicySet, context);
if (!resolved.isUnresolved() || resolved != referredPolicySet) {
referredPolicySets.add(resolved);
} else {
error(context.getMonitor(), "ReferredPolicySetNotFound", policySet, referredPolicySet, policySet);
return;
//throw new ContributionResolveException("Referred PolicySet - " + referredPolicySet
//+ "not found for PolicySet - " + policySet);
}
} else {
referredPolicySets.add(referredPolicySet);
}
}
policySet.getReferencedPolicySets().clear();
policySet.getReferencedPolicySets().addAll(referredPolicySets);
}
private void includeReferredPolicySets(PolicySet policySet, PolicySet referredPolicySet) {
for (PolicySet furtherReferredPolicySet : referredPolicySet.getReferencedPolicySets()) {
includeReferredPolicySets(referredPolicySet, furtherReferredPolicySet);
}
policySet.getPolicies().addAll(referredPolicySet.getPolicies());
policySet.getIntentMaps().addAll(referredPolicySet.getIntentMaps());
}
public void resolve(PolicySet policySet, ModelResolver resolver, ProcessorContext context)
throws ContributionResolveException {
if (policySet != null && policySet.isUnresolved()) {
resolveProvidedIntents(policySet, resolver, context);
resolveIntentsInMappedPolicies(policySet, resolver, context);
resolveReferredPolicySets(policySet, resolver, context);
for (PolicySet referredPolicySet : policySet.getReferencedPolicySets()) {
includeReferredPolicySets(policySet, referredPolicySet);
}
if (policySet.isUnresolved()) {
//resolve the policy attachments
resolvePolicies(policySet, resolver, context);
/*if ( !policySet.isUnresolved() ) {
resolver.addModel(policySet);
}*/
}
policySet.setUnresolved(false);
}
}
}