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

File BaseClass.java

 

Coverage histogram

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

Code metrics

168
459
90
1
1,338
944
193
0.42
5.1
90
2.14

Classes

Class Line # Actions
BaseClass 68 459 0% 193 161
0.7754532777.5%
 

Contributing tests

This file is covered by 142 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.classes;
21   
22    import java.util.ArrayList;
23    import java.util.Collection;
24    import java.util.Collections;
25    import java.util.List;
26    import java.util.Map;
27    import java.util.Set;
28   
29    import org.apache.commons.lang3.StringUtils;
30    import org.dom4j.Element;
31    import org.slf4j.Logger;
32    import org.slf4j.LoggerFactory;
33    import org.xwiki.model.EntityType;
34    import org.xwiki.model.reference.DocumentReference;
35    import org.xwiki.model.reference.DocumentReferenceResolver;
36    import org.xwiki.model.reference.EntityReference;
37    import org.xwiki.model.reference.SpaceReference;
38    import org.xwiki.security.authorization.ContextualAuthorizationManager;
39    import org.xwiki.security.authorization.Right;
40   
41    import com.google.common.base.Objects;
42    import com.xpn.xwiki.XWikiContext;
43    import com.xpn.xwiki.XWikiException;
44    import com.xpn.xwiki.doc.XWikiDocument;
45    import com.xpn.xwiki.doc.merge.MergeConfiguration;
46    import com.xpn.xwiki.doc.merge.MergeResult;
47    import com.xpn.xwiki.internal.merge.MergeUtils;
48    import com.xpn.xwiki.objects.BaseCollection;
49    import com.xpn.xwiki.objects.BaseObject;
50    import com.xpn.xwiki.objects.BaseProperty;
51    import com.xpn.xwiki.objects.ElementInterface;
52    import com.xpn.xwiki.objects.ObjectDiff;
53    import com.xpn.xwiki.objects.PropertyInterface;
54    import com.xpn.xwiki.objects.classes.TextAreaClass.ContentType;
55    import com.xpn.xwiki.objects.classes.TextAreaClass.EditorType;
56    import com.xpn.xwiki.objects.meta.MetaClass;
57    import com.xpn.xwiki.objects.meta.PropertyMetaClass;
58    import com.xpn.xwiki.validation.XWikiValidationInterface;
59    import com.xpn.xwiki.validation.XWikiValidationStatus;
60    import com.xpn.xwiki.web.Utils;
61   
62    /**
63    * Represents an XClass, and contains XClass properties. Each field from {@link BaseCollection} is of type
64    * {@link PropertyClass} and defines a single XClass property.
65    *
66    * @version $Id: 3875cef16edc129d7c71690c22af81571e62e1f7 $
67    */
 
68    public class BaseClass extends BaseCollection<DocumentReference> implements ClassInterface
69    {
70    protected static final Logger LOGGER = LoggerFactory.getLogger(BaseClass.class);
71   
72    private String customMapping;
73   
74    private String customClass;
75   
76    private String defaultWeb;
77   
78    private String defaultViewSheet;
79   
80    private String defaultEditSheet;
81   
82    private String validationScript;
83   
84    private String nameField;
85   
86    /**
87    * Set to true if the class is modified from the database version of it.
88    */
89    private boolean isDirty = true;
90   
91    /**
92    * Used to resolve a string into a proper Document Reference using the current document's reference to fill the
93    * blanks, except for the page name for which the default page name is used instead and for the wiki name for which
94    * the current wiki is used instead of the current document reference's wiki.
95    */
96    private DocumentReferenceResolver<String> currentMixedDocumentReferenceResolver;
97   
98    private DocumentReferenceResolver<String> currentDocumentReferenceResolver;
99   
 
100  4 toggle private DocumentReferenceResolver<String> getCurrentMixedDocumentReferenceResolver()
101    {
102  4 if (this.currentMixedDocumentReferenceResolver == null) {
103  4 this.currentMixedDocumentReferenceResolver =
104    Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, "currentmixed");
105    }
106   
107  4 return this.currentMixedDocumentReferenceResolver;
108    }
109   
110    /**
111    * Used to resolve a string into a proper Document Reference using the current document's reference to fill the
112    * blanks.
113    *
114    * @since 7.2M3
115    */
 
116  2 toggle private DocumentReferenceResolver<String> getCurrentDocumentReferenceResolver()
117    {
118  2 if (this.currentDocumentReferenceResolver == null) {
119  1 this.currentDocumentReferenceResolver =
120    Utils.getComponent(DocumentReferenceResolver.TYPE_STRING, "current");
121    }
122   
123  2 return this.currentDocumentReferenceResolver;
124    }
125   
 
126  126487 toggle @Override
127    public DocumentReference getReference()
128    {
129  126487 return getDocumentReference();
130    }
131   
132    /**
133    * {@inheritDoc}
134    * <p>
135    * Note: This method is overridden to add the deprecation warning so that code using is can see it's deprecated.
136    * </p>
137    *
138    * @deprecated since 2.2M2 use {@link #getDocumentReference()}
139    */
 
140  77988 toggle @Deprecated
141    @Override
142    public String getName()
143    {
144  77986 return super.getName();
145    }
146   
147    /**
148    * {@inheritDoc}
149    * <p>
150    * Note: BaseElement#setName() does not support setting reference anymore since 2.4M2. This was broken and has been
151    * replaced by this overridden method. See XWIKI-5285
152    * </p>
153    *
154    * @deprecated since 2.2M2 use {@link #setDocumentReference(org.xwiki.model.reference.DocumentReference)}
155    */
 
