001
002/*
003 * Copyright (C) 2010 Archie L. Cobbs. All rights reserved.
004 *
005 * $Id$
006 */
007
008package org.dellroad.jibxbindings.vcard;
009
010import java.io.IOException;
011
012import javax.xml.parsers.DocumentBuilderFactory;
013import javax.xml.parsers.ParserConfigurationException;
014
015import org.jibx.extras.DomElementMapper;
016import org.jibx.runtime.IMarshallingContext;
017import org.jibx.runtime.IUnmarshallingContext;
018import org.jibx.runtime.JiBXException;
019import org.w3c.dom.Document;
020import org.w3c.dom.Element;
021
022import ezvcard.VCard;
023import ezvcard.io.xml.XCardDocument;
024
025/**
026 * JiBX marshaller/unmarshaller for a single {@link VCard}.
027 *
028 * <p>
029 * Example of use:
030 *  <pre>
031 *  &lt;mapping ... &gt;
032 *      &lt;namespace uri="urn:ietf:params:xml:ns:vcard-4.0" prefix="vc"/&gt;
033 *      ...
034 *      &lt;structure name="ContactInfo"&gt;
035 *          &lt;structure name="vcard" field="contactInfo" ns="urn:ietf:params:xml:ns:vcard-4.0"
036 *            marshaller="org.dellroad.jibxbindings.vcard.VCardMarshaller"
037 *            unmarshaller="org.dellroad.jibxbindings.vcard.VCardMarshaller"/&gt;
038 *      &lt;/structure&gt;
039 *      ...
040 *  &lt;/mapping&gt;
041 *  </pre>
042 * </p>
043 *
044 * @see <a href="https://ez-vcard.googlecode.com">The EZ-vCard Project</a>
045 * @see <a href="https://tools.ietf.org/html/rfc6351">RFC 6351</a>
046 */
047public class VCardMarshaller extends DomElementMapper {
048
049    public static final String VCARD_NAMESPACE_URI = "urn:ietf:params:xml:ns:vcard-4.0";
050    public static final String VCARDS_ELEMENT_NAME = "vcards";
051    public static final String VCARD_ELEMENT_NAME = "vcard";
052
053    public VCardMarshaller() throws JiBXException {
054        this(VCARD_NAMESPACE_URI, 0, VCARD_ELEMENT_NAME);
055    }
056
057    public VCardMarshaller(String uri, int index, String name) throws JiBXException {
058        super(uri, index, name);
059    }
060
061    @Override
062    public void marshal(Object obj, IMarshallingContext ctx) throws JiBXException {
063
064        // Handle null
065        if (obj == null)
066            return;
067
068        // Convert to XML
069        final XCardDocument xcard = new XCardDocument();
070        xcard.add((VCard)obj);
071        super.marshal(xcard.getDocument().getDocumentElement().getFirstChild(), ctx);
072    }
073
074    @Override
075    public VCard unmarshal(Object obj, IUnmarshallingContext ctx) throws JiBXException {
076
077        // Get XML element
078        final Element element = (Element)super.unmarshal(obj, ctx);
079
080        // Handle null
081        if (element == null)
082            return null;
083
084        // Create temporary XML <vcards> document
085        final Document doc;
086        try {
087            doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
088        } catch (ParserConfigurationException e) {
089            throw new RuntimeException("unexpected exception", e);
090        }
091        final Element vcards = doc.createElementNS(VCARD_NAMESPACE_URI, VCARDS_ELEMENT_NAME);
092        doc.appendChild(vcards);
093
094        // Append <vcard> node
095        vcards.appendChild(doc.importNode(element, true));
096
097        // Read it
098        try {
099            return new XCardDocument(doc).reader().readNext();
100        } catch (IOException e) {
101            throw new RuntimeException("unexpected exception", e);
102        }
103    }
104
105    /**
106     * Clone a {@link VCard} by converting it to XML and back.
107     * This method works around the fact that {@link VCard} does not implement {@link Cloneable}.
108     *
109     * @throws IllegalArgumentException if {@code vcard} is null
110     */
111    public static VCard clone(VCard vcard) {
112
113        // Sanity check
114        if (vcard == null)
115            throw new IllegalArgumentException("null vcard");
116
117        // Convert to XML
118        final XCardDocument xcard = new XCardDocument();
119        xcard.add(vcard);
120        final Document doc = xcard.getDocument();
121
122        // Convert from XML
123        try {
124            return new XCardDocument(doc).reader().readNext();
125        } catch (IOException e) {
126            throw new RuntimeException("unexpected exception", e);
127        }
128    }
129}
130