1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.jxpath.ri.model.beans;
  17. import java.util.Locale;
  18. import org.apache.commons.jxpath.JXPathContext;
  19. import org.apache.commons.jxpath.JXPathIntrospector;
  20. import org.apache.commons.jxpath.ri.QName;
  21. import org.apache.commons.jxpath.ri.compiler.NodeTest;
  22. import org.apache.commons.jxpath.ri.model.NodeIterator;
  23. import org.apache.commons.jxpath.ri.model.NodePointer;
  24. import org.apache.commons.jxpath.util.ValueUtils;
  25. /**
  26. * Transparent pointer to a collection (array or Collection).
  27. *
  28. * @author Dmitri Plotnikov
  29. * @version $Revision: 1.19 $ $Date: 2004/04/04 22:06:35 $
  30. */
  31. public class CollectionPointer extends NodePointer {
  32. private Object collection;
  33. private NodePointer valuePointer;
  34. public CollectionPointer(Object collection, Locale locale) {
  35. super(null, locale);
  36. this.collection = collection;
  37. }
  38. public CollectionPointer(NodePointer parent, Object collection) {
  39. super(parent);
  40. this.collection = collection;
  41. }
  42. public QName getName() {
  43. return null;
  44. }
  45. public Object getBaseValue() {
  46. return collection;
  47. }
  48. public boolean isCollection() {
  49. return true;
  50. }
  51. public int getLength() {
  52. return ValueUtils.getLength(getBaseValue());
  53. }
  54. public boolean isLeaf() {
  55. Object value = getNode();
  56. return value == null
  57. || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic();
  58. }
  59. public boolean isContainer() {
  60. return index != WHOLE_COLLECTION;
  61. }
  62. public Object getImmediateNode() {
  63. if (index != WHOLE_COLLECTION) {
  64. return ValueUtils.getValue(collection, index);
  65. }
  66. else {
  67. return ValueUtils.getValue(collection);
  68. }
  69. }
  70. public void setValue(Object value) {
  71. if (index == WHOLE_COLLECTION) {
  72. parent.setValue(value);
  73. }
  74. else {
  75. ValueUtils.setValue(collection, index, value);
  76. }
  77. }
  78. public void setIndex(int index) {
  79. super.setIndex(index);
  80. valuePointer = null;
  81. }
  82. public NodePointer getValuePointer() {
  83. if (valuePointer == null) {
  84. if (index == WHOLE_COLLECTION) {
  85. valuePointer = this;
  86. }
  87. else {
  88. Object value = getImmediateNode();
  89. valuePointer =
  90. NodePointer.newChildNodePointer(this, getName(), value);
  91. }
  92. }
  93. return valuePointer;
  94. }
  95. public NodePointer createPath(JXPathContext context) {
  96. Object collection = getBaseValue();
  97. if (ValueUtils.getLength(collection) <= index) {
  98. collection = ValueUtils.expandCollection(getNode(), index + 1);
  99. }
  100. return this;
  101. }
  102. public NodePointer createPath(JXPathContext context, Object value) {
  103. NodePointer ptr = createPath(context);
  104. ptr.setValue(value);
  105. return ptr;
  106. }
  107. public NodePointer createChild(
  108. JXPathContext context,
  109. QName name,
  110. int index,
  111. Object value)
  112. {
  113. NodePointer ptr = (NodePointer) clone();
  114. ptr.setIndex(index);
  115. return ptr.createPath(context, value);
  116. }
  117. public NodePointer createChild(
  118. JXPathContext context,
  119. QName name,
  120. int index)
  121. {
  122. NodePointer ptr = (NodePointer) clone();
  123. ptr.setIndex(index);
  124. return ptr.createPath(context);
  125. }
  126. public int hashCode() {
  127. return System.identityHashCode(collection) + index;
  128. }
  129. public boolean equals(Object object) {
  130. if (object == this) {
  131. return true;
  132. }
  133. if (!(object instanceof CollectionPointer)) {
  134. return false;
  135. }
  136. CollectionPointer other = (CollectionPointer) object;
  137. return collection == other.collection && index == other.index;
  138. }
  139. public NodeIterator childIterator(NodeTest test,
  140. boolean reverse, NodePointer startWith)
  141. {
  142. if (index == WHOLE_COLLECTION) {
  143. return new CollectionChildNodeIterator(
  144. this,
  145. test,
  146. reverse,
  147. startWith);
  148. }
  149. else {
  150. return getValuePointer().childIterator(test, reverse, startWith);
  151. }
  152. }
  153. public NodeIterator attributeIterator(QName name) {
  154. if (index == WHOLE_COLLECTION) {
  155. return new CollectionAttributeNodeIterator(this, name);
  156. }
  157. return getValuePointer().attributeIterator(name);
  158. }
  159. public NodeIterator namespaceIterator() {
  160. if (index == WHOLE_COLLECTION) {
  161. return null;
  162. }
  163. return getValuePointer().namespaceIterator();
  164. }
  165. public NodePointer namespacePointer(String namespace) {
  166. if (index == WHOLE_COLLECTION) {
  167. return null;
  168. }
  169. return getValuePointer().namespacePointer(namespace);
  170. }
  171. public boolean testNode(NodeTest nodeTest) {
  172. // if (index
  173. /** @todo: infinite loop here */
  174. return getValuePointer().testNode(nodeTest);
  175. }
  176. public int compareChildNodePointers(
  177. NodePointer pointer1, NodePointer pointer2)
  178. {
  179. return pointer1.getIndex() - pointer2.getIndex();
  180. }
  181. /**
  182. * Returns an XPath that maps to this Pointer.
  183. */
  184. public String asPath() {
  185. StringBuffer buffer = new StringBuffer();
  186. NodePointer parent = getImmediateParentPointer();
  187. if (parent != null) {
  188. buffer.append(parent.asPath());
  189. if (index != WHOLE_COLLECTION) {
  190. // Address the list[1][2] case
  191. if (parent.getIndex() != WHOLE_COLLECTION) {
  192. buffer.append("/.");
  193. }
  194. buffer.append("[").append(index + 1).append(']');
  195. }
  196. }
  197. else {
  198. if (index != WHOLE_COLLECTION) {
  199. buffer.append("/.[").append(index + 1).append(']');
  200. }
  201. else {
  202. buffer.append("/");
  203. }
  204. }
  205. return buffer.toString();
  206. }
  207. }