156  1173 toggle @Deprecated
157    @Override
158    public void setName(String name)
159    {
160  1173 if (this instanceof MetaClass || this instanceof PropertyMetaClass) {
161  1150 super.setName(name);
162    } else {
163  23 DocumentReference reference = getDocumentReference();
164   
165  23 if (reference != null) {
166  19 EntityReference relativeReference =
167    getRelativeEntityReferenceResolver().resolve(name, EntityType.DOCUMENT);
168  19 reference = new DocumentReference(relativeReference.extractReference(EntityType.DOCUMENT).getName(),
169    new SpaceReference(relativeReference.extractReference(EntityType.SPACE).getName(),
170    reference.getParent().getParent()));
171    } else {
172  4 reference = getCurrentMixedDocumentReferenceResolver().resolve(name);
173    }
174  23 setDocumentReference(reference);
175    }
176  1173 setDirty(true);
177    }
178   
179    /**
180    * {@inheritDoc}
181    * <p>
182    * This insures natural ordering between properties.
183    * </p>
184    *
185    * @see com.xpn.xwiki.objects.BaseCollection#addField(java.lang.String, com.xpn.xwiki.objects.PropertyInterface)
186    */
 
187  58425 toggle @Override
188    public void addField(String name, PropertyInterface element)
189    {
190  58425 Set<String> properties = getPropertyList();
191  58425 if (!properties.contains(name)) {
192  58425 if (((BaseCollection) element).getNumber() == 0) {
193  20890 ((BaseCollection) element).setNumber(properties.size() + 1);
194    }
195    }
196   
197  58424 super.addField(name, element);
198   
199  58421 setDirty(true);
200    }
201   
202    /**
203    * Mark a property as disabled. A disabled property should not be editable, but existing object values are still
204    * kept in the database.
205    *
206    * @param name the name of the property to disable
207    * @since 2.4M2
208    */
 
209  0 toggle public void disableField(String name)
210    {
211  0 PropertyClass pclass = (PropertyClass) safeget(name);
212   
213  0 if (pclass != null) {
214  0 pclass.setDisabled(true);
215    }
216   
217  0 setDirty(true);
218    }
219   
220    /**
221    * Re-enable a property. This field will appear again in object instances.
222    *
223    * @param name the name of the property to enable
224    * @since 2.4M2
225    */
 
226  0 toggle public void enableField(String name)
227    {
228  0 PropertyClass pclass = (PropertyClass) safeget(name);
229   
230  0 if (pclass != null) {
231  0 pclass.setDisabled(false);
232    }
233   
234  0 setDirty(true);
235    }
236   
 
237  371713 toggle @Override
238    public PropertyInterface get(String name)
239    {
240  371717 return safeget(name);
241    }
242   
 
243  7822 toggle @Override
244    public void put(String name, PropertyInterface property)
245    {
246  7822 safeput(name, property);
247  7822 setDirty(true);
248    }
249   
250    /**
251    * Get the list of enabled (the default, normal state) property definitions that exist in this class. The resulting
252    * list is unmodifiable, but the contained elements are live.
253    *
254    * @return an unmodifiable list containing the enabled properties of the class
255    * @see PropertyClass#isDisabled()
256    * @since 2.4M2
257    */
 
258  2 toggle public List<PropertyClass> getEnabledProperties()
259    {
260  2 @SuppressWarnings("unchecked")
261    Collection<PropertyClass> allProperties = getFieldList();
262  2 if (allProperties == null) {
263  0 return Collections.emptyList();
264    }
265   
266  2 List<PropertyClass> enabledProperties = new ArrayList<PropertyClass>(allProperties.size());
267   
268  2 for (PropertyClass property : allProperties) {
269  154 if (property != null && !property.isDisabled()) {
270  154 enabledProperties.add(property);
271    }
272    }
273   
274  2 Collections.sort(enabledProperties);
275  2 return Collections.unmodifiableList(enabledProperties);
276    }
277   
278    /**
279    * Get the list of disabled property definitions that exist in this class. The resulting list is unmodifiable, but
280    * the contained elements are live.
281    *
282    * @return an unmodifiable list containing the disabled properties of the class
283    * @see PropertyClass#isDisabled()
284    * @since 2.4M2
285    */
 
286  0 toggle public List<PropertyClass> getDisabledProperties()
287    {
288  0 @SuppressWarnings("unchecked")
289    Collection<PropertyClass> allProperties = getFieldList();
290  0 if (allProperties == null) {
291  0 return Collections.emptyList();
292    }
293   
294  0 List<PropertyClass> disabledProperties = new ArrayList<PropertyClass>();
295   
296  0 for (PropertyClass property : allProperties) {
297  0 if (property != null && property.isDisabled()) {
298  0 disabledProperties.add(property);
299    }
300    }
301   
302  0 Collections.sort(disabledProperties);
303  0 return Collections.unmodifiableList(disabledProperties);
304    }
305   
306    /**
307    * Get the list of disabled properties that exist in a given object. This list is a subset of all the disabled
308    * properties in a class, since the object could have been created and stored before some of the class properties
309    * were added. The resulting list is unmodifiable, but the contained elements are live.
310    *
311    * @param object the instance of this class where the disabled properties must exist
312    * @return an unmodifiable list containing the disabled properties of the given object
313    * @see PropertyClass#isDisabled()
314    * @since 2.4M2
315    */
 
316  0 toggle public List<PropertyClass> getDisabledObjectProperties(BaseObject object)
317    {
318  0 List<PropertyClass> disabledProperties = getDisabledProperties();
319  0 if (disabledProperties == null) {
320  0 return Collections.emptyList();
321    }
322   
323  0 List<PropertyClass> disabledObjectProperties = new ArrayList<PropertyClass>(disabledProperties.size());
324   
325  0 for (PropertyClass property : disabledProperties) {
326  0 try {
327  0 if (object.get(property.getName()) != null) {
328  0 disabledObjectProperties.add(property);
329    }
330    } catch (XWikiException ex) {
331    // Not really gonna happen
332    }
333    }
334   
335  0 return Collections.unmodifiableList(disabledObjectProperties);
336    }
337   
338    /**
339    * Retrieves deprecated properties of the given object compared to the class. A deprecated property is a property
340    * which exists in the Object but doesn't exist anymore in the Class, or which has the wrong data type. This is used
341    * for synchronization of existing or imported Objects with respect to the modifications of their associated Class.
342    *
343    * @param object the instance of this class where to look for undefined properties
344    * @return an unmodifiable list containing the properties of the object which don't exist in the class
345    * @since 2.4M2
346    */
 
347  91 toggle public List<BaseProperty> getDeprecatedObjectProperties(BaseObject object)
348    {
349  91 @SuppressWarnings("unchecked")
350    Collection<BaseProperty> objectProperties = object.getFieldList();
351  91 if (objectProperties == null) {
352  0 return Collections.emptyList();
353    }
354   
355  91 List<BaseProperty> deprecatedObjectProperties = new ArrayList<BaseProperty>();
356   
357  91 for (BaseProperty property : objectProperties) {
358  832 if (safeget(property.getName()) == null) {
359  12 deprecatedObjectProperties.add(property);
360    } else {
361  820 String propertyClass = ((PropertyClass) safeget(property.getName())).newProperty().getClassType();
362  820 String objectPropertyClass = property.getClassType();
363   
364  820 if (!propertyClass.equals(objectPropertyClass)) {
365  0 deprecatedObjectProperties.add(property);
366    }
367    }
368    }
369   
370  91 return Collections.unmodifiableList(deprecatedObjectProperties);
371    }
372   
 
373  0 toggle public BaseProperty fromString(String value)
374    {
375  0 return null; // To change body of implemented methods use Options | File Templates.
376    }
377   
378    /**
379    * @deprecated since 2.2.3 use {@link com.xpn.xwiki.doc.XWikiDocument#newXObject}
380    */
 
381  125 toggle @Deprecated
382    public BaseCollection newObject(XWikiContext context) throws XWikiException
383    {
384  125 BaseObject bobj = newCustomClassInstance(context);
385  125 DocumentReference classReference = getDocumentReference();
386  125 bobj.setXClassReference(classReference.removeParent(classReference.getWikiReference()));
387   
388  125 return bobj;
389    }
390   
391    /**
392    * @deprecated since 2.2.3 use {@link #fromMap(java.util.Map, com.xpn.xwiki.objects.BaseCollection)}
393    */
 
394  0 toggle @Deprecated
395    public BaseCollection fromMap(Map<String, ?> map, XWikiContext context) throws XWikiException
396    {
397  0 BaseCollection object = newObject(context);
398   
399  0 return fromMap(map, object);
400    }
401   
 
402  244 toggle public BaseCollection fromMap(Map<String, ?> map, BaseCollection object)
403    {
404  244 for (PropertyClass property : (Collection<PropertyClass>) getFieldList()) {
405  3369 String name = property.getName();
406  3369 Object formvalues = map.get(name);
407  3369 if (formvalues != null) {
408  774 BaseProperty objprop;
409  774 if (formvalues instanceof String[]) {
410  774 objprop = property.fromStringArray(((String[]) formvalues));
411  0 } else if (formvalues instanceof String) {
412  0 objprop = property.fromString(formvalues.toString());
413    } else {
414  0 objprop = property.fromValue(formvalues);
415    }
416   
417  774 if (objprop != null) {
418  774 objprop.setObject(object);
419  774 object.safeput(name, objprop);
420    }
421    }
422    }
423   
424  244 return object;
425    }
426   
 
427  41 toggle public BaseCollection fromValueMap(Map<String, ?> map, BaseCollection object)
428    {
429  41 for (PropertyClass property : (Collection<PropertyClass>) getFieldList()) {
430  2957 String name = property.getName();
431  2957 Object formvalue = map.get(name);
432  2957 if (formvalue != null) {
433  151 BaseProperty objprop;
434  151 objprop = property.fromValue(formvalue);
435  151 if (objprop != null) {
436  151 objprop.setObject(object);
437  151 object.safeput(name, objprop);
438    }
439    }
440    }
441   
442  41 return object;
443    }
444   
 
445  20728 toggle @Override
446    public BaseClass clone()
447    {
448  20728 BaseClass bclass = (BaseClass) super.clone();
449  20727 bclass.setCustomClass(getCustomClass());
450  20727 bclass.setCustomMapping(getCustomMapping());
451  20727 bclass.setDefaultWeb(getDefaultWeb());
452  20728 bclass.setDefaultViewSheet(getDefaultViewSheet());
453  20728 bclass.setDefaultEditSheet(getDefaultEditSheet());
454  20726 bclass.setNameField(getNameField());
455  20727 bclass.setDirty(this.isDirty);
456  20728 bclass.setOwnerDocument(this.ownerDocument);
457   
458  20729 return bclass;
459    }
460   
 
461  101 toggle @Override
462    public boolean equals(Object obj)
463    {
464    // Same Java object, they sure are equal
465  101 if (this == obj) {
466  0 return true;
467    }
468   
469  101 if (!super.equals(obj)) {
470  20 return false;
471    }
472   
473  81 BaseClass bclass = (BaseClass) obj;
474   
475  81 if (!getCustomClass().equals(bclass.getCustomClass())) {
476  0 return false;
477    }
478   
479  81 if (!Objects.equal(this.customMapping, bclass.customMapping)
480    && !getCustomMapping().equals(bclass.getCustomMapping())) {
481  0 return false;
482    }
483   
484  81 if (!getDefaultViewSheet().equals(bclass.getDefaultViewSheet())) {
485  0 return false;
486    }
487   
488  81 if (!getDefaultEditSheet().equals(bclass.getDefaultEditSheet())) {
489  0 return false;
490    }
491   
492  81 if (!getDefaultWeb().equals(bclass.getDefaultWeb())) {
493  0 return false;
494    }
495   
496  81 if (!getValidationScript().equals(bclass.getValidationScript())) {
497  0 return false;
498    }
499   
500  81 if (!getNameField().equals(bclass.getNameField())) {
501  0 return false;
502    }
503   
504  81 return true;
505    }
506   
 
507  0 toggle public void merge(BaseClass bclass)
508    {
509    }
510   
 
511  2 toggle @Override
512    public void fromXML(Element element) throws XWikiException
513    {
514  2 super.fromXML(element);
515    }
516   
 
517  3615 toggle @Override
518    public void fromXML(String xml) throws XWikiException
519    {
520  3615 super.fromXML(xml);
521    }
522   
 
523  7192 toggle public boolean addTextField(String fieldName, String fieldPrettyName, int size)
524    {
525  7192 if (get(fieldName) == null) {
526  3003 StringClass text_class = new StringClass();
527  3003 text_class.setName(fieldName);
528  3003 text_class.setPrettyName(fieldPrettyName);
529  3003 text_class.setSize(size);
530  3003 text_class.setObject(this);
531  3003 put(fieldName, text_class);
532   
533  3003 return true;
534    }
535   
536  4189 return false;
537    }
538   
 
