Skip to content

Commit

Permalink
Merge branch 'feature/constant-prefixes'
Browse files Browse the repository at this point in the history
  • Loading branch information
tonydamage committed Feb 24, 2021
2 parents 83efabf + 2b92e32 commit 65cdc8a
Show file tree
Hide file tree
Showing 28 changed files with 232 additions and 29 deletions.
Expand Up @@ -108,8 +108,10 @@ public class PrismConstants {
public static final QName A_SCHEMA_MIGRATION_ELEMENT = new QName(NS_ANNOTATION, "element");
public static final QName A_SCHEMA_MIGRATION_VERSION = new QName(NS_ANNOTATION, "version");
public static final QName A_SCHEMA_MIGRATION_OPERATION = new QName(NS_ANNOTATION, "operation");
public static final QName A_DEFAULT_PREFIX = new QName(NS_ANNOTATION, "defaultPrefix");

public static final QName SCHEMA_DOCUMENTATION = new QName(W3C_XML_SCHEMA_NS_URI, "documentation");
public static final QName SCHEMA_ANNOTATION = new QName(W3C_XML_SCHEMA_NS_URI, "annotation");
public static final QName SCHEMA_APP_INFO = new QName(W3C_XML_SCHEMA_NS_URI, "appinfo");

public static final QName A_MAX_OCCURS = new QName(NS_ANNOTATION, "maxOccurs");
Expand Down
Expand Up @@ -37,6 +37,17 @@ public abstract class PrismNamespaceContext implements Serializable {
.put(PrismConstants.PREFIX_NS_QUERY, PrismConstants.NS_QUERY)
.build());

public static PrismNamespaceContext from(Map<String, String> prefixToNs) {
if(prefixToNs.isEmpty()) {
return EMPTY;
}
return new Impl(null, prefixToNs);
}

public static PrismNamespaceContext.Builder builder() {
return new Builder();
}

/**
* Returns parent namespace context
* @return parent namespace context
Expand Down Expand Up @@ -121,6 +132,14 @@ public final Optional<String> prefixFor(String namespace) {
*/
public abstract PrismNamespaceContext childContext(Map<String, String> local);

/**
* Creates optimized child namespace context with supplied local mapping
*
* @param local Local definition of prefixes
* @return Child context with local definitions
*/
public abstract PrismNamespaceContext optimizedChildContext(Map<String, String> local);

/**
* Returns child namespace context with no local mappings.
*
Expand All @@ -132,13 +151,6 @@ public final Optional<String> prefixFor(String namespace) {
*/
public abstract PrismNamespaceContext inherited();

public static PrismNamespaceContext from(Map<String, String> prefixToNs) {
if(prefixToNs.isEmpty()) {
return EMPTY;
}
return new Impl(null, prefixToNs);
}

private static class Impl extends PrismNamespaceContext {

private static final long serialVersionUID = 1L;
Expand Down Expand Up @@ -194,6 +206,21 @@ public PrismNamespaceContext childContext(Map<String, String> local) {
return new Impl(this, local);
}

@Override
public PrismNamespaceContext optimizedChildContext(Map<String, String> local) {
if(local.isEmpty()) {
return inherited;
}
ImmutableMap.Builder<String, String> optimizedLocal = ImmutableMap.builder();
for(Entry<String, String> entry : local.entrySet()) {
Optional<String> ns = namespaceFor(entry.getKey());
if(ns.isEmpty() || !entry.getValue().equals(ns.get())) {
optimizedLocal.put(entry);
}
}
return childContext(optimizedLocal.build());
}

@Override
public Optional<String> namespaceFor(String prefix) {
if(prefix == null) {
Expand Down Expand Up @@ -364,6 +391,11 @@ public PrismNamespaceContext childContext(Map<String, String> local) {
return parent.childContext(local);
}

@Override
public PrismNamespaceContext optimizedChildContext(Map<String, String> local) {
return parent.optimizedChildContext(local);
}

@Override
public Optional<String> namespaceFor(String prefix) {
return parent.namespaceFor(prefix);
Expand Down Expand Up @@ -437,6 +469,11 @@ public PrismNamespaceContext childContext(Map<String, String> local) {
return from(local);
}

@Override
public PrismNamespaceContext optimizedChildContext(Map<String, String> local) {
return childContext(local);
}

@Override
public PrismNamespaceContext inherited() {
return this;
Expand Down Expand Up @@ -529,4 +566,26 @@ public String toString() {
return new StringBuilder(this.getClass().getSimpleName()).append(allPrefixes().toString()).toString();
}

public static class Builder {

protected Builder() {

}

private final Map<String, String> prefixToNamespace = new HashMap<>();

public Builder addPrefix(String prefix, String namespace) {
String previous = prefixToNamespace.putIfAbsent(prefix, namespace);
Preconditions.checkArgument(previous == null || namespace.equals(previous), "Prefix %s is already declared as '%s', trying to redeclare it as '%s'", prefix, previous, namespace);
return this;
}

public PrismNamespaceContext build() {
return from(prefixToNamespace);
}

public void defaultNamespace(String defaultNamespace) {
addPrefix(DEFAULT_PREFIX, defaultNamespace);
}
}
}
Expand Up @@ -34,6 +34,9 @@ public interface SchemaRegistry extends PrismContextSensitive, DebugDumpable, Gl
*/
DynamicNamespacePrefixMapper getNamespacePrefixMapper();


PrismNamespaceContext staticNamespaceContext();

void registerInvalidationListener(InvalidationListener listener);

String getDefaultNamespace();
Expand Down Expand Up @@ -226,7 +229,4 @@ interface InvalidationListener {
void invalidate();
}

default PrismNamespaceContext globalNamespaceContext() {
return PrismNamespaceContext.EMPTY; // FIXME later
}
}
Expand Up @@ -46,7 +46,11 @@ public abstract class AbstractReader {

AbstractReader(@NotNull SchemaRegistry schemaRegistry) {
this.schemaRegistry = schemaRegistry;
this.namespaceContext = schemaRegistry.globalNamespaceContext();
// Parsing legacy namespace-less JSON with default namespace declared
// would put any undefined element to default namespace (usually common)
// which will break in places, where namespace change is expected
// and final item name is not directly defined in parent.
this.namespaceContext = schemaRegistry.staticNamespaceContext().withoutDefault();
}

@NotNull
Expand Down
Expand Up @@ -42,15 +42,18 @@ class DocumentWriter {

@NotNull private final JsonGenerator generator;

private XNodeDefinition.Root schema;
private final XNodeDefinition.Root schema;

private XNodeDefinition metadataDef;
private final XNodeDefinition metadataDef;

private final PrismNamespaceContext staticNamespaces;

DocumentWriter(WritingContext<?> ctx, XNodeDefinition.Root schema) {
this.ctx = ctx;
this.generator = ctx.generator;
this.schema = schema;
this.metadataDef = schema.metadataDef();
this.staticNamespaces = schema.staticNamespaceContext().inherited();
}

void writeListAsSeparateDocuments(@NotNull ListXNodeImpl root) throws IOException {
Expand All @@ -66,11 +69,10 @@ void writeListAsSeparateDocuments(@NotNull ListXNodeImpl root) throws IOExceptio
}

public void write(XNodeImpl xnode) throws IOException {
// FIXME: Use actual namespace context
if (xnode instanceof RootXNodeImpl) {
write(((RootXNodeImpl) xnode).toMapXNode(), PrismNamespaceContext.EMPTY, false, schema);
write(((RootXNodeImpl) xnode).toMapXNode(), staticNamespaces, false, schema);
} else {
write(xnode, PrismNamespaceContext.EMPTY, false, schema);
write(xnode, staticNamespaces, false, schema);
}
}

Expand Down
Expand Up @@ -38,15 +38,19 @@ public final class SchemaDescriptionImpl extends AbstractFreezable implements Sc
private PrismSchema schema;
private Package compileTimeClassesPackage;

private String defaultPrefix;

SchemaDescriptionImpl(String sourceDescription, String path) {
this.sourceDescription = sourceDescription;
this.path = path;
}

@Override
public String getPath() {
return path;
}

@Override
public String getNamespace() {
return namespace;
}
Expand All @@ -66,6 +70,7 @@ public void setNode(Node node) {
this.node = node;
}

@Override
public String getUsualPrefix() {
return usualPrefix;
}
Expand All @@ -75,10 +80,12 @@ void setUsualPrefix(String usualPrefix) {
this.usualPrefix = usualPrefix;
}

@Override
public String getSourceDescription() {
return sourceDescription;
}

@Override
public boolean isPrismSchema() {
return isPrismSchema;
}
Expand All @@ -89,6 +96,7 @@ void setPrismSchema(boolean value) {
this.isPrismSchema = value;
}

@Override
public boolean isDefault() {
return isDefault;
}
Expand All @@ -98,6 +106,7 @@ public void setDefault(boolean isDefault) {
this.isDefault = isDefault;
}

@Override
public boolean isDeclaredByDefault() {
return isDeclaredByDefault;
}
Expand All @@ -107,6 +116,7 @@ void setDeclaredByDefault(boolean isDeclaredByDefault) {
this.isDeclaredByDefault = isDeclaredByDefault;
}

@Override
public PrismSchema getSchema() {
return schema;
}
Expand All @@ -116,6 +126,7 @@ public void setSchema(PrismSchema schema) {
this.schema = schema;
}

@Override
public Package getCompileTimeClassesPackage() {
return compileTimeClassesPackage;
}
Expand All @@ -125,17 +136,20 @@ void setCompileTimeClassesPackage(Package compileTimeClassesPackage) {
this.compileTimeClassesPackage = compileTimeClassesPackage;
}

@Override
public boolean canInputStream() {
return streamable != null;
}

@Override
public InputStream openInputStream() {
if (!canInputStream()) {
throw new IllegalStateException("Schema "+sourceDescription+" cannot provide input stream");
}
return streamable.openInputStream();
}

@Override
public Source getSource() {
Source source;
if (canInputStream()) {
Expand All @@ -150,6 +164,7 @@ public Source getSource() {
return source;
}

@Override
public Element getDomElement() {
if (node instanceof Element) {
return (Element)node;
Expand Down Expand Up @@ -191,4 +206,12 @@ protected void performFreeze() {
", schema=" + schema +
'}';
}

public void setDefaultPrefix(String prefix) {
this.defaultPrefix = prefix;
}

public String getDefaultPrefix() {
return defaultPrefix;
}
}
Expand Up @@ -9,21 +9,23 @@

import com.evolveum.midpoint.prism.schema.SchemaDescription;
import com.evolveum.midpoint.prism.schema.SchemaRegistry;
import com.evolveum.midpoint.util.Checks;
import com.evolveum.midpoint.util.DOMUtil;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.exception.SystemException;
import com.evolveum.midpoint.util.exception.TunnelException;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

import javax.xml.namespace.QName;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import static com.evolveum.midpoint.prism.PrismConstants.*;
/**
* Parser for SchemaDescription objects. TODO Rework, along with SchemaDescriptionImpl.
*/
Expand Down Expand Up @@ -142,15 +144,18 @@ static SchemaDescriptionImpl parseNode(Node node, String sourceDescription) thro

private static void fetchBasicInfoFromSchema(SchemaDescriptionImpl desc) throws SchemaException {
Element rootElement = desc.getDomElement();
if (DOMUtil.XSD_SCHEMA_ELEMENT.equals(DOMUtil.getQName(rootElement))) {
String targetNamespace = DOMUtil.getAttribute(rootElement, DOMUtil.XSD_ATTR_TARGET_NAMESPACE);
if (targetNamespace != null) {
desc.setNamespace(targetNamespace);
} else {
throw new SchemaException("Schema " + desc.getSourceDescription() + " does not have targetNamespace attribute");
Checks.checkSchema(DOMUtil.XSD_SCHEMA_ELEMENT.equals(DOMUtil.getQName(rootElement)), "Schema %s does not start with xsd:schema element", desc.getSourceDescription());
String targetNamespace = DOMUtil.getAttribute(rootElement, DOMUtil.XSD_ATTR_TARGET_NAMESPACE);
Checks.checkSchemaNotNull(targetNamespace, "Schema %s does not have targetNamespace attribute", desc.getSourceDescription());
desc.setNamespace(targetNamespace);
Optional<Element> defaultPrefixElem = DOMUtil.getElement(rootElement, SCHEMA_ANNOTATION, SCHEMA_APP_INFO, A_DEFAULT_PREFIX);
if(defaultPrefixElem.isPresent()) {
String defaultPrefix = defaultPrefixElem.get().getTextContent().strip();
if(!defaultPrefix.isEmpty()) {
desc.setDefaultPrefix(defaultPrefix);
}
} else {
throw new SchemaException("Schema " + desc.getSourceDescription() + " does not start with xsd:schema element");

}

}
}

0 comments on commit 65cdc8a

Please sign in to comment.