View Javadoc

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                     + "'"
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                     + """
218                     + string.substring(index + 1);
219             index = string.indexOf('\"');
220         }
221         return string;
222     }
223 }