Skip to content

Commit

Permalink
Revive enum & extensionForRef serialization
Browse files Browse the repository at this point in the history
The code was temporarily removed during previous git merge.
Now it's back.
  • Loading branch information
mederly committed Apr 18, 2024
1 parent d8d43fd commit dc46e34
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
*/
package com.evolveum.midpoint.prism;

import com.evolveum.midpoint.prism.schema.SerializableDefinition;

import java.io.Serializable;
import java.util.Collection;
import java.util.Optional;
Expand All @@ -15,7 +17,8 @@
*
* Enumeration has restricted value set - only declared value can be used.
*/
public interface EnumerationTypeDefinition extends SimpleTypeDefinition {
public interface EnumerationTypeDefinition
extends SimpleTypeDefinition, SerializableDefinition {

/**
* Returns definition of enumeration values
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ public class PrismConstants {
public static final QName A_PROCESSING = new QName(NS_ANNOTATION, "processing");
public static final QName A_OPERATIONAL = new QName(NS_ANNOTATION, "operational");
public static final QName A_EXTENSION = new QName(NS_ANNOTATION, "extension");
public static final QName A_EXTENSION_REF = new QName(NS_ANNOTATION, "ref");
public static final QName A_REF = new QName(NS_ANNOTATION, "ref");
public static final QName A_OBJECT_REFERENCE = new QName(NS_ANNOTATION, "objectReference");
public static final QName A_OBJECT_REFERENCE_TARGET_TYPE = new QName(NS_ANNOTATION, "objectReferenceTargetType");
public static final QName A_COMPOSITE = new QName(NS_ANNOTATION, "composite");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ public interface DefinitionFeatureSerializer<V> {

void serialize(@NotNull V value, @NotNull SerializationTarget target);

/** Interface through which we put information into DOM. Currently implemented only for "appInfo" annotation creation. */
/** Interface through which we put information into DOM. */
interface SerializationTarget {
void addAnnotation(QName name, Boolean value);
void addAnnotation(QName name, String value);
void addAnnotation(QName qname, QName value);
void addRefAnnotation(QName qname, QName value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public interface SerializableComplexTypeDefinition extends SerializableDefinitio

@NotNull QName getTypeName();
@Nullable QName getSuperType();
@Nullable QName getExtensionForType();
@NotNull Collection<? extends SerializableItemDefinition> getDefinitionsToSerialize();
boolean isXsdAnyMarker();
boolean isObjectMarker();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,27 @@

package com.evolveum.midpoint.prism.impl.schema;

import static com.evolveum.midpoint.prism.impl.schema.features.DefinitionFeatures.DF_EXTENSION_REF;

import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI;

import static com.evolveum.midpoint.prism.PrismConstants.*;
import static com.evolveum.midpoint.prism.impl.schema.features.DefinitionFeatures.DF_ACCESS;
import static com.evolveum.midpoint.util.MiscUtil.argNonNull;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import com.evolveum.midpoint.prism.EnumerationTypeDefinition;
import com.evolveum.midpoint.prism.impl.schema.features.DefinitionFeatures;
import com.evolveum.midpoint.prism.impl.schema.features.EnumerationValuesInfoXsomParser;
import com.evolveum.midpoint.prism.impl.schema.features.EnumerationValuesXsomParser;

import org.jetbrains.annotations.NotNull;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
Expand Down Expand Up @@ -123,6 +130,8 @@ public SchemaDomSerializer(SerializableSchema schema) throws SchemaException {
for (var definition : schema.getDefinitionsToSerialize()) {
if (definition instanceof SerializableComplexTypeDefinition ctd) {
serializeComplexTypeDefinition(ctd, documentRootElement);
} else if (definition instanceof EnumerationTypeDefinition etd) {
serializeEnumerationTypeDefinition(etd, document.getDocumentElement());
}
}

Expand All @@ -133,7 +142,8 @@ public SchemaDomSerializer(SerializableSchema schema) throws SchemaException {
} else if (definition instanceof SerializablePropertyDefinition ppd) {
// Add top-level property definition. It will create <element> XSD definition
serializePropertyDefinition(ppd, documentRootElement);
} else if (definition instanceof SerializableComplexTypeDefinition) {
} else if (definition instanceof SerializableComplexTypeDefinition
|| definition instanceof EnumerationTypeDefinition) {
// Skip this. Already processed above.
} else {
throw new IllegalArgumentException("Encountered unsupported definition in schema: " + definition);
Expand Down Expand Up @@ -358,13 +368,64 @@ private void serializeComplexTypeDefinition(SerializableComplexTypeDefinition ct
addAnnotation(A_CONTAINER, true, appInfo.appInfoElement);
}

DF_EXTENSION_REF.serialize(ctd, appInfo);

addCommonDefinitionAnnotations(ctd, appInfo);

addExtraFeatures(ctd, appInfo);

appInfo.removeIfNotNeeded();
}

/** TODO reconcile with (move to) {@link EnumerationValuesXsomParser} and {@link EnumerationValuesInfoXsomParser} one day */
private void serializeEnumerationTypeDefinition(EnumerationTypeDefinition definition, Element parent) {
if (definition == null) {
// Nothing to do
return;
}

Element simpleType = createElement(new QName(W3C_XML_SCHEMA_NS_URI, "simpleType"));
parent.appendChild(simpleType);
// "typeName" should be used instead of "name" when defining a XSD type
setAttribute(simpleType, "name", definition.getTypeName().getLocalPart());

var appInfo = createAppInfoAnnotationsTarget(simpleType);
addCommonDefinitionAnnotations(definition, appInfo);
appInfo.removeIfNotNeeded();

Element restriction = createElement(new QName(W3C_XML_SCHEMA_NS_URI, "restriction"));
setAttribute(restriction, "base", definition.getBaseTypeName());
simpleType.appendChild(restriction);

Collection<EnumerationTypeDefinition.ValueDefinition> valueDefinitions = definition.getValues();
for (EnumerationTypeDefinition.ValueDefinition valueDefinition : valueDefinitions) {
restriction.appendChild(createValueDefinitionChild(valueDefinition));
}
}

private Element createValueDefinitionChild(EnumerationTypeDefinition.ValueDefinition valueDefinition) {
Element enumeration = createElement(new QName(W3C_XML_SCHEMA_NS_URI, "enumeration"));
setAttribute(enumeration, "value", valueDefinition.getValue());
Element annotation = createElement(new QName(W3C_XML_SCHEMA_NS_URI, "annotation"));
enumeration.appendChild(annotation);

if (valueDefinition.getDocumentation().isPresent()) {
Element documentation = createElement(new QName(W3C_XML_SCHEMA_NS_URI, "documentation"));
documentation.setTextContent(valueDefinition.getDocumentation().get());
annotation.appendChild(documentation);
}

Element appinfo = createElement(new QName(W3C_XML_SCHEMA_NS_URI, "appinfo"));
annotation.appendChild(appinfo);
if (valueDefinition.getConstantName().isPresent()) {
Element typeSafeEnum = createElement(EnumerationValuesXsomParser.TYPESAFE_ENUM_MEMBER);
setAttribute(typeSafeEnum, "name", valueDefinition.getConstantName().get());
appinfo.appendChild(typeSafeEnum);
}

return enumeration;
}

private static void addExtraFeatures(SerializableDefinition definition, AppInfoSerializationTarget appInfo) {
for (DefinitionFeature<?, ?, ?, ?> extraFeature : definition.getExtraFeaturesToSerialize()) {
extraFeature.serialize(definition, appInfo);
Expand Down Expand Up @@ -491,6 +552,10 @@ private void setAttribute(Element element, String attrName, QName attrValue) {
DOMUtil.setQNameAttribute(element, attrName, attrValue, documentRootElement);
}

private void setAttribute(Element element, String attrName, String attrValue) {
DOMUtil.setAttributeValue(element, attrName, attrValue);
}

/**
* Set attribute in the DOM element to a QName value. This will make sure that the
* appropriate namespace definition for the QName exists.
Expand Down Expand Up @@ -553,20 +618,23 @@ private record AppInfoSerializationTarget(
SchemaDomSerializer schemaSerializer)
implements SerializationTarget {

@Override
public void addAnnotation(QName qname, Boolean value) {
if (value != null) {
addNewElement(qname)
.setTextContent(Boolean.toString(value));
}
}

@Override
public void addAnnotation(QName qname, String value) {
if (value != null) {
addNewElement(qname)
.setTextContent(value);
}
}

@Override
public void addAnnotation(QName qname, QName value) {
if (value != null) {
DOMUtil.setQNameValue(
Expand All @@ -575,6 +643,16 @@ public void addAnnotation(QName qname, QName value) {
}
}

@Override
public void addRefAnnotation(QName qname, QName value) {
if (value != null) {
DOMUtil.setQNameAttribute(
addNewElement(qname),
A_REF.getLocalPart(),
value);
}
}

private Element addNewElement(QName qname) {
Element annotation = schemaSerializer.createElement(qname);
appInfoElement.appendChild(annotation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ private void processTopSimpleTypeDefinition(SchemaBuilder target, XSSimpleType s
private SimpleTypeDefinitionImpl createSimpleTypeDefinitionBuilder(QName typeName, XSSimpleType simpleType) {
XSType baseType = simpleType.getBaseType();
QName baseTypeName = baseType != null ? new QName(baseType.getTargetNamespace(), baseType.getName()) : null;
var enumerationValues = XsomParsers.DF_ENUMERATION_VALUES_PROCESSOR.getValue(simpleType);
var enumerationValues = XsomParsers.DF_ENUMERATION_VALUES_PARSER.getValue(simpleType);
if (enumerationValues != null) {
return new EnumerationTypeDefinitionImpl(typeName, baseTypeName, enumerationValues);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.evolveum.midpoint.prism.impl.schema.annotation.AlwaysUseForEquals;
import com.evolveum.midpoint.prism.impl.schema.features.SchemaMigrationXsomParser.SchemaMigrations;
import com.evolveum.midpoint.prism.schema.DefinitionFeatureSerializer;
import com.evolveum.midpoint.prism.schema.SerializableComplexTypeDefinition;
import com.evolveum.midpoint.prism.xml.XmlTypeConverter;

import com.evolveum.midpoint.util.MiscUtil;
Expand Down Expand Up @@ -129,7 +130,10 @@ public boolean applicableTo(Object sourceComponent) {
QName.class,
ComplexTypeDefinitionLikeBuilder.class,
ComplexTypeDefinitionLikeBuilder::setExtensionForType,
XsomParsers.DF_EXTENSION_REF_PROCESSOR);
XsomParsers.DF_EXTENSION_REF_PARSER,
SerializableComplexTypeDefinition.class,
SerializableComplexTypeDefinition::getExtensionForType,
XsdSerializers.qNameRef(A_EXTENSION));

public static final DefinitionFeature<Boolean, ComplexTypeDefinitionLikeBuilder, Object, ?> DF_CONTAINER_MARKER =
DefinitionFeature.of(
Expand Down Expand Up @@ -256,23 +260,23 @@ public static class XsomParsers {
}
};

public static final DefinitionFeatureParser<QName, XSType> DF_EXTENSION_REF_PROCESSOR =
public static final DefinitionFeatureParser<QName, XSType> DF_EXTENSION_REF_PARSER =
new DefinitionFeatureParser<>() {
@Override
public @Nullable QName getValue(@Nullable XSType sourceComplexType) throws SchemaException {
Element extensionAnnotationElement = getAnnotationElement(sourceComplexType, A_EXTENSION);
if (extensionAnnotationElement == null) {
return null;
}
QName extendedTypeName = DOMUtil.getQNameAttribute(extensionAnnotationElement, A_EXTENSION_REF.getLocalPart());
QName extendedTypeName = DOMUtil.getQNameAttribute(extensionAnnotationElement, A_REF.getLocalPart());
if (extendedTypeName != null) {
return extendedTypeName;
}
throw new SchemaException(
"The %s annotation on %s complex type (%s) does not have %s attribute".formatted(
A_EXTENSION, sourceComplexType.getName(), sourceComplexType.getTargetNamespace(),
A_EXTENSION_REF.getLocalPart()),
A_EXTENSION_REF);
A_REF.getLocalPart()),
A_REF);
}
};
public static final DefinitionFeatureParser.Marker<Object> DF_CONTAINER_MARKER_PROCESSOR = markerInherited(A_CONTAINER);
Expand All @@ -281,7 +285,7 @@ public static class XsomParsers {
public static final DefinitionFeatureParser.Marker<Object> DF_EMBEDDED_OBJECT_MARKER_PROCESSOR = marker(A_EMBEDDED_OBJECT);
public static final DefinitionFeatureParser.Marker<Object> DF_COMPOSITE_MARKER_PROCESSOR = marker(A_COMPOSITE);
public static final DefinitionFeatureParser.Marker<Object> DF_DEPRECATED = marker(A_DEPRECATED);
public static final EnumerationValuesXsomParser DF_ENUMERATION_VALUES_PROCESSOR = new EnumerationValuesXsomParser();
public static final EnumerationValuesXsomParser DF_ENUMERATION_VALUES_PARSER = new EnumerationValuesXsomParser();
public static final EnumerationValuesInfoXsomParser DF_ENUMERATION_VALUES_INFO_PROCESSOR = new EnumerationValuesInfoXsomParser();
public static final AccessXsomProcessor DF_ACCESS_PROCESSOR = new AccessXsomProcessor();
public static final DefinitionFeatureParser<QName, Object> DF_TYPE_OVERRIDE_PROCESSOR = qName(A_TYPE);
Expand Down Expand Up @@ -481,6 +485,11 @@ public static class XsdSerializers {
return (value, target) -> target.addAnnotation(annotationName, value);
}

/** This is perhaps a legacy format, abandoned for several uses, but kept e.g. for "extension for type". */
public static @NotNull DefinitionFeatureSerializer<QName> qNameRef(@NotNull QName annotationName) {
return (value, target) -> target.addRefAnnotation(annotationName, value);
}

public static <E extends Enum<E>> @NotNull DefinitionFeatureSerializer<E> enumBased(
Class<E> valueClass, @NotNull QName annotationName, @NotNull Function<E, String> valueExtractor) {
return (value, target) -> target.addAnnotation(annotationName, valueExtractor.apply(value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
public class EnumerationValuesXsomParser
implements DefinitionFeatureParser<List<EnumerationTypeDefinition.ValueDefinition>, XSSimpleType> {

private static final QName TYPESAFE_ENUM_MEMBER = new QName("https://jakarta.ee/xml/ns/jaxb", "typesafeEnumMember");
public static final QName TYPESAFE_ENUM_MEMBER = new QName("https://jakarta.ee/xml/ns/jaxb", "typesafeEnumMember");
private static final QName TYPESAFE_ENUM_MEMBER_LEGACY = new QName("http://java.sun.com/xml/ns/jaxb","typesafeEnumMember");

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,9 +587,7 @@ public static void setQNameAttribute(

public static void setQNameAttribute(
Element element, String attributeName, QName attributeValue) {
Document doc = element.getOwnerDocument();
Attr attr = doc.createAttribute(attributeName);
setQNameAttribute(element, attr, attributeValue, element);
setQNameAttribute(element, attributeName, attributeValue, element);
}

public static void setQNameAttribute(
Expand Down

0 comments on commit dc46e34

Please sign in to comment.