001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.jxpath.ri.model.beans; 018 019import java.util.Locale; 020 021import org.apache.commons.jxpath.JXPathContext; 022import org.apache.commons.jxpath.JXPathIntrospector; 023import org.apache.commons.jxpath.ri.Compiler; 024import org.apache.commons.jxpath.ri.QName; 025import org.apache.commons.jxpath.ri.compiler.NodeNameTest; 026import org.apache.commons.jxpath.ri.compiler.NodeTest; 027import org.apache.commons.jxpath.ri.compiler.NodeTypeTest; 028import org.apache.commons.jxpath.ri.model.NodeIterator; 029import org.apache.commons.jxpath.ri.model.NodePointer; 030import org.apache.commons.jxpath.util.ValueUtils; 031 032/** 033 * Transparent pointer to a collection (array or Collection). 034 * 035 * @author Dmitri Plotnikov 036 * @version $Revision: 668329 $ $Date: 2008-06-16 23:59:48 +0200 (Mo, 16 Jun 2008) $ 037 */ 038public class CollectionPointer extends NodePointer { 039 private Object collection; 040 private NodePointer valuePointer; 041 042 private static final long serialVersionUID = 8620254915563256588L; 043 044 /** 045 * Create a new CollectionPointer. 046 * @param collection value 047 * @param locale Locale 048 */ 049 public CollectionPointer(Object collection, Locale locale) { 050 super(null, locale); 051 this.collection = collection; 052 } 053 054 /** 055 * Create a new CollectionPointer. 056 * @param parent parent NodePointer 057 * @param collection value 058 */ 059 public CollectionPointer(NodePointer parent, Object collection) { 060 super(parent); 061 this.collection = collection; 062 } 063 064 public QName getName() { 065 return null; 066 } 067 068 public Object getBaseValue() { 069 return collection; 070 } 071 072 public boolean isCollection() { 073 return true; 074 } 075 076 public int getLength() { 077 return ValueUtils.getLength(getBaseValue()); 078 } 079 080 public boolean isLeaf() { 081 Object value = getNode(); 082 return value == null || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic(); 083 } 084 085 public boolean isContainer() { 086 return index != WHOLE_COLLECTION; 087 } 088 089 public Object getImmediateNode() { 090 return index == WHOLE_COLLECTION ? ValueUtils.getValue(collection) 091 : ValueUtils.getValue(collection, index); 092 } 093 094 public void setValue(Object value) { 095 if (index == WHOLE_COLLECTION) { 096 parent.setValue(value); 097 } 098 else { 099 ValueUtils.setValue(collection, index, value); 100 } 101 } 102 103 public void setIndex(int index) { 104 super.setIndex(index); 105 valuePointer = null; 106 } 107 108 public NodePointer getValuePointer() { 109 if (valuePointer == null) { 110 if (index == WHOLE_COLLECTION) { 111 valuePointer = this; 112 } 113 else { 114 Object value = getImmediateNode(); 115 valuePointer = 116 NodePointer.newChildNodePointer(this, getName(), value); 117 } 118 } 119 return valuePointer; 120 } 121 122 public NodePointer createPath(JXPathContext context) { 123 if (ValueUtils.getLength(getBaseValue()) <= index) { 124 collection = ValueUtils.expandCollection(getNode(), index + 1); 125 } 126 return this; 127 } 128 129 public NodePointer createPath(JXPathContext context, Object value) { 130 NodePointer ptr = createPath(context); 131 ptr.setValue(value); 132 return ptr; 133 } 134 135 public NodePointer createChild( 136 JXPathContext context, 137 QName name, 138 int index, 139 Object value) { 140 NodePointer ptr = (NodePointer) clone(); 141 ptr.setIndex(index); 142 return ptr.createPath(context, value); 143 } 144 145 public NodePointer createChild( 146 JXPathContext context, 147 QName name, 148 int index) { 149 NodePointer ptr = (NodePointer) clone(); 150 ptr.setIndex(index); 151 return ptr.createPath(context); 152 } 153 154 public int hashCode() { 155 return System.identityHashCode(collection) + index; 156 } 157 158 public boolean equals(Object object) { 159 if (object == this) { 160 return true; 161 } 162 163 if (!(object instanceof CollectionPointer)) { 164 return false; 165 } 166 167 CollectionPointer other = (CollectionPointer) object; 168 return collection == other.collection && index == other.index; 169 } 170 171 public NodeIterator childIterator(NodeTest test, 172 boolean reverse, NodePointer startWith) { 173 if (index == WHOLE_COLLECTION) { 174 return new CollectionChildNodeIterator( 175 this, 176 test, 177 reverse, 178 startWith); 179 } 180 return getValuePointer().childIterator(test, reverse, startWith); 181 } 182 183 public NodeIterator attributeIterator(QName name) { 184 return index == WHOLE_COLLECTION ? new CollectionAttributeNodeIterator(this, name) 185 : getValuePointer().attributeIterator(name); 186 } 187 188 public NodeIterator namespaceIterator() { 189 return index == WHOLE_COLLECTION ? null : getValuePointer().namespaceIterator(); 190 } 191 192 public NodePointer namespacePointer(String namespace) { 193 return index == WHOLE_COLLECTION ? null : getValuePointer().namespacePointer(namespace); 194 } 195 196 public boolean testNode(NodeTest test) { 197 if (index == WHOLE_COLLECTION) { 198 if (test == null) { 199 return true; 200 } 201 if (test instanceof NodeNameTest) { 202 return false; 203 } 204 return test instanceof NodeTypeTest && ((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_NODE; 205 } 206 return getValuePointer().testNode(test); 207 } 208 209 public int compareChildNodePointers( 210 NodePointer pointer1, NodePointer pointer2) { 211 return pointer1.getIndex() - pointer2.getIndex(); 212 } 213 214 public String asPath() { 215 StringBuffer buffer = new StringBuffer(); 216 NodePointer parent = getImmediateParentPointer(); 217 if (parent != null) { 218 buffer.append(parent.asPath()); 219 if (index != WHOLE_COLLECTION) { 220 // Address the list[1][2] case 221 if (parent.getIndex() != WHOLE_COLLECTION) { 222 buffer.append("/."); 223 } 224 buffer.append("[").append(index + 1).append(']'); 225 } 226 } 227 else { 228 if (index != WHOLE_COLLECTION) { 229 buffer.append("/.[").append(index + 1).append(']'); 230 } 231 else { 232 buffer.append("/"); 233 } 234 } 235 return buffer.toString(); 236 } 237}