
org.xmlbeam.AutoValue Maven / Gradle / Ivy
/**
* Copyright 2016 Sven Ewald
*
* 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 org.xmlbeam;
import java.util.Iterator;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import org.w3c.dom.Attr;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xmlbeam.dom.DOMAccess;
import org.xmlbeam.evaluation.DefaultXPathEvaluator;
import org.xmlbeam.evaluation.InvocationContext;
import org.xmlbeam.types.XBAutoValue;
import org.xmlbeam.util.intern.DOMHelper;
/**
*
*/
class AutoValue implements XBAutoValue {
private final InvocationContext invocationContext;
private Node dataNode;
private Node baseNode = null;
// private Element parent;
private final DomChangeTracker domChangeTracker = new DomChangeTracker() {
@Override
void refresh(final boolean forWrite) throws XPathExpressionException {
final NodeList nodes = (NodeList) invocationContext.getxPathExpression().evaluate(baseNode, XPathConstants.NODESET);;
if ((nodes.getLength() == 0) && forWrite) {
// parent = invocationContext.getDuplexExpression().ensureParentExistence(baseNode);
dataNode = invocationContext.getDuplexExpression().ensureExistence(baseNode);
return;
} else {
// parent = nodes.getLength() == 0 ? null : (Element) nodes.item(0).getParentNode();
}
dataNode = nodes.getLength() == 0 ? null : nodes.item(0);
}
};
/**
* @param baseNode
* @param invocationContext
*/
public AutoValue(final Node baseNode, final InvocationContext invocationContext) {
this.baseNode = baseNode;
this.invocationContext = invocationContext;
invocationContext.getProjector().addDOMChangeListener(domChangeTracker);
}
@Override
public E get() {
domChangeTracker.refreshForReadIfNeeded();
if (dataNode == null) {
return null;
}
return DefaultXPathEvaluator.convertToComponentType(invocationContext, dataNode, invocationContext.getTargetComponentType());
}
@Override
public E set(final E element) {
if (dataNode == null) {
domChangeTracker.domChanged();
}
domChangeTracker.refreshForReadIfNeeded();
Node prevNode = dataNode;
// domChangeTracker.refreshForWriteIfNeeded();
E result = DefaultXPathEvaluator.convertToComponentType(invocationContext, prevNode, invocationContext.getTargetComponentType());
Node oldNode = dataNode;
domChangeTracker.domChanged();
domChangeTracker.refreshForWriteIfNeeded();
if (element instanceof Node) {
Node newNode = ((Node) element).cloneNode(true);
oldNode.getParentNode().replaceChild(oldNode, newNode);
dataNode = newNode;
return result;
}
if (element instanceof DOMAccess) {
Node newNode = ((DOMAccess) element).getDOMBaseElement().cloneNode(true);
oldNode.getParentNode().replaceChild(oldNode, newNode);
dataNode = newNode;
return result;
}
final String asString = invocationContext.getProjector().config().getStringRenderer().render(element.getClass(), element, invocationContext.getDuplexExpression().getExpressionFormatPattern());
dataNode.setTextContent(asString);
return result;
}
@Override
public E remove() {
// refresh done in get()
//domChangeTracker.refreshForReadIfNeeded();
E oldValue = get();
if (dataNode == null) {
return oldValue;
}
if (dataNode.getNodeType() == Node.ATTRIBUTE_NODE) {
DOMHelper.removeAttribute((Attr) dataNode);
dataNode = null;
return oldValue;
}
if (dataNode.getParentNode() == null) {
return oldValue;
}
DOMHelper.trim(dataNode);
dataNode.getParentNode().removeChild(dataNode);
dataNode = null;
return oldValue;
}
@Override
public boolean isPresent() {
domChangeTracker.refreshForReadIfNeeded();
return dataNode != null;
}
@Override
public Iterator iterator() {
return new Iterator() {
boolean read = !(isPresent());
@Override
public boolean hasNext() {
return (!read) && (isPresent());
}
@Override
public E next() {
if (read) {
throw new IllegalStateException();
}
read = true;
return get();
}
@Override
public void remove() {
if ((!read) || (!isPresent())) {
throw new IllegalStateException();
}
AutoValue.this.remove();
}
};
}
@Override
public XBAutoValue rename(final String newName) {
domChangeTracker.domChanged();
domChangeTracker.refreshForWriteIfNeeded();
if (dataNode == null) {
throw new IllegalStateException("Can not rename when no value is present.");
}
dataNode = DOMHelper.renameNode(dataNode, newName);
domChangeTracker.domChanged();
return this;
}
@Override
public String getName() {
domChangeTracker.refreshForReadIfNeeded();
if (dataNode == null) {
throw new IllegalStateException("No value is present.");
}
return dataNode.getNodeName();
}
Node getNode() {
domChangeTracker.refreshForReadIfNeeded();
return dataNode;
}
@Override
public boolean equals(final Object o) {
if (!isPresent()) {
return false;
}
E e = get();
if (e == null) {
return false;
}
return e.equals(o);
}
@Override
public int hashCode() {
if (!isPresent()) {
return 0;
}
E e = get();
if (e == null) {
return 0;
}
return get().hashCode();
}
/**
* @param defaultValue
* @return isPresent() ? get() : defaultValue
* @see org.xmlbeam.types.XBAutoValue#getOrDefault(java.lang.Object)
*/
@Override
public E getOrDefault(E defaultValue) {
return isPresent() ? get() : defaultValue;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy