1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package com.xpn.xwiki.objects

File BaseElement.java

 

Coverage histogram

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

Code metrics

48
105
29
1
482
280
61
0.58
3.62
29
2.1

Classes

Class Line # Actions
BaseElement 56 105 0% 61 40
0.780219878%
 

Contributing tests

This file is covered by 282 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.io.IOException;
23    import java.io.Serializable;
24    import java.io.StringWriter;
25   
26    import javax.inject.Provider;
27   
28    import org.apache.commons.lang3.StringUtils;
29    import org.dom4j.Element;
30    import org.dom4j.io.DocumentResult;
31    import org.slf4j.Logger;
32    import org.slf4j.LoggerFactory;
33    import org.xwiki.filter.input.StringInputSource;
34    import org.xwiki.filter.xar.output.XAROutputProperties;
35    import org.xwiki.filter.xml.output.DefaultResultOutputTarget;
36    import org.xwiki.localization.ContextualLocalizationManager;
37    import org.xwiki.model.reference.DocumentReference;
38    import org.xwiki.model.reference.EntityReference;
39    import org.xwiki.model.reference.EntityReferenceSerializer;
40   
41    import com.xpn.xwiki.XWikiContext;
42    import com.xpn.xwiki.XWikiException;
43    import com.xpn.xwiki.doc.XWikiDocument;
44    import com.xpn.xwiki.doc.merge.MergeConfiguration;
45    import com.xpn.xwiki.doc.merge.MergeResult;
46    import com.xpn.xwiki.internal.filter.XWikiDocumentFilterUtils;
47    import com.xpn.xwiki.internal.merge.MergeUtils;
48    import com.xpn.xwiki.util.Util;
49    import com.xpn.xwiki.web.Utils;
50   
51    /**
52    * Base class for representing an element having a name (either a reference of a free form name) and a pretty name.
53    *
54    * @version $Id: c77bd51f37733c4611d22198473a4558768cb30b $
55    */
 
56    public abstract class BaseElement<R extends EntityReference> implements ElementInterface, Serializable
57    {
58    protected static final Logger LOGGER = LoggerFactory.getLogger(BaseObject.class);
59   
60    /**
61    * Full reference of this element.
62    *
63    * @since 3.2M1
64    */
65    protected R referenceCache;
66   
67    /**
68    * Reference to the document in which this element is defined (for elements where this make sense, for example for
69    * an XClass or a XObject).
70    *
71    * @since 5.3M1
72    */
73    protected DocumentReference documentReference;
74   
75    /**
76    * The owner document, if this element was obtained from a document.
77    *
78    * @since 5.3M1
79    */
80    protected transient XWikiDocument ownerDocument;
81   
82    /**
83    * Free form name (for elements which don't point to a reference, for example for instances of {@link BaseProperty}
84    * ).
85    */
86    private String name;
87   
88    private String prettyName;
89   
90    /**
91    * Used to convert a proper Document Reference to a string but without the wiki name.
92    */
93    private EntityReferenceSerializer<String> localEntityReferenceSerializer;
94   
95    /**
96    * Used to build uid string for the getId() hash.
97    */
98    private EntityReferenceSerializer<String> localUidStringEntityReferenceSerializer;
99   
100    private ContextualLocalizationManager localization;
101   
 
102  3558627 toggle @Override
103    public R getReference()
104    {
105  3558989 if (this.referenceCache == null) {
106  921667 this.referenceCache = createReference();
107    }
108   
109  3558868 return this.referenceCache;
110    }
111   
112    /**
113    * @since 3.2M1
114    */
 
115  0 toggle protected R createReference()
116    {
117  0 return null;
118    }
119   
 
120  2876840 toggle @Override
121    public DocumentReference getDocumentReference()
122    {
123    // Object using name without setting a reference are not allowed to retrieve the reference
124  2876893 if (this.documentReference == null && this.name != null) {
125  0 throw new IllegalStateException(
126    "BaseElement#getDocumentReference could not be called when a non-reference Name has been set.");
127    }
128   
129  2876823 return this.documentReference;
130    }
131   
132    /**
133    * {@inheritDoc}
134    * <p>
135    * Note that this method is used by Hibernate for saving an element.
136    * </p>
137    *
138    * @see com.xpn.xwiki.objects.ElementInterface#getName()
139    */
 
140  24125779 toggle @Override
141    public String getName()
142    {
143    // If the name is null then serialize the reference as a string.
144  24126060 if (this.name == null && this.documentReference != null) {
145  80859 this.name = getLocalEntityReferenceSerializer().serialize(this.documentReference);
146    }
147   
148  24126140 return this.name;
149    }
150   
 
151  3076627 toggle @Override
152    public void setDocumentReference(DocumentReference reference)
153    {
154    // If the name is already set then reset it since we're now using a reference
155  3076622 this.documentReference = reference;
156  3076591 this.name = null;
157  3076591 this.referenceCache = null;
158    }
159   
160    /**
161    * {@inheritDoc}
162    * <p>
163    * Note that this method is used by Hibernate for loading an element.
164    * </p>
165    *
166    * @see com.xpn.xwiki.objects.ElementInterface#setName(java.lang.String)
167    */
 
168  16960857 toggle @Override
169    public void setName(String name)
170    {
171    // If a reference is already set, then you cannot set a name
172  16960946 if (this.documentReference != null) {
173  0 throw new IllegalStateException("BaseElement#setName could not be called when a reference has been set.");
174    }
175   
176  16960853 this.name = name;
177  16960863 this.referenceCache = null;
178    }
179   
 
180  11876971 toggle public String getPrettyName()
181    {
182  11876977 return this.prettyName;
183    }
184   
 
185  11111636 toggle public void setPrettyName(String name)
186    {
187  11111510 this.prettyName = name;
188    }
189   
190    /**
191    * @return the component used to build uid string for the getId() hash
192    * @since 4.0M1
193    */
 
194  1735235 toggle protected EntityReferenceSerializer<String> getLocalUidStringEntityReferenceSerializer()
195    {
196  1735261 if (this.localUidStringEntityReferenceSerializer == null) {
197  70637 this.localUidStringEntityReferenceSerializer =
198    Utils.getComponent(EntityReferenceSerializer.TYPE_STRING, "local/uid");
199    }
200   
201  1735293 return this.localUidStringEntityReferenceSerializer;
202    }
203   
204    /**
205    * @return the component used to convert a proper Document Reference to a string but without the wiki name.
206    * @since 6.3M1
207    */
 
208  120469 toggle protected EntityReferenceSerializer<String> getLocalEntityReferenceSerializer()
209    {
210  120466 if (this.localEntityReferenceSerializer == null) {
211  58567 this.localEntityReferenceSerializer = Utils.getComponent(EntityReferenceSerializer.TYPE_STRING, "local");
212    }
213   
214  120467 return this.localEntityReferenceSerializer;
215    }
216   
 
217  41422 toggle protected ContextualLocalizationManager getLocalization()
218    {
219  41422 if (this.localization == null) {
220  2910 this.localization = Utils.getComponent(ContextualLocalizationManager.class);
221    }
222   
223  41422 return this.localization;
224    }
225   
 
226  41422 toggle protected String localizePlain(String key, Object... parameters)
227    {
228  41422 return getLocalization().getTranslationPlain(key, parameters);
229    }
230   
 
231  0 toggle protected String localizePlainOrKey(String key, Object... parameters)
232    {
233  0 return StringUtils.defaultString(getLocalization().getTranslationPlain(key, parameters), key);
234    }
235   
236    /**
237    * @return a unique identifier representing this element reference to be used for {@code hashCode()}.
238    * @since 4.0M1
239    */
 
240  1734833 toggle protected String getLocalKey()
241    {
242    // The R40000XWIKI6990DataMigration use the same algorithm to compute object id. It should be properly synced.
243  1735362 return getLocalUidStringEntityReferenceSerializer().serialize(getReference());
244    }
245   
246    /**
247    * Return an truncated MD5 hash of the local key computed in {@link #getLocalKey()}.
248    *
249    * @return the identifier used by hibernate for storage.
250    * @since 4.0M1
251    */
 
252  1734912 toggle public long getId()
253    {
254  1735334 String key = getLocalKey();
255   
256  1735404 if (key != null) {
257    // The R40000XWIKI6990DataMigration use the same algorithm to compute object id. It should be properly
258    // synced.
259  1735352 return Util.getHash(key);
260    }
261   
262  2 return 0;
263    }
264   
265    /**
266    * Dummy function, do hibernate is always happy.
267    *
268    * @param id the identifier assigned by hibernate.
269    * @since 4.0M1
270    */
 
271  67708 toggle public void setId(long id)
272    {
273    }
274   
 
275  2 toggle @Override
276    public int hashCode()
277    {
278  2 return (int) Util.getHash(getLocalKey());
279    }
280   
 
281  165907 toggle @Override
282    public boolean equals(Object el)
283    {
284    // Same Java object, they sure are equal
285  165907 if (this == el) {
286  0 return true;
287    }
288   
289  165907 if (el == null || !(el.getClass().equals(this.getClass()))) {
290  62 return false;
291    }
292   
293  165845 BaseElement element = (BaseElement) el;
294   
295  165845 if (element.documentReference != null) {
296  4374 if (!element.documentReference.equals(this.documentReference)) {
297  22 return false;
298    }
299    } else {
300  161471 if (this.documentReference != null) {
301  0 return false;
302    }
303  161471 if (element.name == null) {
304  14270 if (this.name != null) {
305  0 return false;
306    }
307  147201 } else if (!element.name.equals(this.name)) {
308  0 return false;
309    }
310    }
311   
312  165823 if (element.getPrettyName() == null) {
313  151553 if (getPrettyName() != null) {
314  0 return false;
315    }
316  14270 } else if (!element.getPrettyName().equals(getPrettyName())) {
317  32 return false;
318    }
319   
320  165791 return true;
321    }
322   
 
323  11542890 toggle @Override
324    public BaseElement clone()
325    {
326  11542896 BaseElement element;
327  11542909 try {
328  11542910 element = (BaseElement) super.clone();
329   
330  11542818 element.setOwnerDocument(getOwnerDocument());
331   
332    // Make sure we clone either the reference or the name depending on which one is used.
333  11542696 if (this.documentReference != null) {
334  718345 element.setDocumentReference(getDocumentReference());
335  10824389 } else if (this.name != null) {
336  10391650 element.setName(getName());
337    }
338   
339  11542714 element.setPrettyName(getPrettyName());
340    } catch (Exception e) {
341    // This should not happen
342  0 element = null;
343    }
344   
345  11542660 return element;
346    }
347   
 
348  1 toggle @Override
349    public void merge(ElementInterface previousElement, ElementInterface newElement, MergeConfiguration configuration,
350    XWikiContext context, MergeResult mergeResult)
351    {
352  1 setPrettyName(MergeUtils.mergeOject(((BaseElement) previousElement).getPrettyName(),
353    ((BaseElement) newElement).getPrettyName(), getPrettyName(), mergeResult));
354    }
355   
 
356  230041 toggle @Override
357    public boolean apply(ElementInterface newElement, boolean clean)
358    {
359  230041 boolean modified = false;
360   
361  230041 BaseElement<R> newBaseElement = (BaseElement<R>) newElement;
362   
363    // Pretty name
364  230041 if (!StringUtils.equals(newBaseElement.getPrettyName(), getPrettyName())) {
365  0 setPrettyName(newBaseElement.getPrettyName());
366  0 modified = true;
367    }
368   
369  230041 return modified;
370    }
371   
372    /**
373    * Set the owner document of this element.
374    *
375    * @param ownerDocument The owner document.
376    * @since 5.3M1
377    */
 
378  56340965 toggle public void setOwnerDocument(XWikiDocument ownerDocument)
379    {
380  56338599 this.ownerDocument = ownerDocument;
381    }
382   
383    /**
384    * @return the owner document of this element.
385    * @since 5.3M1
386    */
 
387  15694690 toggle public XWikiDocument getOwnerDocument()
388    {
389  15694709 return this.ownerDocument;
390    }
391   
392    /**
393    * Get XWiki context from execution context.
394    *
395    * @return the XWiki context for the current thread
396    * @since 9.0RC1
397    */
 
398  0 toggle protected XWikiContext getXWikiContext()
399    {
400  0 Provider<XWikiContext> xcontextProvider = Utils.getComponent(XWikiContext.TYPE_PROVIDER);
401   
402  0 if (xcontextProvider != null) {
403  0 return xcontextProvider.get();
404    }
405   
406  0 return null;
407    }
408   
 
409  2 toggle protected void fromXML(Element oel) throws XWikiException
410    {
411    // Serialize the Document (could not find a way to convert a dom4j Element into a usable StAX source)
412  2 StringWriter writer = new StringWriter();
413  2 try {
414  2 org.dom4j.io.XMLWriter domWriter = new org.dom4j.io.XMLWriter(writer);
415  2 domWriter.write(oel);
416  2 domWriter.flush();
417    } catch (IOException e) {
418  0 throw new XWikiException(XWikiException.MODULE_XWIKI_DOC, XWikiException.ERROR_DOC_XML_PARSING,
419    "Error parsing xml", e, null);
420    }
421   
422    // Actually parse the XML
423  2 fromXML(writer.toString());
424    }
425   
426    /**
427    * @param source the XML to read
428    * @throws XWikiException when failing to parse XML
429    */
 
430  24769 toggle public void fromXML(String source) throws XWikiException
431    {
432  24775 if (!source.isEmpty()) {
433  4997 try {
434  4996 Utils.getComponent(XWikiDocumentFilterUtils.class).importEntity(this, new StringInputSource(source));
435    } catch (Exception e) {
436  0 throw new XWikiException(XWikiException.MODULE_XWIKI_DOC, XWikiException.ERROR_DOC_XML_PARSING,
437    "Error parsing xml", e, null);
438    }
439    }
440    }
441   
 
442  0 toggle protected Element toXML()
443    {
444  0 DocumentResult domResult = new DocumentResult();
445   
446  0 try {
447  0 Utils.getComponent(XWikiDocumentFilterUtils.class).exportEntity(this,
448    new DefaultResultOutputTarget(domResult));
449    } catch (Exception e) {
450  0 LOGGER.error("Failed to serialize element to XML", e);
451   
452  0 return null;
453    }
454   
455  0 return domResult.getDocument().getRootElement();
456    }
457   
458    /**
459    * @param format true if the XML should be formated
460    * @return the XML as a String
461    * @since 9.0RC1
462    */
 
463  1885 toggle public String toXMLString(boolean format)
464    {
465  1885 XAROutputProperties xarProperties = new XAROutputProperties();
466  1885 xarProperties.setFormat(false);
467   
468  1885 try {
469  1885 return Utils.getComponent(XWikiDocumentFilterUtils.class).exportEntity(this, xarProperties);
470    } catch (Exception e) {
471  0 LOGGER.error("Failed to serialize collection to XML", e);
472   
473  0 return "";
474    }
475    }
476   
 
477  2 toggle @Override
478    public String toString()
479    {
480  2 return toXMLString(true);
481    }
482    }