/* * Copyright (c) 2014 Evolveum * * Licensed 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 com.evolveum.midpoint.prism.xnode; import java.io.File; import java.io.Serializable; import java.util.Map.Entry; import javax.xml.namespace.QName; import com.evolveum.midpoint.prism.Visitable; import com.evolveum.midpoint.prism.Visitor; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.Transformer; /** * @author semancik * */ public abstract class XNode implements DebugDumpable, Visitable, Cloneable, Serializable { public static final QName KEY_OID = new QName(null, "oid"); public static final QName KEY_VERSION = new QName(null, "version"); public static final QName KEY_CONTAINER_ID = new QName(null, "id"); public static final QName KEY_REFERENCE_OID = new QName(null, "oid"); public static final QName KEY_REFERENCE_TYPE = new QName(null, "type"); public static final QName KEY_REFERENCE_RELATION = new QName(null, "relation"); public static final QName KEY_REFERENCE_DESCRIPTION = new QName(null, "description"); public static final QName KEY_REFERENCE_FILTER = new QName(null, "filter"); public static final QName KEY_REFERENCE_RESOLUTION_TIME = new QName(null, "resolutionTime"); public static final QName KEY_REFERENCE_TARGET_NAME = new QName(null, "targetName"); public static final QName KEY_REFERENCE_OBJECT = new QName(null, "object"); public static final QName DUMMY_NAME = new QName(null, "dummy"); // Common fields protected XNode parent; /** * If set to true that the element came from the explicit type definition * (e.g. xsi:type in XML) on the parsing side; or that it the explicit type * definition should be included on the serialization side. */ private boolean explicitTypeDeclaration = false; // These are set when parsing a file private File originFile; private String originDescription; private int lineNumber; // These may be detected in parsed file and are also used for serialization protected QName typeQName; protected QName elementName; // Filled if and only if this is a member of heterogeneous list. protected Integer maxOccurs; // a comment that could be stored into formats that support these (e.g. XML or YAML) private String comment; public XNode getParent() { return parent; } public void setParent(XNode parent) { this.parent = parent; } public File getOriginFile() { return originFile; } public void setOriginFile(File originFile) { this.originFile = originFile; } public String getOriginDescription() { return originDescription; } public void setOriginDescription(String originDescription) { this.originDescription = originDescription; } public int getLineNumber() { return lineNumber; } public void setLineNumber(int lineNumber) { this.lineNumber = lineNumber; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public QName getTypeQName() { return typeQName; } public void setTypeQName(QName typeQName) { this.typeQName = typeQName; } public QName getElementName() { return elementName; } public void setElementName(QName elementName) { this.elementName = elementName; } public Integer getMaxOccurs() { return maxOccurs; } public void setMaxOccurs(Integer maxOccurs) { this.maxOccurs = maxOccurs; } public abstract boolean isEmpty(); public boolean isExplicitTypeDeclaration() { return explicitTypeDeclaration; } public void setExplicitTypeDeclaration(boolean explicitTypeDeclaration) { this.explicitTypeDeclaration = explicitTypeDeclaration; } public abstract void accept(Visitor visitor); public XNode clone() { return cloneTransformKeys(null); } public XNode cloneTransformKeys(Transformer<QName,QName> keyTransformer) { return cloneTransformKeys(keyTransformer, this); } private static <X extends XNode> X cloneTransformKeys(Transformer<QName,QName> keyTransformer, X xnode) { XNode xclone; if (xnode == null) { return null; } else if (xnode instanceof PrimitiveXNode<?>) { return (X) ((PrimitiveXNode) xnode).cloneInternal(); } else if (xnode instanceof MapXNode) { MapXNode xmap = (MapXNode)xnode; xclone = new MapXNode(); for (Entry<QName,XNode> entry: xmap.entrySet()) { QName key = entry.getKey(); QName newKey = keyTransformer != null ? keyTransformer.transform(key) : key; if (newKey != null) { XNode value = entry.getValue(); XNode newValue = cloneTransformKeys(keyTransformer, value); ((MapXNode) xclone).put(newKey, newValue); } } } else if (xnode instanceof ListXNode) { xclone = new ListXNode(); for (XNode xsubnode: ((ListXNode)xnode)) { ((ListXNode) xclone).add(cloneTransformKeys(keyTransformer, xsubnode)); } } else if (xnode instanceof RootXNode) { xclone = new RootXNode(((RootXNode) xnode).getRootElementName(), cloneTransformKeys(keyTransformer, ((RootXNode) xnode).getSubnode())); } else { throw new IllegalArgumentException("Unknown xnode "+xnode); } xclone.copyCommonAttributesFrom(xnode); return (X) xclone; } // filling-in other properties (we skip parent and origin-related things) protected void copyCommonAttributesFrom(XNode xnode) { explicitTypeDeclaration = xnode.explicitTypeDeclaration; setTypeQName(xnode.getTypeQName()); setComment(xnode.getComment()); setMaxOccurs(xnode.getMaxOccurs()); } @Override public String debugDump() { return debugDump(0); } public abstract String getDesc(); protected String dumpSuffix() { StringBuilder sb = new StringBuilder(); if (elementName != null) { sb.append(" element=").append(elementName); } if (typeQName != null) { sb.append(" type=").append(typeQName); } if (maxOccurs != null) { sb.append(" maxOccurs=").append(maxOccurs); } return sb.toString(); } // overriden in RootXNode public RootXNode toRootXNode() { return new RootXNode(XNode.DUMMY_NAME, this); } public boolean isHeterogeneousList() { return false; } }