539  354 toggle public boolean addPasswordField(String fieldName, String fieldPrettyName, int size)
540    {
541  354 if (get(fieldName) == null) {
542  182 PasswordClass text_class = new PasswordClass();
543  182 text_class.setName(fieldName);
544  182 text_class.setPrettyName(fieldPrettyName);
545  182 text_class.setSize(size);
546  182 text_class.setObject(this);
547  182 put(fieldName, text_class);
548   
549  182 return true;
550    }
551   
552  172 return false;
553    }
554   
 
555  41 toggle public boolean addEmailField(String fieldName, String fieldPrettyName, int size)
556    {
557  41 if (get(fieldName) == null) {
558  41 EmailClass emailClass = new EmailClass();
559  41 emailClass.setName(fieldName);
560  41 emailClass.setPrettyName(fieldPrettyName);
561  41 emailClass.setSize(size);
562  41 emailClass.setObject(this);
563  41 put(fieldName, emailClass);
564   
565  41 return true;
566    }
567   
568  0 return false;
569    }
570   
 
571  78 toggle public boolean addTimezoneField(String fieldName, String fieldPrettyName, int size)
572    {
573  78 if (get(fieldName) == null) {
574  78 TimezoneClass timezoneClass = new TimezoneClass();
575  78 timezoneClass.setName(fieldName);
576  78 timezoneClass.setPrettyName(fieldPrettyName);
577  78 timezoneClass.setSize(size);
578  78 timezoneClass.setObject(this);
579  78 put(fieldName, timezoneClass);
580   
581  78 return true;
582    }
583   
584  0 return false;
585    }
586   
 
587  3526 toggle public boolean addBooleanField(String fieldName, String fieldPrettyName, String displayType)
588    {
589  3526 if (get(fieldName) == null) {
590  1462 BooleanClass boolean_class = new BooleanClass();
591  1462 boolean_class.setName(fieldName);
592  1462 boolean_class.setPrettyName(fieldPrettyName);
593  1462 boolean_class.setDisplayType(displayType);
594  1462 boolean_class.setObject(this);
595  1462 put(fieldName, boolean_class);
596   
597  1462 return true;
598    }
599   
600  2064 return false;
601    }
602   
 
603  216 toggle public boolean addUsersField(String fieldName, String fieldPrettyName)
604    {
605  216 return addUsersField(fieldName, fieldPrettyName, true);
606    }
607   
608    /**
609    * @since 1.1.2
610    * @since 1.2M2
611    */
 
612  304 toggle public boolean addUsersField(String fieldName, String fieldPrettyName, boolean multiSelect)
613    {
614  304 return addUsersField(fieldName, fieldPrettyName, 5, multiSelect);
615    }
616   
 
617  0 toggle public boolean addUsersField(String fieldName, String fieldPrettyName, int size)
618    {
619  0 return addUsersField(fieldName, fieldPrettyName, size, true);
620    }
621   
622    /**
623    * @since 1.1.2
624    * @since 1.2M2
625    */
 
626  304 toggle public boolean addUsersField(String fieldName, String fieldPrettyName, int size, boolean multiSelect)
627    {
628  304 if (get(fieldName) == null) {
629  112 UsersClass users_class = new UsersClass();
630  112 users_class.setName(fieldName);
631  112 users_class.setPrettyName(fieldPrettyName);
632  112 users_class.setSize(size);
633  112 users_class.setMultiSelect(multiSelect);
634  112 users_class.setObject(this);
635  112 put(fieldName, users_class);
636   
637  112 return true;
638    }
639   
640  192 return false;
641    }
642   
 
643  216 toggle public boolean addLevelsField(String fieldName, String fieldPrettyName)
644    {
645  216 return addLevelsField(fieldName, fieldPrettyName, 3);
646    }
647   
 
648  216 toggle public boolean addLevelsField(String fieldName, String fieldPrettyName, int size)
649    {
650  216 if (get(fieldName) == null) {
651  78 LevelsClass levels_class = new LevelsClass();
652  78 levels_class.setName(fieldName);
653  78 levels_class.setPrettyName(fieldPrettyName);
654  78 levels_class.setSize(size);
655  78 levels_class.setMultiSelect(true);
656  78 levels_class.setObject(this);
657  78 put(fieldName, levels_class);
658   
659  78 return true;
660    }
661   
662  138 return false;
663    }
664   
 
665  216 toggle public boolean addGroupsField(String fieldName, String fieldPrettyName)
666    {
667  216 return addGroupsField(fieldName, fieldPrettyName, 5);
668    }
669   
 
670  216 toggle public boolean addGroupsField(String fieldName, String fieldPrettyName, int size)
671    {
672  216 if (get(fieldName) == null) {
673  78 GroupsClass groups_class = new GroupsClass();
674  78 groups_class.setName(fieldName);
675  78 groups_class.setPrettyName(fieldPrettyName);
676  78 groups_class.setSize(size);
677  78 groups_class.setMultiSelect(true);
678  78 groups_class.setObject(this);
679  78 put(fieldName, groups_class);
680   
681  78 return true;
682    }
683   
684  138 return false;
685    }
686   
 
687  644 toggle public boolean addTemplateField(String fieldName, String fieldPrettyName)
688    {
689  644 return addTextAreaField(fieldName, fieldPrettyName, 80, 15, EditorType.PURE_TEXT);
690    }
691   
 
692  749 toggle public boolean addTextAreaField(String fieldName, String fieldPrettyName, int cols, int rows)
693    {
694  749 return addTextAreaField(fieldName, fieldPrettyName, cols, rows, (String) null);
695    }
696   
 
697  986 toggle public boolean addTextAreaField(String fieldName, String fieldPrettyName, int cols, int rows, EditorType editorType)
698    {
699  986 return addTextAreaField(fieldName, fieldPrettyName, cols, rows, editorType,
700    TextAreaClass.getContentType(editorType, null));
701    }
702   
 
703  749 toggle public boolean addTextAreaField(String fieldName, String fieldPrettyName, int cols, int rows, String editor)
704    {
705  749 return addTextAreaField(fieldName, fieldPrettyName, cols, rows, editor, null);
706    }
707   
708    /**
709    * @since 8.3
710    */
 
711  988 toggle public boolean addTextAreaField(String fieldName, String fieldPrettyName, int cols, int rows,
712    ContentType contentType)
713    {
714  988 return addTextAreaField(fieldName, fieldPrettyName, cols, rows, TextAreaClass.getEditorType(contentType, null),
715    contentType);
716    }
717   
718    /**
719    * @since 8.3
720    */
 
721  2038 toggle public boolean addTextAreaField(String fieldName, String fieldPrettyName, int cols, int rows, EditorType editorType,
722    ContentType contentType)
723    {
724  2038 return addTextAreaField(fieldName, fieldPrettyName, cols, rows,
725  2038 editorType != null ? editorType.toString() : null, contentType != null ? contentType.toString() : null);
726    }
727   
728    /**
729    * @since 8.3
730    */
 
731  2787 toggle public boolean addTextAreaField(String fieldName, String fieldPrettyName, int cols, int rows, String editor,
732    String contenttype)
733    {
734  2787 boolean result = false;
735   
736  2787 TextAreaClass textAreaClass;
737  2787 PropertyInterface field = get(fieldName);
738  2787 if (field instanceof TextAreaClass) {
739  1527 textAreaClass = (TextAreaClass) field;
740    } else {
741    // Remove the field if it already exist
742  1260 if (field != null) {
743  1 removeField(fieldName);
744    }
745   
746    // Create a new field
747  1260 textAreaClass = new TextAreaClass();
748  1260 textAreaClass.setName(fieldName);
749  1260 textAreaClass.setObject(this);
750  1260 put(fieldName, textAreaClass);
751   
752  1260 result = true;
753    }
754   
755    // If one of the other parameter values have changed, return true so that we update it.
756   
757  2787 if (!textAreaClass.getPrettyName().equals(fieldPrettyName)) {
758  1260 textAreaClass.setPrettyName(fieldPrettyName);
759  1260 result = true;
760    }
761   
762    // Note: TextAreaClass.getEditor() transforms the editor string into lowercase so we need to do the same when
763    // comparing here. In addition when the editor is not, an empty string is returned from getEditor()...
764  2787 if ((editor == null && !textAreaClass.getEditor().isEmpty())
765    || (editor != null && !textAreaClass.getEditor().equals(editor.toLowerCase()))) {
766  841 textAreaClass.setEditor(editor);
767  841 result = true;
768    }
769   
770    // Note: TextAreaClass.getContentType() will return a lowercase ContentType.WIKI_TEXT if the stored content
771    // editor is not set (i.e. using a default content type). Thus we need to take that into account when comparing.
772    // If the passed content type is null and the set content type is ContentType.WIKI_TEXT we don't consider that
773    // the content type is different (and vice versa).
774  2787 if ((contenttype == null && !textAreaClass.getContentType().equalsIgnoreCase(ContentType.WIKI_TEXT.toString()))
775    || (contenttype != null && !textAreaClass.getContentType().equalsIgnoreCase(contenttype))) {
776  404 textAreaClass.setContentType(contenttype);
777  404 result = true;
778    }
779   
780  2787 if (textAreaClass.getSize() != cols) {
781  818 textAreaClass.setSize(cols);
782  818 result = true;
783    }
784   
785  2787 if (textAreaClass.getRows() != rows) {
786  1047 textAreaClass.setRows(rows);
787  1047 result = true;
788    }
789   
790  2787 return result;
791    }
792   
 
793  2388 toggle public boolean addStaticListField(String fieldName, String fieldPrettyName, String values)
794    {
795  2388 return addStaticListField(fieldName, fieldPrettyName, 1, false, values);
796    }
797   
 
798  2437 toggle public boolean addStaticListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect,
799    String values)
800    {
801  2437 return addStaticListField(fieldName, fieldPrettyName, size, multiSelect, values, null);
802    }
803   
 
804  2606 toggle public boolean addStaticListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect,
805    String values, String displayType)
806    {
807  2606 return addStaticListField(fieldName, fieldPrettyName, size, multiSelect, values, displayType, null);
808    }
809   
810    /**
811    * @since 1.1.2
812    * @since 1.2M2
813    */
 
814  2720 toggle public boolean addStaticListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect,
815    String values, String displayType, String separators)
816    {
817  2720 return addStaticListField(fieldName, fieldPrettyName, size, multiSelect, false, values, displayType,
818    separators);
819    }
820   
821    /**
822    * @since 1.8M1
823    */
 
824  2813 toggle public boolean addStaticListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect,
825    boolean relationalStorage, String values, String displayType, String separators)
826    {
827  2813 if (get(fieldName) == null) {
828  1195 StaticListClass list_class = new StaticListClass();
829  1195 list_class.setName(fieldName);
830  1195 list_class.setPrettyName(fieldPrettyName);
831  1195 list_class.setSize(size);
832  1195 list_class.setMultiSelect(multiSelect);
833  1195 list_class.setRelationalStorage(relationalStorage);
834  1195 list_class.setValues(values);
835  1195 if (displayType != null) {
836  165 list_class.setDisplayType(displayType);
837    }
838  1195 if (separators != null) {
839  76 list_class.setSeparators(separators);
840  76 list_class.setSeparator(separators.substring(0, 1));
841    }
842  1195 list_class.setObject(this);
843  1195 put(fieldName, list_class);
844   
845  1195 return true;
846    }
847   
848  1618 return false;
849    }
850   
 
851  309 toggle public boolean addNumberField(String fieldName, String fieldPrettyName, int size, String type)
852    {
853  309 if (get(fieldName) == null) {
854  191 NumberClass number_class = new NumberClass();
855  191 number_class.setName(fieldName);
856  191 number_class.setPrettyName(fieldPrettyName);
857  191 number_class.setSize(size);
858  191 number_class.setNumberType(type);
859  191 number_class.setObject(this);
860  191 put(fieldName, number_class);
861   
862  191 return true;
863    }
864   
865  118 return false;
866    }
867   
 
868  116 toggle public boolean addDateField(String fieldName, String fieldPrettyName)
869    {
870  116 return addDateField(fieldName, fieldPrettyName, null, 1);
871    }
872   
 
873  0 toggle public boolean addDateField(String fieldName, String fieldPrettyName, String dformat)
874    {
875  0 return addDateField(fieldName, fieldPrettyName, dformat, 1);
876    }
877   
 
878  0 toggle public boolean addDateField(String fieldName, String fieldPrettyName, String dformat, int emptyIsToday)
879    {
880  0 if (get(fieldName) == null) {
881  0 DateClass date_class = new DateClass();
882  0 date_class.setName(fieldName);
883  0 date_class.setPrettyName(fieldPrettyName);
884  0 if (dformat != null) {
885  0 date_class.setDateFormat(dformat);
886    }
887  0 date_class.setObject(this);
888  0 date_class.setEmptyIsToday(emptyIsToday);
889  0 put(fieldName, date_class);
890   
891  0 return true;
892    }
893   
894  64 return false;
895    }
896   
 
897  188 toggle public boolean addDBListField(String fieldName, String fieldPrettyName, String sql)
898    {
899  188 return addDBListField(fieldName, fieldPrettyName, 1, false, sql);
900    }
901   
 
902  204 toggle public boolean addDBListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect, String sql)
903    {
904  204 return addDBListField(fieldName, fieldPrettyName, size, multiSelect, multiSelect, sql);
905    }
906   
907    /**
908    * @since 1.8M1
909    */
 
910  204 toggle public boolean addDBListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect,
911    boolean relationalStorage, String sql)
912    {
913  204 if (get(fieldName) == null) {
914  82 DBListClass list_class = new DBListClass();
915  82 list_class.setName(fieldName);
916  82 list_class.setPrettyName(fieldPrettyName);
917  82 list_class.setSize(size);
918  82 list_class.setMultiSelect(multiSelect);
919  82 list_class.setRelationalStorage(relationalStorage);
920  82 list_class.setSql(sql);
921  82 list_class.setObject(this);
922  82 put(fieldName, list_class);
923   
924  82 return true;
925    }
926   
927  122 return false;
928    }
929   
 
930  0 toggle public boolean addDBTreeListField(String fieldName, String fieldPrettyName, String sql)
931    {
932  0 return addDBTreeListField(fieldName, fieldPrettyName, 1, false, sql);
933    }
934   
 
935  0 toggle public boolean addDBTreeListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect,
936    String sql)
937    {
938  0 return addDBTreeListField(fieldName, fieldPrettyName, size, multiSelect, multiSelect, sql);
939    }
940   
941    /**
942    * @since 1.8M1
943    */
 
944  0 toggle public boolean addDBTreeListField(String fieldName, String fieldPrettyName, int size, boolean multiSelect,
945    boolean relationalStorage, String sql)
946    {
947  0 if (get(fieldName) == null) {
948  0 DBTreeListClass list_class = new DBTreeListClass();
949  0 list_class.setName(fieldName);
950  0 list_class.setPrettyName(fieldPrettyName);
951  0 list_class.setSize(size);
952  0 list_class.setMultiSelect(multiSelect);
953  0 list_class.setRelationalStorage(relationalStorage);
954  0 list_class.setSql(sql);
955  0 list_class.setObject(this);
956  0 put(fieldName, list_class);
957   
958  0 return true;
959    }
960   
961  0 return false;
962    }
963   
 
964  25931 toggle public void setCustomMapping(String customMapping)
965    {
966  25932 this.customMapping = customMapping;
967    }
968   
 
969  45347 toggle public String getCustomMapping()
970    {
971  45346 if ("XWiki.XWikiPreferences".equals(getName())) {
972  1625 return "internal";
973    }
974   
975  43720 if (this.customMapping == null) {
976  25004 return "";
977    }
978   
979  18715 return this.customMapping;
980    }
981   
 
982  9322 toggle public boolean hasCustomMapping()
983    {
984  9322 String cMapping = getCustomMapping();
985   
986  9322 return (cMapping != null) && (!"".equals(cMapping));
987    }
988   
 
989  2045 toggle public boolean hasExternalCustomMapping()
990    {
991  2045 String cMapping = getCustomMapping();
992   
993  2045 return (cMapping != null) && (!"".equals(cMapping)) && (!"internal".equals(cMapping));
994    }
995   
 
996  0 toggle public boolean hasInternalCustomMapping()
997    {
998  0 return "internal".equals(this.customMapping);
999    }
1000   
 
1001  0 toggle public boolean isCustomMappingValid(XWikiContext context) throws XWikiException
1002    {
1003  0 return isCustomMappingValid(getCustomMapping(), context);
1004    }
1005   
 
1006  0 toggle public boolean isCustomMappingValid(String custommapping, XWikiContext context) throws XWikiException
1007    {
1008  0 if ((custommapping != null) && (custommapping.trim().length() > 0)) {
1009  0 return context.getWiki().getStore().isCustomMappingValid(this, custommapping, context);
1010    } else {
1011  0 return true;
1012    }
1013    }
1014   
 
1015  330 toggle public List<String> getCustomMappingPropertyList(XWikiContext context)
1016    {
1017  330 String custommapping1 = getCustomMapping();
1018  330 if ((custommapping1 != null) && (custommapping1.trim().length() > 0)) {
1019  78 return context.getWiki().getStore().getCustomMappingPropertyList(this);
1020    } else {
1021  252 return new ArrayList<String>();
1022    }
1023    }
1024   
 
1025  25797 toggle public void setCustomClass(String customClass)
1026    {
1027  25799 this.customClass = customClass;
1028    }
1029   
 
1030  41452 toggle public String getCustomClass()
1031    {
1032  41451 if (this.customClass == null) {
1033  23704 return "";
1034    }
1035   
1036  17748 return this.customClass;
1037    }
1038   
 
1039  6727 toggle public BaseObject newCustomClassInstance(XWikiContext context) throws XWikiException
1040    {
1041  6727 String customClass = getCustomClass();
1042  6727 try {
1043  6727 if ((customClass == null) || (customClass.equals(""))) {
1044  6717 return new BaseObject();
1045    } else {
1046  10 return (BaseObject) Class
1047    .forName(getCustomClass(), true, Thread.currentThread().getContextClassLoader()).newInstance();
1048    }
1049    } catch (Exception e) {
1050  10 Object[] args = { customClass };
1051  10 throw new XWikiException(XWikiException.MODULE_XWIKI_CLASSES,
1052    XWikiException.ERROR_XWIKI_CLASSES_CUSTOMCLASSINVOCATIONERROR, "Cannot instanciate custom class {0}", e,
1053    args);
1054    }
1055    }
1056   
1057    /**
1058    * @since 2.2.3
1059    */
 
1060  6557 toggle public static BaseObject newCustomClassInstance(DocumentReference classReference, XWikiContext context)
1061    throws XWikiException
1062    {
1063  6557 BaseClass bclass = context.getWiki().getXClass(classReference, context);
1064  6557 BaseObject object = (bclass == null) ? new BaseObject() : bclass.newCustomClassInstance(context);
1065  6557 object.setXClassReference(classReference);
1066   
1067  6557 return object;
1068    }
1069   
1070    /**
1071    * @deprecated since 2.2.3 use {@link #newCustomClassInstance(DocumentReference, XWikiContext)}
1072    */
 
1073  1 toggle @Deprecated
1074    public static BaseObject newCustomClassInstance(String className, XWikiContext context) throws XWikiException
1075    {
1076  1 BaseClass bclass = context.getWiki().getClass(className, context);
1077  1 BaseObject object = (bclass == null) ? new BaseObject() : bclass.newCustomClassInstance(context);
1078   
1079  1 return object;
1080    }
1081   
 
1082  31585 toggle public String getDefaultWeb()
1083    {
1084  31588 if (this.defaultWeb == null) {
1085  20740 return "";
1086    }
1087   
1088  10847 return this.defaultWeb;
1089    }
1090   
 
1091  25799 toggle public void setDefaultWeb(String defaultWeb)
1092    {
1093  25798 this.defaultWeb = defaultWeb;
1094    }
1095   
 
1096  31583 toggle public String getDefaultViewSheet()
1097    {
1098  31586 if (this.defaultViewSheet == null) {
1099  20738 return "";
1100    }
1101   
1102  10847 return this.defaultViewSheet;
1103    }
1104   
 
1105  25798 toggle public void setDefaultViewSheet(String defaultViewSheet)
1106    {
1107  25796 this.defaultViewSheet = defaultViewSheet;
1108    }
1109   
 
1110  31585 toggle public String getDefaultEditSheet()
1111    {
1112  31585 if (this.defaultEditSheet == null) {
1113  20740 return "";
1114    }
1115   
1116  10847 return this.defaultEditSheet;
1117    }
1118   
 
1119  25798 toggle public void setDefaultEditSheet(String defaultEditSheet)
1120    {
1121  25797 this.defaultEditSheet = defaultEditSheet;
1122    }
1123   
 
1124  31585 toggle public String getNameField()
1125    {
1126  31588 if (this.nameField == null) {
1127  20736 return "";
1128    }
1129   
1130  10847 return this.nameField;
1131    }
1132   
 
1133  25794 toggle public void setNameField(String nameField)
1134    {
1135  25800 this.nameField = nameField;
1136    }
1137   
 
1138  5020 toggle public void setValidationScript(String validationScript)
1139    {
1140  5018 this.validationScript = validationScript;
1141    }
1142   
 
1143  10691 toggle public String getValidationScript()
1144    {
1145  10691 if (this.validationScript == null) {
1146  5933 return "";
1147    } else {
1148  4758 return this.validationScript;
1149    }
1150    }
1151   
 
1152  6 toggle public boolean validateObject(BaseObject obj, XWikiContext context) throws XWikiException
1153    {
1154  6 boolean isValid = true;
1155  6 Object[] props = getPropertyNames();
1156  6 for (Object prop : props) {
1157  42 String propname = (String) prop;
1158  42 BaseProperty property = (BaseProperty) obj.get(propname);
1159  42 PropertyClass propclass = (PropertyClass) get(propname);
1160  42 isValid &= propclass.validateProperty(property, context);
1161    }
1162   
1163  6 String validSript = getValidationScript();
1164  6 if ((validSript != null) && (!validSript.trim().equals(""))) {
1165  2 isValid &= executeValidationScript(obj, validSript, context);
1166    }
1167   
1168  6 return isValid;
1169    }
1170   
 
1171  2 toggle private boolean executeValidationScript(BaseObject obj, String validationScript, XWikiContext context)
1172    {
1173  2 try {
1174  2 ContextualAuthorizationManager authorization = Utils.getComponent(ContextualAuthorizationManager.class);
1175  2 DocumentReference validationScriptReference =
1176    getCurrentDocumentReferenceResolver().resolve(validationScript, getDocumentReference());
1177   
1178    // Make sure target document is allowed to execute Groovy
1179    // TODO: this check should probably be right in XWiki#parseGroovyFromPage
1180  2 authorization.checkAccess(Right.PROGRAM, validationScriptReference);
1181   
1182  1 XWikiValidationInterface validObject =
1183    (XWikiValidationInterface) context.getWiki().parseGroovyFromPage(validationScript, context);
1184   
1185  1 return validObject.validateObject(obj, context);
1186    } catch (Throwable e) {
1187  1 XWikiValidationStatus.addExceptionToContext(getName(), "", e, context);
1188  1 return false;
1189    }
1190    }
1191   
 
1192  0 toggle public void flushCache()
1193    {
1194  0 Object[] props = getPropertyNames();
1195  0 for (Object prop : props) {
1196  0 String propname = (String) prop;
1197  0 PropertyClass propclass = (PropertyClass) get(propname);
1198  0 if (propclass != null) {
1199  0 propclass.flushCache();
1200    }
1201    }
1202    }
1203   
 
1204  516 toggle @Override
1205    public List<ObjectDiff> getDiff(Object oldObject, XWikiContext context)
1206    {
1207  516 ArrayList<ObjectDiff> difflist = new ArrayList<ObjectDiff>();
1208  516 BaseClass oldClass = (BaseClass) oldObject;
1209  516 for (PropertyClass newProperty : (Collection<PropertyClass>) getFieldList()) {
1210  7686 String propertyName = newProperty.getName();
1211  7686 PropertyClass oldProperty = (PropertyClass) oldClass.get(propertyName);
1212  7686 String propertyType = newProperty.getClassType();
1213   
1214  7686 if (oldProperty == null) {
1215  11 difflist.add(new ObjectDiff(getXClassReference(), getNumber(), "", ObjectDiff.ACTION_PROPERTYADDED,
1216    propertyName, propertyType, "", ""));
1217  7675 } else if (!oldProperty.equals(newProperty)) {
1218  7 difflist.add(new ObjectDiff(getXClassReference(), getNumber(), "", ObjectDiff.ACTION_PROPERTYCHANGED,
1219    propertyName, propertyType, "", ""));
1220    }
1221    }
1222   
1223  516 for (PropertyClass oldProperty : (Collection<PropertyClass>) oldClass.getFieldList()) {
1224  7676 String propertyName = oldProperty.getName();
1225  7676 PropertyClass newProperty = (PropertyClass) get(propertyName);
1226  7676 String propertyType = oldProperty.getClassType();
1227   
1228  7676 if (newProperty == null) {
1229  1 difflist.add(new ObjectDiff(getXClassReference(), getNumber(), "", ObjectDiff.ACTION_PROPERTYREMOVED,
1230    propertyName, propertyType, "", ""));
1231    }
1232    }
1233   
1234  516 return difflist;
1235    }
1236   
 
1237  54 toggle @Override
1238    public void merge(ElementInterface previousElement, ElementInterface newElement, MergeConfiguration configuration,
1239    XWikiContext context, MergeResult mergeResult)
1240    {
1241  54 BaseClass previousClass = (BaseClass) previousElement;
1242  54 BaseClass newClass = (BaseClass) newElement;
1243   
1244  54 setCustomClass(MergeUtils.mergeOject(previousClass.getCustomClass(), newClass.getCustomClass(),
1245    getCustomClass(), mergeResult));
1246   
1247  54 setCustomMapping(MergeUtils.mergeOject(previousClass.getCustomMapping(), newClass.getCustomMapping(),
1248    getCustomMapping(), mergeResult));
1249   
1250  54 setDefaultWeb(MergeUtils.mergeOject(previousClass.getDefaultWeb(), newClass.getDefaultWeb(), getDefaultWeb(),
1251    mergeResult));
1252   
1253  54 setDefaultViewSheet(MergeUtils.mergeOject(previousClass.getDefaultViewSheet(), newClass.getDefaultViewSheet(),
1254    getDefaultViewSheet(), mergeResult));
1255   
1256  54 setDefaultEditSheet(MergeUtils.mergeOject(previousClass.getDefaultEditSheet(), newClass.getDefaultEditSheet(),
1257    getDefaultEditSheet(), mergeResult));
1258   
1259  54 setNameField(
1260    MergeUtils.mergeOject(previousClass.getNameField(), newClass.getNameField(), getNameField(), mergeResult));
1261   
1262    // Properties
1263   
1264  54 super.merge(previousElement, newElement, configuration, context, mergeResult);
1265    }
1266   
 
1267  6 toggle @Override
1268    public boolean apply(ElementInterface newElement, boolean clean)
1269    {
1270  6 boolean modified = super.apply(newElement, clean);
1271   
1272  6 BaseClass newBaseClass = (BaseClass) newElement;
1273   
1274  6 if (!StringUtils.equals(getCustomClass(), newBaseClass.getCustomClass())) {
1275  0 setCustomClass(newBaseClass.getCustomClass());
1276  0 modified = true;
1277    }
1278   
1279  6 if (!StringUtils.equals(getCustomMapping(), newBaseClass.getCustomMapping())) {
1280  0 setCustomMapping(newBaseClass.getCustomMapping());
1281  0 modified = true;
1282    }
1283   
1284  6 if (!StringUtils.equals(getDefaultWeb(), newBaseClass.getDefaultWeb())) {
1285  0 setDefaultWeb(newBaseClass.getDefaultWeb());
1286  0 modified = true;
1287    }
1288   
1289  6 if (!StringUtils.equals(getDefaultViewSheet(), newBaseClass.getDefaultViewSheet())) {
1290  0 setDefaultViewSheet(newBaseClass.getDefaultViewSheet());
1291  0 modified = true;
1292    }
1293   
1294  6 if (!StringUtils.equals(getDefaultEditSheet(), newBaseClass.getDefaultEditSheet())) {
1295  0 setDefaultEditSheet(newBaseClass.getDefaultEditSheet());
1296  0 modified = true;
1297    }
1298   
1299  6 if (!StringUtils.equals(getNameField(), newBaseClass.getNameField())) {
1300  0 setNameField(newBaseClass.getNameField());
1301  0 modified = true;
1302    }
1303   
1304  6 return modified;
1305    }
1306   
1307    /**
1308    * Set the owner document of this base property.
1309    *
1310    * @param ownerDocument The owner document.
1311    * @since 4.3M2
1312    */
 
1313  81059 toggle @Override
1314    public void setOwnerDocument(XWikiDocument ownerDocument)
1315    {
1316  81062 super.setOwnerDocument(ownerDocument);
1317   
1318  81062 if (this.ownerDocument != null) {
1319  81017 setDocumentReference(this.ownerDocument.getDocumentReference());
1320    }
1321   
1322  81060 if (ownerDocument != null && this.isDirty) {
1323  5281 ownerDocument.setMetaDataDirty(true);
1324    }
1325    }
1326   
1327    /**
1328    * @param isDirty Indicate if the dirty flag should be set or cleared.
1329    * @since 4.3M2
1330    */
 
1331  110655 toggle public void setDirty(boolean isDirty)
1332    {
1333  110652 this.isDirty = isDirty;
1334  110653 if (isDirty && this.ownerDocument != null) {
1335  17025 this.ownerDocument.setMetaDataDirty(true);
1336    }
1337    }
1338    }