    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 org.apache.commons.jxpath.JXPathContext;
    19  import org.apache.commons.jxpath.JXPathException;
    20  import org.apache.commons.jxpath.ri.QName;
    21  import org.apache.commons.jxpath.ri.model.NodePointer;
    22
    23  /***
    24   * @author Dmitri Plotnikov
    25   * @version $Revision: 1.18 $ $Date: 2004/03/25 03:49:50 $
    26   */
    27  public class NullPropertyPointer extends PropertyPointer {
    28
    29      private String propertyName = "*";
    30      private boolean byNameAttribute = false;
    31
    32      /***
    33       */
    34      public NullPropertyPointer(NodePointer parent) {
    35          super(parent);
    36      }
    37
    38      public QName getName() {
    39          return new QName(propertyName);
    40      }
    41
    42      public void setPropertyIndex(int index) {
    43      }
    44
    45      public int getLength() {
    46          return 0;
    47      }
    48
    49      public Object getBaseValue() {
    50          return null;
    51      }
    52
    53      public Object getImmediateNode() {
    54          return null;
    55      }
    56
    57      public boolean isLeaf() {
    58          return true;
    59      }
    60
    61      public NodePointer getValuePointer() {
    62          return new NullPointer(this,  new QName(getPropertyName()));
    63      }
    64
    65      protected boolean isActualProperty() {
    66          return false;
    67      }
    68
    69      public boolean isActual() {
    70          return false;
    71      }
    72
    73      public boolean isContainer() {
    74          return true;
    75      }
    76
    77      public void setValue(Object value) {
    78          if (parent == null || parent.isContainer()) {
    79              throw new JXPathException(
    80                  "Cannot set property "
    81                      + asPath()
    82                      + ", the target object is null");
    83          }
    84          else if (parent instanceof PropertyOwnerPointer &&
    85                  ((PropertyOwnerPointer) parent).
    86                      isDynamicPropertyDeclarationSupported()){
    87              // If the parent property owner can create
    88              // a property automatically - let it do so
    89              PropertyPointer propertyPointer =
    90                  ((PropertyOwnerPointer) parent).getPropertyPointer();
    91              propertyPointer.setPropertyName(propertyName);
    92              propertyPointer.setValue(value);
    93          }
    94          else {
    95              throw new JXPathException(
    96                  "Cannot set property "
    97                      + asPath()
    98                      + ", path does not match a changeable location");
    99          }
    100     }
    101
    102     public NodePointer createPath(JXPathContext context) {
    103         NodePointer newParent = parent.createPath(context);
    104         if (isAttribute()) {
    105             return newParent.createAttribute(context, getName());
    106         }
    107         else {
    108             // Consider these two use cases:
    109             // 1. The parent pointer of NullPropertyPointer is
    110             //    a PropertyOwnerPointer other than NullPointer. When we call
    111             //    createPath on it, it most likely returns itself. We then
    112             //    take a PropertyPointer from it and get the PropertyPointer
    113             //    to expand the collection for the corresponsing property.
    114             //
    115             // 2. The parent pointer of NullPropertyPointer is a NullPointer.
    116             //    When we call createPath, it may return a PropertyOwnerPointer
    117             //    or it may return anything else, like a DOMNodePointer.
    118             //    In the former case we need to do exactly what we did in use
    119             //    case 1.  In the latter case, we simply request that the
    120             //    non-property pointer expand the collection by itself.
    121             if (newParent instanceof PropertyOwnerPointer) {
    122                 PropertyOwnerPointer pop = (PropertyOwnerPointer) newParent;
    123                 newParent = pop.getPropertyPointer();
    124             }
    125             return newParent.createChild(context, getName(), getIndex());
    126         }
    127     }
    128
    129     public NodePointer createPath(JXPathContext context, Object value) {
    130         NodePointer newParent = parent.createPath(context);
    131         if (isAttribute()) {
    132             NodePointer pointer = newParent.createAttribute(context, getName());
    133             pointer.setValue(value);
    134             return pointer;
    135         }
    136         else {
    137             if (newParent instanceof PropertyOwnerPointer) {
    138                 PropertyOwnerPointer pop = (PropertyOwnerPointer) newParent;
    139                 newParent = pop.getPropertyPointer();
    140             }
    141             return newParent.createChild(context, getName(), index, value);
    142         }
    143     }
    144
    145     public NodePointer createChild(
    146             JXPathContext context,
    147             QName name,
    148             int index)
    149     {
    150         return createPath(context).createChild(context, name, index);
    151     }
    152
    153     public NodePointer createChild(
    154             JXPathContext context,
    155             QName name,
    156             int index,
    157             Object value)
    158     {
    159         return createPath(context).createChild(context, name, index, value);
    160     }
    161
    162     public String getPropertyName() {
    163         return propertyName;
    164     }
    165
    166     public void setPropertyName(String propertyName) {
    167         this.propertyName = propertyName;
    168     }
    169
    170     public void setNameAttributeValue(String attributeValue) {
    171         this.propertyName = attributeValue;
    172         byNameAttribute = true;
    173     }
    174
    175     public boolean isCollection() {
    176         return getIndex() != WHOLE_COLLECTION;
    177     }
    178
    179     public int getPropertyCount() {
    180         return 0;
    181     }
    182
    183     public String[] getPropertyNames() {
    184         return new String[0];
    185     }
    186
    187     public String asPath() {
    188         if (!byNameAttribute) {
    189             return super.asPath();
    190         }
    191         else {
    192             StringBuffer buffer = new StringBuffer();
    193             buffer.append(getImmediateParentPointer().asPath());
    194             buffer.append("[@name='");
    195             buffer.append(escape(getPropertyName()));
    196             buffer.append("']");
    197             if (index != WHOLE_COLLECTION) {
    198                 buffer.append('[').append(index + 1).append(']');
    199             }
    200             return buffer.toString();
    201         }
    202     }
    203
    204     private String escape(String string) {
    205         int index = string.indexOf('\'');
    206         while (index != -1) {
    207             string =
    208                 string.substring(0, index)
    209                     + "&apos;"
    210                     + string.substring(index + 1);
    211             index = string.indexOf('\'');
    212         }
    213         index = string.indexOf('\"');
    214         while (index != -1) {
    215             string =
    216                 string.substring(0, index)
    217                     + "&quot;"
    218                     + string.substring(index + 1);
    219             index = string.indexOf('\"');
    220         }
    221         return string;
    222     }
    223 }