org.fabric3.introspection.xml.composite.CompositeLoader Maven / Gradle / Ivy
/*
* Fabric3
* Copyright (c) 2009-2013 Metaform Systems
*
* Fabric3 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version, with the
* following exception:
*
* Linking this software statically or dynamically with other
* modules is making a combined work based on this software.
* Thus, the terms and conditions of the GNU General Public
* License cover the whole combination.
*
* As a special exception, the copyright holders of this software
* give you permission to link this software with independent
* modules to produce an executable, regardless of the license
* terms of these independent modules, and to copy and distribute
* the resulting executable under terms of your choice, provided
* that you also meet, for each linked independent module, the
* terms and conditions of the license of that module. An
* independent module is a module which is not derived from or
* based on this software. If you modify this software, you may
* extend this exception to your version of the software, but
* you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version.
*
* Fabric3 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the
* GNU General Public License along with Fabric3.
* If not, see .
*
* ----------------------------------------------------
*
* Portions originally based on Apache Tuscany 2007
* licensed under the Apache 2.0 license.
*
*/
package org.fabric3.introspection.xml.composite;
import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import org.fabric3.host.contribution.ArtifactValidationFailure;
import org.fabric3.introspection.xml.common.AbstractExtensibleTypeLoader;
import org.fabric3.model.type.ModelObject;
import org.fabric3.model.type.component.AbstractReference;
import org.fabric3.model.type.component.AbstractService;
import org.fabric3.model.type.component.Autowire;
import org.fabric3.model.type.component.ChannelDefinition;
import org.fabric3.model.type.component.ComponentDefinition;
import org.fabric3.model.type.component.ComponentReference;
import org.fabric3.model.type.component.ComponentType;
import org.fabric3.model.type.component.Composite;
import org.fabric3.model.type.component.CompositeReference;
import org.fabric3.model.type.component.CompositeService;
import org.fabric3.model.type.component.Implementation;
import org.fabric3.model.type.component.Include;
import org.fabric3.model.type.component.Multiplicity;
import org.fabric3.model.type.component.Property;
import org.fabric3.model.type.component.PropertyValue;
import org.fabric3.model.type.component.ResourceDefinition;
import org.fabric3.model.type.component.WireDefinition;
import org.fabric3.model.type.contract.ServiceContract;
import org.fabric3.spi.contract.ContractMatcher;
import org.fabric3.spi.contract.MatchResult;
import org.fabric3.spi.introspection.DefaultIntrospectionContext;
import org.fabric3.spi.introspection.IntrospectionContext;
import org.fabric3.spi.introspection.xml.IncompatibleContracts;
import org.fabric3.spi.introspection.xml.InvalidValue;
import org.fabric3.spi.introspection.xml.LoaderHelper;
import org.fabric3.spi.introspection.xml.LoaderRegistry;
import org.fabric3.spi.introspection.xml.MissingAttribute;
import org.fabric3.spi.introspection.xml.TypeLoader;
import org.fabric3.spi.introspection.xml.UnrecognizedElement;
import org.fabric3.spi.util.UriHelper;
import org.oasisopen.sca.annotation.Constructor;
import org.oasisopen.sca.annotation.EagerInit;
import org.oasisopen.sca.annotation.Reference;
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
import static org.fabric3.spi.introspection.xml.CompositeConstants.CHANNEL;
import static org.fabric3.spi.introspection.xml.CompositeConstants.COMPONENT;
import static org.fabric3.spi.introspection.xml.CompositeConstants.COMPOSITE;
import static org.fabric3.spi.introspection.xml.CompositeConstants.INCLUDE;
import static org.fabric3.spi.introspection.xml.CompositeConstants.PROPERTY;
import static org.fabric3.spi.introspection.xml.CompositeConstants.REFERENCE;
import static org.fabric3.spi.introspection.xml.CompositeConstants.SERVICE;
import static org.fabric3.spi.introspection.xml.CompositeConstants.WIRE;
/**
* Loads a composite component definition from an XML-based assembly file
*/
@EagerInit
public class CompositeLoader extends AbstractExtensibleTypeLoader {
private TypeLoader serviceLoader;
private TypeLoader referenceLoader;
private TypeLoader propertyLoader;
private ContractMatcher contractMatcher;
private final LoaderHelper loaderHelper;
boolean roundTrip;
/**
* Constructor used during bootstrap; service and reference elements are not supported.
*
* @param registry the loader registry to register with; also used to load extension elements
* @param propertyLoader the property loader
* @param loaderHelper helper the helper
*/
public CompositeLoader(LoaderRegistry registry, TypeLoader propertyLoader, LoaderHelper loaderHelper) {
this(registry, null, null, propertyLoader, null, loaderHelper);
}
/**
* Constructor. Specific loaders to handle overloaded property>, service
and reference
elements on composites and
* components.
*
* @param registry the loader registry to register with; also used to load extension elements
* @param serviceLoader the service loader
* @param referenceLoader the reference loader
* @param propertyLoader the property loader
* @param contractMatcher the contract matcher
* @param loaderHelper helper the helper
*/
@Constructor
public CompositeLoader(@Reference LoaderRegistry registry,
@Reference(name = "service") TypeLoader serviceLoader,
@Reference(name = "reference") TypeLoader referenceLoader,
@Reference(name = "property") TypeLoader propertyLoader,
@Reference ContractMatcher contractMatcher,
@Reference LoaderHelper loaderHelper) {
super(registry);
addAttributes("name", "autowire", "targetNamespace", "local", "requires", "policySets", "constrainingType", "channel", "schemaLocation");
this.serviceLoader = serviceLoader;
this.referenceLoader = referenceLoader;
this.propertyLoader = propertyLoader;
this.contractMatcher = contractMatcher;
this.loaderHelper = loaderHelper;
}
@org.oasisopen.sca.annotation.Property(required = false)
public void setRoundTrip(boolean roundTrip) {
this.roundTrip = roundTrip;
}
public QName getXMLType() {
return COMPOSITE;
}
@SuppressWarnings({"VariableNotUsedInsideIf"})
public Composite load(XMLStreamReader reader, IntrospectionContext context) throws XMLStreamException {
// track locations so they can be used to report validation errors after the parser has been advanced
Map locations = new HashMap();
String name = reader.getAttributeValue(null, "name");
String targetNamespace = reader.getAttributeValue(null, "targetNamespace");
String localStr = reader.getAttributeValue(null, "local");
boolean local = Boolean.valueOf(localStr);
IntrospectionContext childContext = new DefaultIntrospectionContext(context, targetNamespace);
QName compositeName = new QName(targetNamespace, name);
NamespaceContext nsContext = createNamespaceContext(reader);
Composite type = new Composite(compositeName);
String autowire = reader.getAttributeValue(null, "autowire");
type.setAutowire(Autowire.fromString(autowire));
if (roundTrip) {
type.enableRoundTrip();
addNamespaces(type, reader);
if (targetNamespace != null) {
type.attributeSpecified("targetNamespace");
}
if (localStr != null) {
type.attributeSpecified("local");
}
if (autowire != null) {
type.attributeSpecified("autowire");
}
}
type.setContributionUri(context.getContributionUri());
type.setLocal(local);
loaderHelper.loadPolicySetsAndIntents(type, reader, childContext);
validateAttributes(reader, context, type);
while (true) {
int val = reader.next();
switch (val) {
case START_ELEMENT:
QName qname = reader.getName();
if (INCLUDE.equals(qname)) {
handleInclude(type, reader, locations, compositeName, childContext, context);
continue;
} else if (PROPERTY.equals(qname)) {
handleProperty(type, reader, locations, childContext);
continue;
} else if (SERVICE.equals(qname)) {
handleService(type, reader, locations, childContext);
continue;
} else if (CHANNEL.equals(qname)) {
handleChannel(type, reader, locations, compositeName, childContext, context);
continue;
} else if (REFERENCE.equals(qname)) {
handleReference(type, reader, locations, childContext);
continue;
} else if (COMPONENT.equals(qname)) {
boolean valid = handleComponent(type, reader, nsContext, locations, compositeName, childContext, context);
if (!valid) {
updateContext(context, childContext, compositeName);
}
continue;
} else if (WIRE.equals(qname)) {
handleWire(type, reader, compositeName, childContext, context);
continue;
} else {
handleExtensionElement(type, reader, childContext);
continue;
}
case END_ELEMENT:
if (!COMPOSITE.equals(reader.getName())) {
continue;
}
updateAndValidateServicePromotions(type, locations, childContext);
updateAndValidateReferencePromotions(type, locations, childContext);
updateContext(context, childContext, compositeName);
return type;
case XMLStreamReader.COMMENT:
if (!roundTrip) {
continue;
}
String comment = reader.getText();
type.addComment(comment);
continue;
default:
if (!roundTrip) {
continue;
}
comment = reader.getText();
type.addText(comment);
}
}
}
private void addNamespaces(Composite type, XMLStreamReader reader) {
int count = reader.getNamespaceCount();
for (int i = 0; i < count; i++) {
String prefix = reader.getNamespacePrefix(i);
String uri = reader.getNamespaceURI(i);
type.addNamespace(prefix, uri);
}
}
private void handleExtensionElement(Composite type, XMLStreamReader reader, IntrospectionContext context) throws XMLStreamException {
Location startLocation = reader.getLocation();
// Extension element - for now try to load and see if we can handle it
ModelObject modelObject = registry.load(reader, ModelObject.class, context);
// TODO when the loader registry is replaced this try..catch must be replaced with a check for a loader and an
// UnrecognizedElement added to the context if none is found
if (modelObject instanceof Property) {
type.add((Property) modelObject);
} else if (modelObject instanceof CompositeService) {
type.add((CompositeService) modelObject);
} else if (modelObject instanceof CompositeReference) {
type.add((CompositeReference) modelObject);
} else if (modelObject instanceof ComponentDefinition) {
type.add((ComponentDefinition>) modelObject);
} else if (modelObject instanceof ResourceDefinition) {
type.add((ResourceDefinition) modelObject);
} else if (modelObject == null) {
// loaders may elect to return a null element; ignore
} else {
UnrecognizedElement failure = new UnrecognizedElement(reader, startLocation, type);
context.addError(failure);
}
}
private void handleWire(Composite type,
XMLStreamReader reader,
QName compositeName,
IntrospectionContext context,
IntrospectionContext parentContext) throws XMLStreamException {
WireDefinition wire;
wire = registry.load(reader, WireDefinition.class, context);
if (wire == null) {
// error encountered loading the wire
updateContext(parentContext, context, compositeName);
return;
}
type.add(wire);
}
private boolean handleComponent(Composite type,
XMLStreamReader reader,
NamespaceContext nsContext,
Map locations,
QName compositeName,
IntrospectionContext context,
IntrospectionContext parentContext) throws XMLStreamException {
Location startLocation = reader.getLocation();
ComponentDefinition> componentDefinition = registry.load(reader, ComponentDefinition.class, context);
if (componentDefinition == null) {
// error encountered loading the componentDefinition
updateContext(parentContext, context, compositeName);
return false;
}
String key = componentDefinition.getName();
if (type.getComponents().containsKey(key)) {
DuplicateComponentName failure = new DuplicateComponentName(key, startLocation, type);
context.addError(failure);
return false;
}
type.add(componentDefinition);
Implementation> implementation = componentDefinition.getImplementation();
if (implementation == null || implementation.getComponentType() == null) {
return false;
}
if (type.getAutowire() != Autowire.INHERITED && componentDefinition.getAutowire() == Autowire.INHERITED) {
componentDefinition.setAutowire(type.getAutowire());
}
// Calculate the namespace context from the composite element since XMLStreamReader.getNamespaceCount() only returns the number of namespaces
// declared on the current element. This means namespaces defined on parent elements which are active (e.g. ) or not reported.
// Scoping results in no namespaces being reported
for (PropertyValue value : componentDefinition.getPropertyValues().values()) {
value.setNamespaceContext(nsContext);
}
locations.put(componentDefinition, startLocation);
return true;
}
private void handleChannel(Composite type,
XMLStreamReader reader,
Map locations,
QName compositeName,
IntrospectionContext context,
IntrospectionContext parentContext) throws XMLStreamException {
Location startLocation = reader.getLocation();
ChannelDefinition channelDefinition = registry.load(reader, ChannelDefinition.class, context);
if (channelDefinition == null) {
// error encountered loading the channel definition
updateContext(parentContext, context, compositeName);
return;
}
String key = channelDefinition.getName();
if (type.getChannels().containsKey(key)) {
DuplicateChannelName failure = new DuplicateChannelName(key, startLocation, type);
context.addError(failure);
return;
}
locations.put(channelDefinition, startLocation);
type.add(channelDefinition);
}
private void handleReference(Composite type, XMLStreamReader reader, Map locations, IntrospectionContext context)
throws XMLStreamException {
Location startLocation = reader.getLocation();
CompositeReference reference = referenceLoader.load(reader, context);
if (reference == null) {
// error encountered loading the reference
return;
}
if (type.getReferences().containsKey(reference.getName())) {
String key = reference.getName();
DuplicatePromotedReference failure = new DuplicatePromotedReference(key, startLocation, type);
context.addError(failure);
} else {
type.add(reference);
locations.put(reference, startLocation);
}
}
private void handleService(Composite type, XMLStreamReader reader, Map locations, IntrospectionContext context)
throws XMLStreamException {
Location startLocation = reader.getLocation();
CompositeService service = serviceLoader.load(reader, context);
if (service == null) {
// error encountered loading the service
return;
}
if (type.getServices().containsKey(service.getName())) {
String key = service.getName();
DuplicatePromotedService failure = new DuplicatePromotedService(key, startLocation, type);
context.addError(failure);
} else {
locations.put(service, startLocation);
type.add(service);
}
}
private void handleProperty(Composite type, XMLStreamReader reader, Map locations, IntrospectionContext context)
throws XMLStreamException {
Location startLocation = reader.getLocation();
Property property = propertyLoader.load(reader, context);
if (property == null) {
// error encountered loading the property
return;
}
String key = property.getName();
if (type.getProperties().containsKey(key)) {
DuplicateProperty failure = new DuplicateProperty(key, startLocation, type);
context.addError(failure);
} else {
type.add(property);
locations.put(property, startLocation);
}
}
private void handleInclude(Composite type,
XMLStreamReader reader,
Map locations,
QName compositeName,
IntrospectionContext context,
IntrospectionContext parentContext) throws XMLStreamException {
Location startLocation = reader.getLocation();
Include include = registry.load(reader, Include.class, context);
if (include == null) {
// error encountered loading the include
updateContext(parentContext, context, compositeName);
return;
}
QName includeName = include.getName();
if (type.getIncludes().containsKey(includeName)) {
String identifier = includeName.toString();
DuplicateInclude failure = new DuplicateInclude(identifier, startLocation, include);
context.addError(failure);
return;
}
Composite included = include.getIncluded();
if (included == null) {
return;
}
if (type.isLocal() != included.isLocal()) {
InvalidInclude error = new InvalidInclude("Composite " + type.getName() + " has a local value of " + type.isLocal()
+ " and the included composite " + includeName + " has a value of "
+ included.isLocal(), startLocation);
context.addError(error);
}
for (ComponentDefinition definition : included.getComponents().values()) {
String key = definition.getName();
if (type.getComponents().containsKey(key)) {
DuplicateComponentName failure = new DuplicateComponentName(key, startLocation, type);
context.addError(failure);
}
}
locations.put(include, startLocation);
type.add(include);
}
private void updateAndValidateServicePromotions(Composite type, Map locations, IntrospectionContext context) {
for (AbstractService definition : type.getServices().values()) {
CompositeService service = (CompositeService) definition;
Location location = locations.get(service);
URI promotedUri = service.getPromote();
if (promotedUri == null) {
String serviceName = service.getName();
QName compositeName = type.getName();
MissingAttribute error =
new MissingAttribute("Service promotion not specified for " + serviceName + " in composite " + compositeName, location);
context.addError(error);
continue;
}
String componentName = UriHelper.getDefragmentedNameAsString(promotedUri);
ComponentDefinition promotedComponent = type.getComponents().get(componentName);
AbstractService promotedService;
String name = service.getName();
if (promotedComponent == null) {
PromotionNotFound error =
new PromotionNotFound("Component " + componentName + " referenced by " + name + " not found", location, service);
context.addError(error);
continue;
} else {
String serviceName = promotedUri.getFragment();
ComponentType componentType = promotedComponent.getComponentType();
if (serviceName != null) {
promotedService = componentType.getServices().get(serviceName);
if (promotedService == null) {
PromotionNotFound error =
new PromotionNotFound("Service " + serviceName + " promoted by " + name + " not found", location, service);
context.addError(error);
continue;
}
} else {
Map services = componentType.getServices();
int numberOfServices = services.size();
if (numberOfServices == 2) {
PromotionNotFound error = new PromotionNotFound("A promoted service must be specified for " + name, location, service);
context.addError(error);
return;
} else if (numberOfServices == 1) {
promotedService = services.values().iterator().next();
} else if (numberOfServices == 0) {
PromotionNotFound error =
new PromotionNotFound("Component " + componentName + " has no services to promote", location, service);
context.addError(error);
continue;
} else {
PromotionNotFound error =
new PromotionNotFound("A promoted service must be specified for " + name, location, service);
context.addError(error);
continue;
}
}
}
processServiceContract(service, promotedService, locations, context);
}
}
private void updateAndValidateReferencePromotions(Composite type, Map locations, IntrospectionContext context) {
for (AbstractReference definition : type.getReferences().values()) {
CompositeReference reference = (CompositeReference) definition;
Location location = locations.get(reference);
for (URI promotedUri : reference.getPromotedUris()) {
String componentName = UriHelper.getDefragmentedNameAsString(promotedUri);
ComponentDefinition> promoted = type.getComponents().get(componentName);
String referenceName = promotedUri.getFragment();
if (promoted == null) {
PromotionNotFound error =
new PromotionNotFound("Component " + componentName + " referenced by " + reference.getName() + " not found",
location,
reference);
context.addError(error);
return;
} else {
if (referenceName == null && promoted.getComponentType().getReferences().size() != 1) {
PromotionNotFound error =
new PromotionNotFound("A promoted reference must be specified for " + reference.getName(), location, reference);
context.addError(error);
continue;
}
AbstractReference promotedReference;
if (referenceName == null && promoted.getComponentType().getReferences().size() == 1) {
promotedReference = promoted.getComponentType().getReferences().values().iterator().next();
} else {
promotedReference = promoted.getComponentType().getReferences().get(referenceName);
}
if (referenceName != null && promotedReference == null) {
PromotionNotFound error =
new PromotionNotFound("Reference " + referenceName + " promoted by " + reference.getName() + " not found",
location,
reference);
context.addError(error);
continue;
}
processMultiplicity(reference, promotedReference, location, context);
processReferenceContract(reference, promotedReference, locations, context);
// check overridable
ComponentReference componentReference = promoted.getReferences().get(referenceName);
if (componentReference != null) {
if (componentReference.isNonOverridable()) {
if (promotedReference.getMultiplicity().equals(Multiplicity.ONE_ONE) || promotedReference.getMultiplicity().equals(
Multiplicity.ZERO_ONE)) {
IllegalPromotion failure =
new IllegalPromotion("Cannot promote a 0..1 or 1..1 non-overridable reference: " + referenceName,
location,
promotedReference);
context.addError(failure);
}
}
}
}
}
}
}
/**
* Sets the composite service contract from the promoted service if not explicitly configured. If configured, validates the contract matches the
* promoted reference contract.
*
* @param service the service
* @param promotedService the promoted service
* @param locations the location mappings
* @param context the context
*/
private void processServiceContract(CompositeService service,
AbstractService promotedService,
Map locations,
IntrospectionContext context) {
if (service.getServiceContract() == null) {
// if a service contract is not set on the composite service, inherit from the promoted service
service.setServiceContract(promotedService.getServiceContract());
} else if (contractMatcher != null) { // null check for contract matcher as it is not used during bootstrap
// verify service contracts are compatible - the composite service contract can be a subset of the promoted service contract
MatchResult result = contractMatcher.isAssignableFrom(service.getServiceContract(), promotedService.getServiceContract(), true);
if (!result.isAssignable()) {
String name = service.getName();
Location location = locations.get(service);
IncompatibleContracts error =
new IncompatibleContracts("The composite service interface " + name + " is not compatible with the promoted service "
+ promotedService.getName() + ": " + result.getError(), location, service);
context.addError(error);
} else {
matchServiceCallbackContracts(service, promotedService, locations, context);
}
}
}
/**
* Sets the composite reference service contract from the promoted reference if not explicitly configured. If configured, validates the contract
* matches the promoted reference contract.
*
* @param reference the reference
* @param promotedReference the promoted reference
* @param locations the locations
* @param context the context
*/
private void processReferenceContract(CompositeReference reference,
AbstractReference promotedReference,
Map locations,
IntrospectionContext context) {
if (reference.getServiceContract() == null) {
// if a reference contract is not set on the composite service, inherit from the promoted reference
reference.setServiceContract(promotedReference.getServiceContract());
} else if (contractMatcher != null) { // null check for contract matcher as it is not used during bootstrap
// verify service contracts are compatible - the promoted reference contract can be a subset of the composite reference contract
ServiceContract promotedContract = promotedReference.getServiceContract();
ServiceContract contract = reference.getServiceContract();
MatchResult result = contractMatcher.isAssignableFrom(promotedContract, contract, true);
if (!result.isAssignable()) {
String name = reference.getName();
Location location = locations.get(reference);
IncompatibleContracts error = new IncompatibleContracts("The composite service interface " + name
+ " is not compatible with the promoted service "
+ promotedReference.getName() + ": " + result.getError(),
location, reference);
context.addError(error);
} else {
matchReferenceCallbackContracts(reference, promotedReference, locations, context);
}
}
}
/**
* Matches the service contract declared on the promoted service and the component service.
*
* @param service the service
* @param promotedService the component type service
* @param locations the locations
* @param context the context
*/
private void matchServiceCallbackContracts(CompositeService service,
AbstractService promotedService,
Map locations,
IntrospectionContext context) {
ServiceContract callbackContract = service.getServiceContract().getCallbackContract();
if (callbackContract == null) {
return;
}
ServiceContract promotedCallbackContract = promotedService.getServiceContract().getCallbackContract();
if (promotedCallbackContract == null) {
Location location = locations.get(service);
IncompatibleContracts error =
new IncompatibleContracts("Component type for service " + service.getName() + " does not have a callback contract",
location,
service);
context.addError(error);
return;
}
MatchResult result = contractMatcher.isAssignableFrom(promotedCallbackContract, callbackContract, true);
if (!result.isAssignable()) {
Location location = locations.get(service);
String name = service.getName();
IncompatibleContracts error = new IncompatibleContracts("The composite service " + name + " callback contract is not compatible with " +
"the promoted service " + promotedService.getName()
+ " callback contract: " + result.getError(), location, service);
context.addError(error);
}
}
/**
* Matches the service contract declared on the promoted reference and the component reference.
*
* @param reference the reference
* @param promotedReference the promoted reference
* @param locations the locations
* @param context the context
*/
private void matchReferenceCallbackContracts(CompositeReference reference,
AbstractReference promotedReference,
Map locations,
IntrospectionContext context) {
ServiceContract callbackContract = reference.getServiceContract().getCallbackContract();
if (callbackContract == null) {
return;
}
ServiceContract promotedCallbackContract = promotedReference.getServiceContract().getCallbackContract();
if (promotedCallbackContract == null) {
Location location = locations.get(reference);
IncompatibleContracts error =
new IncompatibleContracts("Component type for reference " + reference.getName() + " does not have a callback contract",
location,
reference);
context.addError(error);
return;
}
MatchResult result = contractMatcher.isAssignableFrom(promotedCallbackContract, callbackContract, true);
if (!result.isAssignable()) {
Location location = locations.get(reference);
String name = reference.getName();
IncompatibleContracts error = new IncompatibleContracts("The composite reference " + name + " callback contract is not compatible with " +
"the promoted reference " + promotedReference.getName()
+ " callback contract: " + result.getError(), location, reference);
context.addError(error);
}
}
/**
* Sets the composite multiplicity to inherit from the promoted reference if not explicitly configured. If configured, validates the setting
* against the promoted setting.
*
* @param reference the reference
* @param promotedReference the promoted reference
* @param location the current location
* @param context the context
*/
private void processMultiplicity(CompositeReference reference,
AbstractReference promotedReference,
Location location,
IntrospectionContext context) {
// set the multiplicity to inherit from the promoted reference
if (reference.getMultiplicity() == null) {
Multiplicity multiplicity = promotedReference.getMultiplicity();
reference.setMultiplicity(multiplicity);
} else {
String name = reference.getName();
if (!loaderHelper.canNarrow(reference.getMultiplicity(), promotedReference.getMultiplicity())) {
InvalidValue failure = new InvalidValue("The multiplicity setting for reference " + name + " widens the default setting", location);
context.addError(failure);
}
}
}
private void updateContext(IntrospectionContext context, IntrospectionContext childContext, QName compositeName) {
if (childContext.hasErrors() || childContext.hasWarnings()) {
URI uri = context.getContributionUri();
if (childContext.hasErrors()) {
ArtifactValidationFailure artifactFailure = new ArtifactValidationFailure(uri, compositeName.toString());
artifactFailure.addFailures(childContext.getErrors());
context.addError(artifactFailure);
}
if (childContext.hasWarnings()) {
ArtifactValidationFailure artifactFailure = new ArtifactValidationFailure(uri, compositeName.toString());
artifactFailure.addFailures(childContext.getWarnings());
context.addWarning(artifactFailure);
}
}
}
private NamespaceContext createNamespaceContext(XMLStreamReader reader) {
StatefulNamespaceContext namespaceContext = new StatefulNamespaceContext();
int count = reader.getNamespaceCount();
for (int i = 0; i < count; i++) {
String prefix = reader.getNamespacePrefix(i);
if (prefix == null) {
continue;
}
String namespaceUri = reader.getNamespaceURI(prefix);
namespaceContext.addNamespace(prefix, namespaceUri);
}
return namespaceContext;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy