View Javadoc
1   /*
2    * This file is part of ***  M y C o R e  ***
3    * See http://www.mycore.de/ for details.
4    *
5    * MyCoRe is free software: you can redistribute it and/or modify
6    * it under the terms of the GNU General Public License as published by
7    * the Free Software Foundation, either version 3 of the License, or
8    * (at your option) any later version.
9    *
10   * MyCoRe 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
13   * GNU General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License
16   * along with MyCoRe.  If not, see <http://www.gnu.org/licenses/>.
17   */
18  
19  package org.mycore.datamodel.metadata;
20  
21  import static org.mycore.common.MCRConstants.XLINK_NAMESPACE;
22  
23  import java.util.Objects;
24  
25  import org.apache.logging.log4j.LogManager;
26  import org.apache.logging.log4j.Logger;
27  import org.apache.xml.utils.XMLChar;
28  import org.jdom2.Element;
29  import org.mycore.common.MCRException;
30  import org.mycore.common.MCRUtils;
31  
32  import com.google.gson.JsonObject;
33  
34  /**
35   * This class implements all method for generic handling with the MCRMetaLink part of a metadata object.
36   * The MCRMetaLink class present two types. At once a reference to an URL.
37   * At second a bidirectional link between two URL's. Optional you can append the reference with the label attribute.
38   * See to W3C XLink Standard for more informations.
39   * <p>
40   * &lt;tag class="MCRMetaLink"&gt; <br>
41   * &lt;subtag xlink:type="locator" xlink:href=" <em>URL</em>" xlink:label="..." xlink:title="..."/&gt; <br>
42   * &lt;subtag xlink:type="arc" xlink:from=" <em>URL</em>" xlink:to="URL"/&gt; <br>
43   * &lt;/tag&gt; <br>
44   * 
45   * @author Jens Kupferschmidt
46   */
47  public class MCRMetaLink extends MCRMetaDefault {
48      // MetaLink data
49      protected String href;
50  
51      protected String label;
52  
53      protected String title;
54  
55      protected String linktype;
56  
57      protected String role;
58  
59      protected String from;
60  
61      protected String to;
62  
63      private static final Logger LOGGER = LogManager.getLogger();
64  
65      /**
66       * initializes with empty values.
67       */
68      public MCRMetaLink() {
69          super();
70      }
71  
72      /**
73       * This is the constructor. <br>
74       * The language element was set. If the value of <em>default_lang</em> is null, empty or false <b>en </b> was set.
75       * The subtag element was set to the value of <em>subtag</em>.
76       * If the value of <em>subtag</em> is null or empty an exception was throwed.
77       * @param subtag
78       *            the name of the subtag
79       * @param inherted
80       *            a value &gt;= 0
81       * @exception MCRException
82       *                if the set_datapart or subtag value is null or empty
83       */
84      public MCRMetaLink(String subtag, int inherted) throws MCRException {
85          super(subtag, null, null, inherted);
86      }
87  
88      /**
89       * This method set a reference with xlink:href, xlink:label and xlink:title.
90       * 
91       * @param href
92       *            the reference
93       * @param label
94       *            the new label string
95       * @param title
96       *            the new title string
97       * @exception MCRException
98       *                if the href value is null or empty
99       */
100     public void setReference(String href, String label, String title) throws MCRException {
101         linktype = "locator";
102 
103         this.href = MCRUtils.filterTrimmedNotEmpty(href)
104             .orElseThrow(() -> new MCRException("The href value is null or empty."));
105         setXLinkLabel(label);
106         this.title = title;
107     }
108 
109     /**
110      * This method set a bidirectional link with xlink:from, xlink:to and xlink:title.
111      * 
112      * @param from
113      *            the source
114      * @param to
115      *            the target
116      * @param title
117      *            the new title string
118      * @exception MCRException
119      *                if the from or to element is null or empty
120      */
121     public void setBiLink(String from, String to, String title) throws MCRException {
122         this.from = MCRUtils.filterTrimmedNotEmpty(from)
123             .orElseThrow(() -> new MCRException("The from value is null or empty."));
124         this.to = MCRUtils.filterTrimmedNotEmpty(to)
125             .orElseThrow(() -> new MCRException("The to value is null or empty."));
126         linktype = "arc";
127         this.title = title;
128     }
129 
130     /**
131      * This method get the xlink:type element.
132      * 
133      * @return the xlink:type
134      */
135     public final String getXLinkType() {
136         return linktype;
137     }
138 
139     /**
140      * This method get the xlink:href element as string.
141      * 
142      * @return the xlink:href element as string
143      */
144     public final String getXLinkHref() {
145         return href;
146     }
147 
148     /**
149      * This method get the xlink:label element.
150      * 
151      * @return the xlink:label
152      */
153     public final String getXLinkLabel() {
154         return label;
155     }
156 
157     /**
158      * This method set the xlink:label
159      * 
160      * @param label
161      *            the xlink:label
162      */
163     public final void setXLinkLabel(String label) {
164         if (label != null && !XMLChar.isValidNCName(label)) {
165             throw new MCRException("xlink:label is not a valid NCName: " + label);
166         }
167         this.label = label;
168     }
169 
170     /**
171      * This method get the xlink:title element.
172      * 
173      * @return the xlink:title
174      */
175     public final String getXLinkTitle() {
176         return title;
177     }
178 
179     /**
180      * This method set the xlink:title
181      * 
182      * @param title
183      *            the xlink:title
184      */
185     public final void setXLinkTitle(String title) {
186         this.title = title;
187     }
188 
189     /**
190      * This method get the xlink:from element as string.
191      * 
192      * @return the xlink:from element as string
193      */
194     public final String getXLinkFrom() {
195         return from;
196     }
197 
198     /**
199      * This method get the xlink:to element as string.
200      * 
201      * @return the xlink:to element as string
202      */
203     public final String getXLinkTo() {
204         return to;
205     }
206 
207     /**
208      * This method sets the xlink:role.
209      * 
210      */
211     public void setXLinkRole(String role) {
212         this.role = role;
213     }
214 
215     /**
216      * This method get the xlink:role element as string.
217      * 
218      */
219     public String getXLinkRole() {
220         return role;
221     }
222 
223     /**
224      * The method compare this instance of MCRMetaLink with a input object of the class type MCRMetaLink.
225      * The both instances are equal, if: <br>
226      * <ul>
227      * <li>for the type 'arc' the 'from' and 'to' element is equal</li>
228      * <li>for the type 'locator' the 'href' element is equal</li>
229      * </ul>
230      * <br>
231      * 
232      * @param input
233      *            the MCRMetaLink input
234      * @return true if it is compare, else return false
235      */
236     public final boolean compare(MCRMetaLink input) {
237         if (linktype.equals("locator")) {
238             if (linktype.equals(input.getXLinkType()) && href.equals(input.getXLinkHref())) {
239                 return true;
240             }
241         }
242 
243         if (linktype.equals("arc")) {
244             return linktype.equals(input.getXLinkType()) && from.equals(input.getXLinkFrom())
245                 && to.equals(input.getXLinkTo());
246         }
247 
248         return false;
249     }
250 
251     @Override
252     public int hashCode() {
253         return Objects.hash(super.hashCode(), from, href, label, linktype, role, title, to);
254     }
255 
256     @Override
257     public boolean equals(Object obj) {
258         if (!super.equals(obj)) {
259             return false;
260         }
261         MCRMetaLink other = (MCRMetaLink) obj;
262         if (!Objects.equals(from, other.from)) {
263             return false;
264         } else if (!Objects.equals(href, other.href)) {
265             return false;
266         } else if (!Objects.equals(label, other.label)) {
267             return false;
268         } else if (!Objects.equals(linktype, other.linktype)) {
269             return false;
270         } else if (!Objects.equals(role, other.role)) {
271             return false;
272         } else if (!Objects.equals(title, other.title)) {
273             return false;
274         } else {
275             return Objects.equals(to, other.to);
276         }
277     }
278 
279     /**
280      * This method read the XML input stream part from a DOM part for the metadata of the document.
281      * 
282      * @param element
283      *            a relevant DOM element for the metadata
284      * @exception MCRException
285      *                if the xlink:type is not locator or arc or if href or from and to are null or empty
286      */
287     @Override
288     public void setFromDOM(Element element) throws MCRException {
289         super.setFromDOM(element);
290 
291         String temp = element.getAttributeValue("type", XLINK_NAMESPACE);
292 
293         if (temp != null && (temp.equals("locator") || temp.equals("arc"))) {
294             linktype = temp;
295         } else {
296             throw new MCRException("The xlink:type is not locator or arc.");
297         }
298 
299         if (linktype.equals("locator")) {
300             String temp1 = element.getAttributeValue("href", XLINK_NAMESPACE);
301             String temp2 = element.getAttributeValue("label", XLINK_NAMESPACE);
302             String temp3 = element.getAttributeValue("title", XLINK_NAMESPACE);
303             setReference(temp1, temp2, temp3);
304         } else {
305             String temp1 = element.getAttributeValue("from", XLINK_NAMESPACE);
306             String temp2 = element.getAttributeValue("to", XLINK_NAMESPACE);
307             String temp3 = element.getAttributeValue("title", XLINK_NAMESPACE);
308             setBiLink(temp1, temp2, temp3);
309         }
310 
311         setXLinkRole(element.getAttributeValue("role", XLINK_NAMESPACE));
312     }
313 
314     /**
315      * This method create a XML stream for all data in this class,
316      * defined by the MyCoRe XML MCRMetaLink definition for the given subtag.
317      * 
318      * @exception MCRException
319      *                if the content of this class is not valid
320      * @return a JDOM Element with the XML MCRMetaLink part
321      */
322     @Override
323     public Element createXML() throws MCRException {
324         Element elm = super.createXML();
325         elm.setAttribute("type", linktype, XLINK_NAMESPACE);
326 
327         if (title != null) {
328             elm.setAttribute("title", title, XLINK_NAMESPACE);
329         }
330 
331         if (label != null) {
332             elm.setAttribute("label", label, XLINK_NAMESPACE);
333         }
334 
335         if (role != null) {
336             elm.setAttribute("role", role, XLINK_NAMESPACE);
337         }
338 
339         if (linktype.equals("locator")) {
340             elm.setAttribute("href", href, XLINK_NAMESPACE);
341         } else {
342             elm.setAttribute("from", from, XLINK_NAMESPACE);
343             elm.setAttribute("to", to, XLINK_NAMESPACE);
344         }
345 
346         return elm;
347     }
348 
349     /**
350      * Creates the JSON representation. Extends the {@link MCRMetaDefault#createJSON()} method
351      * with the following data.
352      * 
353      * For linktype equals 'locator':
354      * <pre>
355      *   {
356      *     label: "MyCoRe Derivate Image",
357      *     title: "MyCoRe Derivate Image",
358      *     role: "image_reference",
359      *     href: "mycore_derivate_00000001/image.tif"
360      *   }
361      * </pre>
362      * 
363      * For all other linktypes (arc):
364      * <pre>
365      *   {
366      *     label: "Link between Issue and Person",
367      *     title: "Link between Issue and Person",
368      *     role: "link",
369      *     from: "mycore_issue_00000001",
370      *     to: "mycore_person_00000001"
371      *   }
372      * </pre>
373      */
374     @Override
375     public JsonObject createJSON() {
376         JsonObject obj = super.createJSON();
377         if (title != null) {
378             obj.addProperty("title", title);
379         }
380         if (label != null) {
381             obj.addProperty("label", label);
382         }
383         if (role != null) {
384             obj.addProperty("role", role);
385         }
386         if (linktype.equals("locator")) {
387             obj.addProperty("href", href);
388         } else {
389             obj.addProperty("from", from);
390             obj.addProperty("to", to);
391         }
392         return obj;
393     }
394 
395     /**
396      * Validates this MCRMetaLink. This method throws an exception if:
397      * <ul>
398      * <li>the subtag is not null or empty</li>
399      * <li>the xlink:type not "locator" or "arc"</li>
400      * <li>the from or to are not valid</li>
401      * </ul>
402      * 
403      * @throws MCRException the MCRMetaLink is invalid
404      */
405     public void validate() throws MCRException {
406         super.validate();
407         if (label != null && label.length() > 0) {
408             if (!XMLChar.isValidNCName(label)) {
409                 throw new MCRException(getSubTag() + ": label is no valid NCName:" + label);
410             }
411         }
412         if (linktype == null) {
413             throw new MCRException(getSubTag() + ": linktype is null");
414         }
415         if (!linktype.equals("locator") && !linktype.equals("arc")) {
416             throw new MCRException(getSubTag() + ": linktype is unsupported: " + linktype);
417         }
418         if (linktype.equals("arc")) {
419             if (from == null || from.length() == 0) {
420                 throw new MCRException(getSubTag() + ": from is null or empty");
421             } else if (!XMLChar.isValidNCName(from)) {
422                 throw new MCRException(getSubTag() + ": from is no valid NCName:" + from);
423             }
424 
425             if (to == null || to.length() == 0) {
426                 throw new MCRException(getSubTag() + ": to is null or empty");
427             } else if (!XMLChar.isValidNCName(to)) {
428                 throw new MCRException(getSubTag() + ": to is no valid NCName:" + to);
429             }
430         }
431         if (linktype.equals("locator")) {
432             if (href == null || href.length() == 0) {
433                 throw new MCRException(getSubTag() + ": href is null or empty");
434             }
435         }
436     }
437 
438     /**
439      * clone of this instance
440      * 
441      * you will get a (deep) clone of this element
442      * 
443      * @see java.lang.Object#clone()
444      */
445     @Override
446     public MCRMetaLink clone() {
447         MCRMetaLink clone = (MCRMetaLink) super.clone();
448 
449         clone.href = this.href;
450         clone.label = this.label;
451         clone.title = this.title;
452         clone.linktype = this.linktype;
453         clone.role = this.role;
454         clone.from = this.from;
455         clone.to = this.to;
456 
457         return clone;
458     }
459 
460     /**
461      * This method put debug data to the logger (for the debug mode).
462      */
463     @Override
464     public final void debug() {
465         if (LOGGER.isDebugEnabled()) {
466             super.debugDefault();
467             LOGGER.debug("Link Type          = {}", linktype);
468             LOGGER.debug("Label              = {}", label);
469             LOGGER.debug("Title              = {}", title);
470             LOGGER.debug("HREF               = {}", href);
471             LOGGER.debug("Role               = {}", role);
472             LOGGER.debug("From               = {}", from);
473             LOGGER.debug("To                 = {}", to);
474             LOGGER.debug("");
475         }
476     }
477 }