Skip to content

Commit

Permalink
Cloning for XNodes.
Browse files Browse the repository at this point in the history
  • Loading branch information
mederly committed Nov 7, 2014
1 parent c96f38b commit 6e0aa89
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 9 deletions.
Expand Up @@ -19,6 +19,11 @@

import javax.xml.namespace.QName;

import com.evolveum.midpoint.prism.parser.PrismBeanConverter;
import com.evolveum.midpoint.prism.util.CloneUtil;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import org.apache.commons.lang.StringUtils;

import com.evolveum.midpoint.prism.Visitor;
Expand All @@ -30,6 +35,8 @@
import com.evolveum.midpoint.util.exception.SchemaException;

public class PrimitiveXNode<T> extends XNode implements Serializable {

private static final Trace LOGGER = TraceManager.getTrace(PrimitiveXNode.class);

private T value;
private ValueParser<T> valueParser;
Expand Down Expand Up @@ -269,4 +276,37 @@ public int hashCode() {
}
return objectToHash != null ? objectToHash.hashCode() : 0;
}

PrimitiveXNode cloneInternal() {

PrimitiveXNode clone;
if (value != null) {
// if we are parsed, things are much simpler
clone = new PrimitiveXNode(CloneUtil.clone(getValue()));
} else {
// !!! DANGEROUS. UGLY HACKING. !!!
//
// ValueParser declares it is serializable, but in reality it depends e.g. on the DOM implementation in use.
// And JSON parser is not serializable at all.
clone = new PrimitiveXNode();
if (valueParser instanceof Serializable || valueParser instanceof Cloneable) {
try {
clone.valueParser = CloneUtil.clone(valueParser);
} catch (Throwable t) {
// Nasty "solution". Actually, by not cloning value parser we will probably not do much harm, but one never knows.
// TODO consider eliminating this hack.
LoggingUtils.logException(LOGGER, "Error when cloning value parser - using original, uncloned value: {}", t, valueParser);
clone.valueParser = valueParser;
//throw t; // useful when testing, not for production
}
} else {
LOGGER.warn("Parser of type {} cannot be cloned; proceeding with original uncloned value.", valueParser!=null?valueParser.getClass():"(null)");
clone.valueParser = valueParser;
}
}

clone.isAttribute = this.isAttribute;
clone.copyCommonAttributesFrom(this);
return clone;
}
}
Expand Up @@ -144,32 +144,41 @@ public XNode clone() {
public XNode cloneTransformKeys(Transformer<QName,QName> keyTransformer) {
return cloneTransformKeys(keyTransformer, this);
}

private <X extends XNode> X cloneTransformKeys(Transformer<QName,QName> keyTransformer, X xnode) {

private static <X extends XNode> X cloneTransformKeys(Transformer<QName,QName> keyTransformer, X xnode) {
XNode xclone;
if (xnode instanceof PrimitiveXNode<?>) {
return xnode;
return (X) ((PrimitiveXNode) xnode).cloneInternal();
} else if (xnode instanceof MapXNode) {
MapXNode xmap = (MapXNode)xnode;
MapXNode xclone = new MapXNode();
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);
xclone.put(newKey, newValue);
((MapXNode) xclone).put(newKey, newValue);
}
}
return (X) xclone;
} else if (xnode instanceof ListXNode) {
ListXNode xclone = new ListXNode();
xclone = new ListXNode();
for (XNode xsubnode: ((ListXNode)xnode)) {
xclone.add(cloneTransformKeys(keyTransformer, xsubnode));
((ListXNode) xclone).add(cloneTransformKeys(keyTransformer, xsubnode));
}
return (X) xclone;
} 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
Expand Down
Expand Up @@ -24,6 +24,8 @@
import java.util.ArrayList;
import java.util.Collection;

import com.evolveum.midpoint.prism.xnode.MapXNode;
import com.evolveum.prism.xml.ns._public.types_3.RawType;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
import org.xml.sax.SAXException;
Expand All @@ -40,6 +42,8 @@
import com.evolveum.midpoint.util.PrettyPrinter;
import com.evolveum.midpoint.util.exception.SchemaException;

import javax.xml.namespace.QName;

/**
* @author Radovan Semancik
*
Expand Down Expand Up @@ -83,4 +87,20 @@ public void testPrismValueContainsRealValue() throws Exception {
assert !PrismValue.containsRealValue(collection, valBaz);
}

@Test
public void testRawTypeClone() throws Exception {
System.out.println("\n\n===[ testRawTypeClone ]===\n");
// GIVEN
QName typeQName = new QName("abcdef");
MapXNode mapXNode = new MapXNode();
mapXNode.setTypeQName(typeQName);
RawType rawType = new RawType(mapXNode, PrismTestUtil.getPrismContext());

// WHEN
RawType rawTypeClone = rawType.clone();

// THEN
assertEquals("Wrong or missing type QName", typeQName, rawTypeClone.getXnode().getTypeQName());
}

}

0 comments on commit 6e0aa89

Please sign in to comment.