001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jxpath.ri.model.beans;
017:
018: import java.util.Locale;
019:
020: import org.apache.commons.jxpath.JXPathException;
021: import org.apache.commons.jxpath.ri.Compiler;
022: import org.apache.commons.jxpath.ri.QName;
023: import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
024: import org.apache.commons.jxpath.ri.compiler.NodeTest;
025: import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
026: import org.apache.commons.jxpath.ri.model.NodeIterator;
027: import org.apache.commons.jxpath.ri.model.NodePointer;
028: import org.apache.commons.jxpath.util.ValueUtils;
029:
030: /**
031: * A pointer describing a node that has properties, each of which could be
032: * a collection.
033: *
034: * @author Dmitri Plotnikov
035: * @version $Revision: 1.19 $ $Date: 2004/04/04 22:06:36 $
036: */
037: public abstract class PropertyOwnerPointer extends NodePointer {
038:
039: public NodeIterator childIterator(NodeTest test, boolean reverse,
040: NodePointer startWith) {
041: if (test == null) {
042: return createNodeIterator(null, reverse, startWith);
043: } else if (test instanceof NodeNameTest) {
044: NodeNameTest nodeNameTest = (NodeNameTest) test;
045: QName testName = nodeNameTest.getNodeName();
046: String property;
047: if (!isDefaultNamespace(testName.getPrefix())) {
048: return null;
049: } else if (nodeNameTest.isWildcard()) {
050: property = null;
051: } else {
052: property = testName.getName();
053: }
054: return createNodeIterator(property, reverse, startWith);
055: } else if (test instanceof NodeTypeTest) {
056: if (((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_NODE) {
057: return createNodeIterator(null, reverse, startWith);
058: }
059: }
060: return null;
061: }
062:
063: public NodeIterator createNodeIterator(String property,
064: boolean reverse, NodePointer startWith) {
065: return new PropertyIterator(this , property, reverse, startWith);
066: }
067:
068: public NodeIterator attributeIterator(QName name) {
069: return new BeanAttributeIterator(this , name);
070: }
071:
072: protected PropertyOwnerPointer(NodePointer parent, Locale locale) {
073: super (parent, locale);
074: }
075:
076: protected PropertyOwnerPointer(NodePointer parent) {
077: super (parent);
078: }
079:
080: public void setIndex(int index) {
081: if (this .index != index) {
082: super .setIndex(index);
083: value = UNINITIALIZED;
084: }
085: }
086:
087: private static final Object UNINITIALIZED = new Object();
088:
089: private Object value = UNINITIALIZED;
090:
091: public Object getImmediateNode() {
092: if (value == UNINITIALIZED) {
093: if (index == WHOLE_COLLECTION) {
094: value = ValueUtils.getValue(getBaseValue());
095: } else {
096: value = ValueUtils.getValue(getBaseValue(), index);
097: }
098: }
099: return value;
100: }
101:
102: public abstract QName getName();
103:
104: /**
105: * Throws an exception if you try to change the root element, otherwise
106: * forwards the call to the parent pointer.
107: */
108: public void setValue(Object value) {
109: this .value = value;
110: if (parent.isContainer()) {
111: parent.setValue(value);
112: } else if (parent != null) {
113: if (index == WHOLE_COLLECTION) {
114: throw new UnsupportedOperationException(
115: "Cannot setValue of an object that is not "
116: + "some other object's property");
117: } else {
118: throw new JXPathException(
119: "The specified collection element does not exist: "
120: + this );
121: }
122: } else {
123: throw new UnsupportedOperationException(
124: "Cannot replace the root object");
125: }
126: }
127:
128: /**
129: * If this is a root node pointer, throws an exception; otherwise
130: * forwards the call to the parent node.
131: */
132: public void remove() {
133: this .value = null;
134: if (parent != null) {
135: parent.remove();
136: } else {
137: throw new UnsupportedOperationException(
138: "Cannot remove an object that is not "
139: + "some other object's property or a collection element");
140: }
141: }
142:
143: public abstract PropertyPointer getPropertyPointer();
144:
145: /**
146: * @return true if the property owner can set a property "does not exist".
147: * A good example is a Map. You can always assign a value to any
148: * key even if it has never been "declared".
149: */
150: public boolean isDynamicPropertyDeclarationSupported() {
151: return false;
152: }
153:
154: public int compareChildNodePointers(NodePointer pointer1,
155: NodePointer pointer2) {
156: int r = pointer1.getName().toString().compareTo(
157: pointer2.getName().toString());
158: if (r != 0) {
159: return r;
160: }
161: return pointer1.getIndex() - pointer2.getIndex();
162: }
163: }
|