View Javadoc

1   /*
2    * ModeShape (http://www.modeshape.org)
3    * See the COPYRIGHT.txt file distributed with this work for information
4    * regarding copyright ownership.  Some portions may be licensed
5    * to Red Hat, Inc. under one or more contributor license agreements.
6    * See the AUTHORS.txt file in the distribution for a full listing of 
7    * individual contributors. 
8    *
9    * ModeShape is free software. Unless otherwise indicated, all code in ModeShape
10   * is licensed to you under the terms of the GNU Lesser General Public License as
11   * published by the Free Software Foundation; either version 2.1 of
12   * the License, or (at your option) any later version.
13   *
14   * ModeShape is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   * Lesser General Public License for more details.
18   *
19   * You should have received a copy of the GNU Lesser General Public
20   * License along with this software; if not, write to the Free
21   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
23   */
24  package org.modeshape.jcr;
25  
26  import java.util.Iterator;
27  import javax.jcr.InvalidItemStateException;
28  import javax.jcr.Item;
29  import javax.jcr.ItemNotFoundException;
30  import javax.jcr.ItemVisitor;
31  import javax.jcr.Node;
32  import javax.jcr.PathNotFoundException;
33  import javax.jcr.Property;
34  import javax.jcr.RepositoryException;
35  import javax.jcr.lock.Lock;
36  import javax.jcr.lock.LockException;
37  import javax.jcr.nodetype.ConstraintViolationException;
38  import javax.jcr.nodetype.PropertyDefinition;
39  import javax.jcr.version.VersionException;
40  import net.jcip.annotations.NotThreadSafe;
41  import org.modeshape.common.util.CheckArg;
42  import org.modeshape.graph.property.Name;
43  import org.modeshape.graph.property.Path;
44  import org.modeshape.graph.property.ValueFactory;
45  import org.modeshape.graph.session.GraphSession.PropertyInfo;
46  import org.modeshape.jcr.SessionCache.JcrPropertyPayload;
47  import org.modeshape.jcr.SessionCache.NodeEditor;
48  
49  /**
50   * An abstract {@link Property JCR Property} implementation.
51   */
52  @NotThreadSafe
53  abstract class AbstractJcrProperty extends AbstractJcrItem implements Property, Comparable<Property> {
54  
55      protected final AbstractJcrNode node;
56      protected final Name name;
57  
58      AbstractJcrProperty( SessionCache cache,
59                           AbstractJcrNode node,
60                           Name name ) {
61          super(cache);
62          assert node != null;
63          assert name != null;
64          this.node = node;
65          this.name = name;
66      }
67  
68      final NodeEditor editor() throws ItemNotFoundException, InvalidItemStateException, RepositoryException {
69          return node.editor();
70      }
71  
72      abstract boolean isMultiple();
73  
74      /**
75       * Checks that this property's parent node is not already locked by another session. If the parent node is not locked or the
76       * parent node is locked but the lock is owned by this {@code Session}, this method completes silently. If the parent node is
77       * locked (either directly or as part of a deep lock from an ancestor), this method throws a {@code LockException}.
78       * 
79       * @throws LockException if the parent node of this property is locked (that is, if {@code getParent().isLocked() == true &&
80       *         getParent().getLock().getLockToken() == null}.
81       * @throws RepositoryException if any other error occurs
82       * @see Node#isLocked()
83       * @see Lock#getLockToken()
84       */
85      protected final void checkForLock() throws LockException, RepositoryException {
86  
87          if (this.getParent().isLocked()) {
88              Lock parentLock = this.getParent().getLock();
89              if (parentLock != null && parentLock.getLockToken() == null) {
90                  throw new LockException(JcrI18n.lockTokenNotHeld.text(this.getParent().location));
91              }
92          }
93      }
94  
95      /**
96       * {@inheritDoc}
97       * 
98       * @throws IllegalArgumentException if <code>visitor</code> is <code>null</code>.
99       * @see javax.jcr.Item#accept(javax.jcr.ItemVisitor)
100      */
101     public final void accept( ItemVisitor visitor ) throws RepositoryException {
102         CheckArg.isNotNull(visitor, "visitor");
103         visitor.visit(this);
104     }
105 
106     final PropertyInfo<JcrPropertyPayload> propertyInfo() throws PathNotFoundException, RepositoryException {
107         return node.nodeInfo().getProperty(name);
108     }
109 
110     final Name name() {
111         return name;
112     }
113 
114     final JcrPropertyPayload payload() throws RepositoryException {
115         return propertyInfo().getPayload();
116     }
117 
118     final org.modeshape.graph.property.Property property() throws RepositoryException {
119         return propertyInfo().getProperty();
120     }
121 
122     JcrValue createValue( Object value ) throws RepositoryException {
123         return new JcrValue(context().getValueFactories(), this.cache, payload().getPropertyType(), value);
124     }
125 
126     final JcrValue createValue( Object value,
127                                 int propertyType ) {
128         return new JcrValue(context().getValueFactories(), this.cache, propertyType, value);
129     }
130 
131     @Override
132     Path path() throws RepositoryException {
133         return context().getValueFactories().getPathFactory().create(node.path(), name);
134     }
135 
136     /**
137      * {@inheritDoc}
138      * 
139      * @see javax.jcr.Property#getType()
140      */
141     public int getType() throws RepositoryException {
142         return payload().getPropertyType();
143     }
144 
145     /**
146      * {@inheritDoc}
147      * 
148      * @see javax.jcr.Property#getDefinition()
149      */
150     public final PropertyDefinition getDefinition() throws RepositoryException {
151         return cache.session().nodeTypeManager().getPropertyDefinition(payload().getPropertyDefinitionId());
152     }
153 
154     /**
155      * {@inheritDoc}
156      * <p>
157      * This method returns the string form of the {@link org.modeshape.graph.property.Property#getName()}, computed dynamically
158      * each time this method is called to ensure that the property namespace prefix is used.
159      * </p>
160      * 
161      * @see javax.jcr.Item#getName()
162      */
163     public final String getName() {
164         return name.getString(namespaces());
165     }
166 
167     /**
168      * {@inheritDoc}
169      * 
170      * @see javax.jcr.Item#getParent()
171      */
172     public final AbstractJcrNode getParent() {
173         return node;
174     }
175 
176     /**
177      * {@inheritDoc}
178      * 
179      * @see javax.jcr.Item#getPath()
180      */
181     public final String getPath() throws RepositoryException {
182         return path().getString(namespaces());
183     }
184 
185     /**
186      * {@inheritDoc}
187      * 
188      * @see javax.jcr.Item#isModified()
189      */
190     public final boolean isModified() {
191         try {
192             return propertyInfo().isModified();
193         } catch (RepositoryException re) {
194             throw new IllegalStateException(re);
195         }
196     }
197 
198     /**
199      * {@inheritDoc}
200      * 
201      * @see javax.jcr.Item#isNew()
202      */
203     public final boolean isNew() {
204         try {
205             return propertyInfo().isNew();
206         } catch (RepositoryException re) {
207             throw new IllegalStateException(re);
208         }
209     }
210 
211     /**
212      * {@inheritDoc}
213      * 
214      * @return false
215      * @see javax.jcr.Item#isNode()
216      */
217     public final boolean isNode() {
218         return false;
219     }
220 
221     /**
222      * {@inheritDoc}
223      * 
224      * @see javax.jcr.Item#isSame(javax.jcr.Item)
225      */
226     @Override
227     public final boolean isSame( Item otherItem ) throws RepositoryException {
228         if (otherItem instanceof Property) {
229             Property otherProperty = (Property)otherItem;
230             // The nodes that own the properties must be the same ...
231             if (!getParent().isSame(otherProperty.getParent())) return false;
232             // The properties must have the same name ...
233             return getName().equals(otherProperty.getName());
234         }
235         return false;
236     }
237 
238     /**
239      * {@inheritDoc}
240      * 
241      * @throws UnsupportedOperationException always
242      * @see javax.jcr.Item#refresh(boolean)
243      */
244     public void refresh( boolean keepChanges ) {
245         throw new UnsupportedOperationException();
246     }
247 
248     /**
249      * {@inheritDoc}
250      * 
251      * @see javax.jcr.Item#remove()
252      */
253     public void remove() throws VersionException, LockException, ConstraintViolationException, RepositoryException {
254         editor().removeProperty(name);
255     }
256 
257     /**
258      * {@inheritDoc}
259      * 
260      * @throws UnsupportedOperationException always
261      * @see javax.jcr.Item#save()
262      */
263     public void save() {
264         throw new UnsupportedOperationException();
265     }
266 
267     /**
268      * {@inheritDoc}
269      * 
270      * @see java.lang.Comparable#compareTo(java.lang.Object)
271      */
272     public int compareTo( Property that ) {
273         if (that == this) return 0;
274         try {
275             return this.getName().compareTo(that.getName());
276         } catch (RepositoryException e) {
277             throw new RuntimeException(e);
278         }
279     }
280 
281     /**
282      * {@inheritDoc}
283      * 
284      * @see java.lang.Object#toString()
285      */
286     @Override
287     public String toString() {
288         try {
289             ValueFactory<String> stringFactory = session().getExecutionContext().getValueFactories().getStringFactory();
290             StringBuilder sb = new StringBuilder();
291             sb.append(getName()).append('=');
292             org.modeshape.graph.property.Property property = propertyInfo().getProperty();
293             if (isMultiple()) {
294                 sb.append('[');
295                 Iterator<?> iter = property.iterator();
296                 if (iter.hasNext()) {
297                     sb.append(stringFactory.create(iter.next()));
298                     if (iter.hasNext()) sb.append(',');
299                 }
300                 sb.append(']');
301             } else {
302                 sb.append(stringFactory.create(property.getFirstValue()));
303             }
304             return sb.toString();
305         } catch (RepositoryException e) {
306             return super.toString();
307         }
308     }
309 }