1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package com.xpn.xwiki.objects

File ListProperty.java

 

Coverage histogram

../../../../img/srcFileCovDistChart8.png
54% of files have more coverage

Code metrics

38
74
21
2
332
194
44
0.59
3.52
10.5
2.1

Classes

Class Line # Actions
ListProperty 37 61 0% 36 31
0.718181871.8%
ListProperty.NotifyList 268 13 0% 8 0
1.0100%
 

Contributing tests

This file is covered by 35 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package com.xpn.xwiki.objects;
21   
22    import java.util.ArrayList;
23    import java.util.Iterator;
24    import java.util.List;
25   
26    import org.dom4j.Element;
27    import org.dom4j.dom.DOMElement;
28    import org.hibernate.collection.PersistentCollection;
29    import org.xwiki.xar.internal.property.ListXarObjectPropertySerializer;
30   
31    import com.xpn.xwiki.doc.merge.MergeResult;
32    import com.xpn.xwiki.internal.AbstractNotifyOnUpdateList;
33    import com.xpn.xwiki.internal.merge.MergeUtils;
34    import com.xpn.xwiki.internal.objects.ListPropertyPersistentList;
35    import com.xpn.xwiki.objects.classes.ListClass;
36   
 
37    public class ListProperty extends BaseProperty implements Cloneable
38    {
39    /**
40    * We make this a notifying list, because we must propagate any value updates to the owner document.
41    */
42    protected transient List<String> list;
43   
44    /**
45    * @deprecated since 7.0M2. This was never used, since it is not the right place to handle separators. They are
46    * defined in {@link ListClass} and that is where they are now handled through
47    * {@link ListClass#toFormString(BaseProperty)}.
48    */
49    @Deprecated
50    private String formStringSeparator = ListClass.DEFAULT_SEPARATOR;
51   
52    /**
53    * This is the actual list. It will be used during serialization/deserialization.
54    */
55    private List<String> actualList = new ArrayList<String>();
56   
 
57  964 toggle {
58  964 this.list = new NotifyList(this.actualList, this);
59    }
60   
61    /**
62    * @deprecated since 7.0M2. This was never used, since it is not the right place to handle separators. They are
63    * defined in {@link ListClass} and that is where they are now handled through
64    * {@link ListClass#toFormString(BaseProperty)}.
65    */
 
66  0 toggle @Deprecated
67    public String getFormStringSeparator()
68    {
69  0 return this.formStringSeparator;
70    }
71   
72    /**
73    * @deprecated since 7.0M2. This was never used, since it is not the right place to handle separators. They are
74    * defined in {@link ListClass} and that is where they are now handled through
75    * {@link ListClass#toFormString(BaseProperty)}.
76    */
 
77  0 toggle @Deprecated
78    public void setFormStringSeparator(String formStringSeparator)
79    {
80  0 this.formStringSeparator = formStringSeparator;
81    }
82   
 
83  4857 toggle @Override
84    public Object getValue()
85    {
86  4857 return getList();
87    }
88   
 
89  189 toggle @Override
90    public void setValue(Object value)
91    {
92  189 this.setList((List<String>) value);
93    }
94   
95    /**
96    * This method is called by Hibernate to get the raw value to store in the database. Check the xwiki.hbm.xml file.
97    *
98    * @return the string value that is saved in the database
99    */
 
100  257 toggle public String getTextValue()
101    {
102  257 return toText();
103    }
104   
 
105  742 toggle @Override
106    public String toText()
107    {
108    // Always use the default separator because this is the value that is stored in the database (for non-relational
109    // lists).
110  742 return ListClass.getStringFromList(this.getList(), ListClass.DEFAULT_SEPARATOR);
111    }
112   
113    /**
114    * @deprecated Since 7.0M2. This method is here for a long time but it does not seem to have ever been used and it
115    * does not bring any value compared to the existing {@link #toFormString()} method.
116    */
 
117  0 toggle @Deprecated
118    public String toSingleFormString()
119    {
120  0 return super.toFormString();
121    }
122   
 
123  96 toggle @Override
124    public boolean equals(Object obj)
125    {
126    // Same Java object, they sure are equal
127  96 if (this == obj) {
128  93 return true;
129    }
130   
131  3 if (!super.equals(obj)) {
132  0 return false;
133    }
134   
135  3 List<String> list1 = getList();
136  3 List<String> list2 = (List<String>) ((BaseProperty) obj).getValue();
137   
138    // If the collection was not yet initialized by Hibernate
139    // Let's use the super result..
140  3 if ((list1 instanceof PersistentCollection) && (!((PersistentCollection) list1).wasInitialized())) {
141  0 return true;
142    }
143   
144  3 if ((list2 instanceof PersistentCollection) && (!((PersistentCollection) list2).wasInitialized())) {
145  0 return true;
146    }
147   
148  3 if (list1.size() != list2.size()) {
149  0 return false;
150    }
151   
152  9 for (int i = 0; i < list1.size(); i++) {
153  6 Object obj1 = list1.get(i);
154  6 Object obj2 = list2.get(i);
155   
156  6 if (!obj1.equals(obj2)) {
157  0 return false;
158    }
159    }
160   
161  3 return true;
162    }
163   
 
164  4805 toggle @Override
165    public ListProperty clone()
166    {
167  4805 return (ListProperty) super.clone();
168    }
169   
 
170  4804 toggle @Override
171    protected void cloneInternal(BaseProperty clone)
172    {
173  4804 ListProperty property = (ListProperty) clone;
174  4804 property.actualList = new ArrayList<String>();
175  4806 for (String entry : getList()) {
176  1806 property.actualList.add(entry);
177    }
178  4806 property.list = new NotifyList(property.actualList, property);
179    }
180   
 
181  11648 toggle public List<String> getList()
182    {
183    // Hibernate will not set the owner of the notify list, so we must make sure this has been done before returning
184    // the list.
185  11648 if (this.list instanceof NotifyList) {
186  5154 ((NotifyList) this.list).setOwner(this);
187  6494 } else if (this.list instanceof ListPropertyPersistentList) {
188  6493 ((ListPropertyPersistentList) this.list).setOwner(this);
189    }
190   
191  11649 return this.list;
192    }
193   
194    /**
195    * Starting from 4.3M2, this method will copy the list passed as parameter. Due to XWIKI-8398 we must be able to
196    * detect when the values in the list changes, so we cannot store the values in any type of list.
197    *
198    * @param list The list to copy.
199    */
 
200  1190 toggle public void setList(List<String> list)
201    {
202  1190 if (list == this.list || list == this.actualList) {
203    // Accept a caller that sets the already existing list instance.
204  0 return;
205    }
206   
207  1190 if (this.list instanceof ListPropertyPersistentList) {
208  55 ListPropertyPersistentList persistentList = (ListPropertyPersistentList) this.list;
209  55 if (persistentList.isWrapper(list)) {
210    // Accept a caller that sets the already existing list instance.
211  0 return;
212    }
213    }
214   
215  1190 if (list instanceof ListPropertyPersistentList) {
216    // This is the list wrapper we are using for hibernate.
217  607 ListPropertyPersistentList persistentList = (ListPropertyPersistentList) list;
218  607 this.list = persistentList;
219  607 persistentList.setOwner(this);
220  607 return;
221    }
222   
223  583 if (list == null) {
224  1 setValueDirty(true);
225  1 this.actualList = new ArrayList();
226  1 this.list = new NotifyList(this.actualList, this);
227    } else {
228  582 this.list.clear();
229  582 this.list.addAll(list);
230    }
231   
232    // In Oracle, empty string are converted to NULL. Since an undefined property is not found at all, it is
233    // safe to assume that a retrieved NULL value should actually be an empty string.
234  951 for (Iterator<String> it = this.list.iterator(); it.hasNext();) {
235  368 if (it.next() == null) {
236  0 it.remove();
237    }
238    }
239    }
240   
241    /**
242    * {@inheritDoc}
243    * <p>
244    * This is important.. Otherwise we can get a stackoverflow calling toXML().
245    * </p>
246    *
247    * @see com.xpn.xwiki.objects.BaseProperty#toString()
248    */
 
249  0 toggle @Override
250    public String toString()
251    {
252  0 if ((getList() instanceof PersistentCollection) && (!((PersistentCollection) getList()).wasInitialized())) {
253  0 return "";
254    }
255   
256  0 return super.toString();
257    }
258   
 
259  0 toggle @Override
260    protected void mergeValue(Object previousValue, Object newValue, MergeResult mergeResult)
261    {
262  0 MergeUtils.mergeList((List<String>) previousValue, (List<String>) newValue, this.list, mergeResult);
263    }
264   
265    /**
266    * List implementation for updating dirty flag when updated. This will be accessed from ListPropertyUserType.
267    */
 
268    public static class NotifyList extends AbstractNotifyOnUpdateList<String>
269    {
270   
271    /** The owner list property. */
272    private ListProperty owner;
273   
274    /** The dirty flag. */
275    private boolean dirty;
276   
277    private List<String> actualList;
278   
279    /**
280    * @param list {@link AbstractNotifyOnUpdateList}.
281    */
 
282  6487 toggle public NotifyList(List<String> list)
283    {
284  6487 super(list);
285  6487 this.actualList = list;
286    }
287   
 
288  5771 toggle private NotifyList(List<String> list, ListProperty owner)
289    {
290  5771 this(list);
291   
292  5771 this.owner = owner;
293    }
294   
 
295  996 toggle @Override
296    public void onUpdate()
297    {
298  996 setDirty();
299    }
300   
301    /**
302    * @param owner The owner list property.
303    */
 
304  12255 toggle public void setOwner(ListProperty owner)
305    {
306  12257 if (this.dirty) {
307  5221 owner.setValueDirty(true);
308    }
309  12257 this.owner = owner;
310  12256 owner.actualList = this.actualList;
311    }
312   
313    /**
314    * @return {@literal true} if the given argument is the instance that this list wraps.
315    */
 
316  55 toggle public boolean isWrapper(Object collection)
317    {
318  55 return this.actualList == collection;
319    }
320   
321    /**
322    * Set the dirty flag.
323    */
 
324  996 toggle private void setDirty()
325    {
326  996 if (this.owner != null) {
327  808 this.owner.setValueDirty(true);
328    }
329  996 this.dirty = true;
330    }
331    }
332    }