/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.commons.jxpath.ri.model.beans;
import org.apache.commons.jxpath.AbstractFactory;
import org.apache.commons.jxpath.JXPathAbstractFactoryException;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.JXPathInvalidAccessException;
import org.apache.commons.jxpath.ri.QName;
import org.apache.commons.jxpath.ri.model.NodePointer;
/**
* @author Dmitri Plotnikov
* @version $Revision: 652884 $ $Date: 2008-05-02 15:02:00 -0500 (Fri, 02 May 2008) $
*/
public class NullPropertyPointer extends PropertyPointer {
private String propertyName = "*";
private boolean byNameAttribute = false;
private static final long serialVersionUID = 5296593071854982754L;
/**
* Create a new NullPropertyPointer.
* @param parent pointer
*/
public NullPropertyPointer(NodePointer parent) {
super(parent);
}
public QName getName() {
return new QName(propertyName);
}
public void setPropertyIndex(int index) {
}
public int getLength() {
return 0;
}
public Object getBaseValue() {
return null;
}
public Object getImmediateNode() {
return null;
}
public boolean isLeaf() {
return true;
}
public NodePointer getValuePointer() {
return new NullPointer(this, new QName(getPropertyName()));
}
protected boolean isActualProperty() {
return false;
}
public boolean isActual() {
return false;
}
public boolean isContainer() {
return true;
}
public void setValue(Object value) {
if (parent == null || parent.isContainer()) {
throw new JXPathInvalidAccessException(
"Cannot set property "
+ asPath()
+ ", the target object is null");
}
if (parent instanceof PropertyOwnerPointer
&& ((PropertyOwnerPointer) parent)
.isDynamicPropertyDeclarationSupported()) {
// If the parent property owner can create
// a property automatically - let it do so
PropertyPointer propertyPointer =
((PropertyOwnerPointer) parent).getPropertyPointer();
propertyPointer.setPropertyName(propertyName);
propertyPointer.setValue(value);
}
else {
throw new JXPathInvalidAccessException(
"Cannot set property "
+ asPath()
+ ", path does not match a changeable location");
}
}
public NodePointer createPath(JXPathContext context) {
NodePointer newParent = parent.createPath(context);
if (isAttribute()) {
return newParent.createAttribute(context, getName());
}
if (parent instanceof NullPointer && parent.equals(newParent)) {
throw createBadFactoryException(context.getFactory());
}
// Consider these two use cases:
// 1. The parent pointer of NullPropertyPointer is
// a PropertyOwnerPointer other than NullPointer. When we call
// createPath on it, it most likely returns itself. We then
// take a PropertyPointer from it and get the PropertyPointer
// to expand the collection for the corresponding property.
//
// 2. The parent pointer of NullPropertyPointer is a NullPointer.
// When we call createPath, it may return a PropertyOwnerPointer
// or it may return anything else, like a DOMNodePointer.
// In the former case we need to do exactly what we did in use
// case 1. In the latter case, we simply request that the
// non-property pointer expand the collection by itself.
if (newParent instanceof PropertyOwnerPointer) {
PropertyOwnerPointer pop = (PropertyOwnerPointer) newParent;
newParent = pop.getPropertyPointer();
}
return newParent.createChild(context, getName(), getIndex());
}
public NodePointer createPath(JXPathContext context, Object value) {
NodePointer newParent = parent.createPath(context);
if (isAttribute()) {
NodePointer pointer = newParent.createAttribute(context, getName());
pointer.setValue(value);
return pointer;
}
if (parent instanceof NullPointer && parent.equals(newParent)) {
throw createBadFactoryException(context.getFactory());
}
if (newParent instanceof PropertyOwnerPointer) {
PropertyOwnerPointer pop = (PropertyOwnerPointer) newParent;
newParent = pop.getPropertyPointer();
}
return newParent.createChild(context, getName(), index, value);
}
public NodePointer createChild(JXPathContext context, QName name, int index) {
return createPath(context).createChild(context, name, index);
}
public NodePointer createChild(JXPathContext context, QName name,
int index, Object value) {
return createPath(context).createChild(context, name, index, value);
}
public String getPropertyName() {
return propertyName;
}
public void setPropertyName(String propertyName) {
this.propertyName = propertyName;
}
/**
* Set the name attribute.
* @param attributeValue value to set
*/
public void setNameAttributeValue(String attributeValue) {
this.propertyName = attributeValue;
byNameAttribute = true;
}
public boolean isCollection() {
return getIndex() != WHOLE_COLLECTION;
}
public int getPropertyCount() {
return 0;
}
public String[] getPropertyNames() {
return new String[0];
}
public String asPath() {
if (!byNameAttribute) {
return super.asPath();
}
StringBuffer buffer = new StringBuffer();
buffer.append(getImmediateParentPointer().asPath());
buffer.append("[@name='");
buffer.append(escape(getPropertyName()));
buffer.append("']");
if (index != WHOLE_COLLECTION) {
buffer.append('[').append(index + 1).append(']');
}
return buffer.toString();
}
/**
* Create a "bad factory" JXPathAbstractFactoryException for the specified AbstractFactory.
* @param factory AbstractFactory
* @return JXPathAbstractFactoryException
*/
private JXPathAbstractFactoryException createBadFactoryException(AbstractFactory factory) {
return new JXPathAbstractFactoryException("Factory " + factory
+ " reported success creating object for path: " + asPath()
+ " but object was null. Terminating to avoid stack recursion.");
}
}
|