001package ezvcard.io.chain;
002
003import java.io.IOException;
004import java.io.OutputStream;
005import java.io.Writer;
006import java.nio.file.Path;
007import java.util.Collection;
008import java.util.HashMap;
009import java.util.Map;
010
011import javax.xml.transform.Transformer;
012import javax.xml.transform.TransformerException;
013
014import org.w3c.dom.Document;
015
016import ezvcard.Ezvcard;
017import ezvcard.VCard;
018import ezvcard.VCardDataType;
019import ezvcard.io.scribe.VCardPropertyScribe;
020import ezvcard.io.xml.XCardDocument;
021import ezvcard.io.xml.XCardDocument.XCardDocumentStreamWriter;
022import ezvcard.io.xml.XCardOutputProperties;
023import ezvcard.property.VCardProperty;
024
025/*
026 Copyright (c) 2012-2023, Michael Angstadt
027 All rights reserved.
028
029 Redistribution and use in source and binary forms, with or without
030 modification, are permitted provided that the following conditions are met: 
031
032 1. Redistributions of source code must retain the above copyright notice, this
033 list of conditions and the following disclaimer. 
034 2. Redistributions in binary form must reproduce the above copyright notice,
035 this list of conditions and the following disclaimer in the documentation
036 and/or other materials provided with the distribution. 
037
038 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
039 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
040 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
041 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
042 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
043 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
044 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
045 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
046 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
047 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
048 */
049
050/**
051 * Chainer class for writing xCards (XML-encoded vCards).
052 * @see Ezvcard#writeXml(Collection)
053 * @see Ezvcard#writeXml(VCard...)
054 * @author Michael Angstadt
055 */
056public class ChainingXmlWriter extends ChainingWriter<ChainingXmlWriter> {
057        private final XCardOutputProperties outputProperties = new XCardOutputProperties();
058        private final Map<String, VCardDataType> parameterDataTypes = new HashMap<>(0);
059
060        /**
061         * @param vcards the vCards to write
062         */
063        public ChainingXmlWriter(Collection<VCard> vcards) {
064                super(vcards);
065        }
066
067        /**
068         * Sets the number of indent spaces to use for pretty-printing. If not set,
069         * then the XML will not be pretty-printed.
070         * @param indent the number of spaces in the indent string or null not to
071         * pretty-print (disabled by default)
072         * @return this
073         */
074        public ChainingXmlWriter indent(Integer indent) {
075                outputProperties.setIndent(indent);
076                return this;
077        }
078
079        /**
080         * Sets the XML version to use. Note that many JDKs only support 1.0
081         * natively. For XML 1.1 support, add a JAXP library like <a href=
082         * "http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22xalan%22%20AND%20a%3A%22xalan%22"
083         * >xalan</a> to your project.
084         * @param xmlVersion the XML version (defaults to "1.0")
085         * @return this
086         */
087        public ChainingXmlWriter xmlVersion(String xmlVersion) {
088                outputProperties.setXmlVersion(xmlVersion);
089                return this;
090        }
091
092        /**
093         * Assigns an output property to the JAXP transformer (see
094         * {@link Transformer#setOutputProperty}).
095         * @param name the property name
096         * @param value the property value
097         * @return this
098         */
099        public ChainingXmlWriter outputProperty(String name, String value) {
100                outputProperties.put(name, value);
101                return this;
102        }
103
104        /**
105         * Assigns all of the given output properties to the JAXP transformer (see
106         * {@link Transformer#setOutputProperty}).
107         * @param outputProperties the properties
108         * @return this
109         */
110        public ChainingXmlWriter outputProperties(Map<String, String> outputProperties) {
111                this.outputProperties.putAll(outputProperties);
112                return this;
113        }
114
115        @Override
116        public ChainingXmlWriter prodId(boolean include) {
117                return super.prodId(include);
118        }
119
120        @Override
121        public ChainingXmlWriter versionStrict(boolean versionStrict) {
122                return super.versionStrict(versionStrict);
123        }
124
125        @Override
126        public ChainingXmlWriter register(VCardPropertyScribe<? extends VCardProperty> scribe) {
127                return super.register(scribe);
128        }
129
130        /**
131         * Registers the data type of a non-standard parameter. Non-standard
132         * parameters use the "unknown" data type by default.
133         * @param parameterName the parameter name (e.g. "x-foo")
134         * @param dataType the data type
135         * @return this
136         */
137        public ChainingXmlWriter register(String parameterName, VCardDataType dataType) {
138                parameterDataTypes.put(parameterName, dataType);
139                return this;
140        }
141
142        /**
143         * Writes the xCards to a string.
144         * @return the XML document
145         */
146        public String go() {
147                return createXCardDocument().write(outputProperties);
148        }
149
150        /**
151         * Writes the xCards to an output stream.
152         * @param out the output stream to write to
153         * @throws TransformerException if there's a problem writing to the output
154         * stream
155         */
156        public void go(OutputStream out) throws TransformerException {
157                createXCardDocument().write(out, outputProperties);
158        }
159
160        /**
161         * Writes the xCards to a file.
162         * @param file the file to write to
163         * @throws IOException if the file can't be opened
164         * @throws TransformerException if there's a problem writing to the file
165         */
166        public void go(Path file) throws IOException, TransformerException {
167                createXCardDocument().write(file, outputProperties);
168        }
169
170        /**
171         * Writes the xCards to a writer.
172         * @param writer the writer to write to
173         * @throws TransformerException if there's a problem writing to the writer
174         */
175        public void go(Writer writer) throws TransformerException {
176                createXCardDocument().write(writer, outputProperties);
177        }
178
179        /**
180         * Generates an XML document object model (DOM) containing the xCards.
181         * @return the DOM
182         */
183        public Document dom() {
184                return createXCardDocument().getDocument();
185        }
186
187        private XCardDocument createXCardDocument() {
188                XCardDocument document = new XCardDocument();
189
190                XCardDocumentStreamWriter writer = document.writer();
191                writer.setAddProdId(prodId);
192                writer.setVersionStrict(versionStrict);
193                for (Map.Entry<String, VCardDataType> entry : parameterDataTypes.entrySet()) {
194                        String parameterName = entry.getKey();
195                        VCardDataType dataType = entry.getValue();
196                        writer.registerParameterDataType(parameterName, dataType);
197                }
198                if (index != null) {
199                        writer.setScribeIndex(index);
200                }
201
202                for (VCard vcard : vcards) {
203                        writer.write(vcard);
204                }
205
206                return document;
207        }
208}