    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
    18  import java.util.Locale;
    19
    20  import org.apache.commons.jxpath.JXPathException;
    21  import org.apache.commons.jxpath.ri.Compiler;
    22  import org.apache.commons.jxpath.ri.QName;
    23  import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
    24  import org.apache.commons.jxpath.ri.compiler.NodeTest;
    25  import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
    26  import org.apache.commons.jxpath.ri.model.NodeIterator;
    27  import org.apache.commons.jxpath.ri.model.NodePointer;
    28  import org.apache.commons.jxpath.util.ValueUtils;
    29
    30  /***
    31   * A pointer describing a node that has properties, each of which could be
    32   * a collection.
    33   *
    34   * @author Dmitri Plotnikov
    35   * @version $Revision: 1.19 $ $Date: 2004/04/04 22:06:36 $
    36   */
    37  public abstract class PropertyOwnerPointer extends NodePointer {
    38
    39      public NodeIterator childIterator(
    40          NodeTest test,
    41          boolean reverse,
    42          NodePointer startWith)
    43      {
    44          if (test == null) {
    45              return createNodeIterator(null, reverse, startWith);
    46          }
    47          else if (test instanceof NodeNameTest) {
    48              NodeNameTest nodeNameTest = (NodeNameTest) test;
    49              QName testName = nodeNameTest.getNodeName();
    50              String property;
    51              if (!isDefaultNamespace(testName.getPrefix())) {
    52                  return null;
    53              }
    54              else if (nodeNameTest.isWildcard()) {
    55                  property = null;
    56              }
    57              else {
    58                  property = testName.getName();
    59              }
    60              return createNodeIterator(property, reverse, startWith);
    61          }
    62          else if (test instanceof NodeTypeTest) {
    63              if (((NodeTypeTest) test).getNodeType()
    64                  == Compiler.NODE_TYPE_NODE) {
    65                  return createNodeIterator(null, reverse, startWith);
    66              }
    67          }
    68          return null;
    69      }
    70
    71      public NodeIterator createNodeIterator(
    72                  String property,
    73                  boolean reverse,
    74                  NodePointer startWith)
    75      {
    76          return new PropertyIterator(this, property, reverse, startWith);
    77      }
    78
    79      public NodeIterator attributeIterator(QName name) {
    80          return new BeanAttributeIterator(this, name);
    81      }
    82
    83      protected PropertyOwnerPointer(NodePointer parent, Locale locale) {
    84          super(parent, locale);
    85      }
    86
    87      protected PropertyOwnerPointer(NodePointer parent) {
    88          super(parent);
    89      }
    90
    91      public void setIndex(int index) {
    92          if (this.index != index) {
    93              super.setIndex(index);
    94              value = UNINITIALIZED;
    95          }
    96      }
    97
    98      private static final Object UNINITIALIZED = new Object();
    99
    100     private Object value = UNINITIALIZED;
    101     public Object getImmediateNode() {
    102         if (value == UNINITIALIZED) {
    103             if (index == WHOLE_COLLECTION) {
    104                 value = ValueUtils.getValue(getBaseValue());
    105             }
    106             else {
    107                 value = ValueUtils.getValue(getBaseValue(), index);
    108             }
    109         }
    110         return value;
    111     }
    112
    113     public abstract QName getName();
    114
    115     /***
    116      * Throws an exception if you try to change the root element, otherwise
    117      * forwards the call to the parent pointer.
    118      */
    119     public void setValue(Object value) {
    120         this.value = value;
    121         if (parent.isContainer()) {
    122             parent.setValue(value);
    123         }
    124         else if (parent != null) {
    125             if (index == WHOLE_COLLECTION) {
    126                 throw new UnsupportedOperationException(
    127                     "Cannot setValue of an object that is not "
    128                         + "some other object's property");
    129             }
    130             else {
    131                 throw new JXPathException(
    132                     "The specified collection element does not exist: " + this);
    133             }
    134         }
    135         else {
    136             throw new UnsupportedOperationException(
    137                 "Cannot replace the root object");
    138         }
    139     }
    140
    141     /***
    142      * If this is a root node pointer, throws an exception; otherwise
    143      * forwards the call to the parent node.
    144      */
    145     public void remove() {
    146         this.value = null;
    147         if (parent != null) {
    148             parent.remove();
    149         }
    150         else {
    151             throw new UnsupportedOperationException(
    152                 "Cannot remove an object that is not "
    153                     + "some other object's property or a collection element");
    154         }
    155     }
    156
    157     public abstract PropertyPointer getPropertyPointer();
    158
    159     /***
    160      * @return true if the property owner can set a property "does not exist".
    161      *         A good example is a Map. You can always assign a value to any
    162      *         key even if it has never been "declared".
    163      */
    164     public boolean isDynamicPropertyDeclarationSupported() {
    165         return false;
    166     }
    167
    168     public int compareChildNodePointers(
    169         NodePointer pointer1,
    170         NodePointer pointer2)
    171     {
    172         int r =
    173             pointer1.getName().toString().compareTo(
    174                 pointer2.getName().toString());
    175         if (r != 0) {
    176             return r;
    177         }
    178         return pointer1.getIndex() - pointer2.getIndex();
    179     }
    180 }