001    package ezvcard.io.html;
002    
003    import java.io.File;
004    import java.io.FileWriter;
005    import java.io.IOException;
006    import java.io.OutputStream;
007    import java.io.OutputStreamWriter;
008    import java.io.StringWriter;
009    import java.io.Writer;
010    import java.util.ArrayList;
011    import java.util.HashMap;
012    import java.util.List;
013    import java.util.Map;
014    
015    import ezvcard.Ezvcard;
016    import ezvcard.VCard;
017    import ezvcard.io.scribe.ScribeIndex;
018    import ezvcard.parameter.ImageType;
019    import ezvcard.property.Photo;
020    import ezvcard.util.DataUri;
021    import ezvcard.util.IOUtils;
022    import freemarker.template.Configuration;
023    import freemarker.template.DefaultObjectWrapper;
024    import freemarker.template.Template;
025    import freemarker.template.TemplateException;
026    
027    /*
028     Copyright (c) 2013, Michael Angstadt
029     All rights reserved.
030    
031     Redistribution and use in source and binary forms, with or without
032     modification, are permitted provided that the following conditions are met: 
033    
034     1. Redistributions of source code must retain the above copyright notice, this
035     list of conditions and the following disclaimer. 
036     2. Redistributions in binary form must reproduce the above copyright notice,
037     this list of conditions and the following disclaimer in the documentation
038     and/or other materials provided with the distribution. 
039    
040     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
041     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
042     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
044     ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
045     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
046     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
047     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
048     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
049     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
050    
051     The views and conclusions contained in the software and documentation are those
052     of the authors and should not be interpreted as representing official policies, 
053     either expressed or implied, of the FreeBSD Project.
054     */
055    
056    /**
057     * <p>
058     * Writes {@link VCard} objects to a templated HTML page (hCard format).
059     * </p>
060     * <p>
061     * <b>Example:</b>
062     * 
063     * <pre class="brush:java">
064     * VCard vcard1 = ...
065     * VCard vcard2 = ...
066     * 
067     * HCardPage page = new HCardPage();
068     * page.add(vcard1);
069     * page.add(vcard2);
070     * 
071     * File file = new File("hcard.html");
072     * page.write(file);
073     * </pre>
074     * 
075     * </p>
076     * @author Michael Angstadt
077     * @see <a
078     * href="http://microformats.org/wiki/hcard">http://microformats.org/wiki/hcard</a>
079     */
080    public class HCardPage {
081            private static final Template template;
082            static {
083                    Configuration cfg = new Configuration();
084                    cfg.setClassForTemplateLoading(HCardPage.class, "");
085                    cfg.setObjectWrapper(new DefaultObjectWrapper());
086                    cfg.setWhitespaceStripping(true);
087                    try {
088                            template = cfg.getTemplate("hcard-template.html");
089                    } catch (IOException e) {
090                            //should never be thrown because it's always on the classpath
091                            throw new RuntimeException(e);
092                    }
093            }
094    
095            private final List<VCard> vcards = new ArrayList<VCard>();
096    
097            /**
098             * Adds a vCard to the HTML page.
099             * @param vcard the vCard to add
100             */
101            public void add(VCard vcard) {
102                    vcards.add(vcard);
103            }
104    
105            /**
106             * Writes the HTML document to a string.
107             * @return the HTML document
108             */
109            public String write() {
110                    StringWriter sw = new StringWriter();
111                    try {
112                            write(sw);
113                    } catch (IOException e) {
114                            //never thrown because we're writing to a string
115                    }
116                    return sw.toString();
117            }
118    
119            /**
120             * Writes the HTML document to an output stream.
121             * @param out the output stream
122             * @throws IOException if there's a problem writing to the output stream
123             */
124            public void write(OutputStream out) throws IOException {
125                    write(new OutputStreamWriter(out));
126            }
127    
128            /**
129             * Writes the HTML document to a file.
130             * @param file the file
131             * @throws IOException if there's a problem writing to the file
132             */
133            public void write(File file) throws IOException {
134                    FileWriter writer = null;
135                    try {
136                            writer = new FileWriter(file);
137                            write(writer);
138                    } finally {
139                            IOUtils.closeQuietly(writer);
140                    }
141            }
142    
143            /**
144             * Writes the HTML document to a writer.
145             * @param writer the writer
146             * @throws IOException if there's a problem writing to the writer
147             */
148            public void write(Writer writer) throws IOException {
149                    Map<String, Object> map = new HashMap<String, Object>();
150                    map.put("vcards", vcards);
151                    map.put("dataUri", new DataUriGenerator());
152                    map.put("translucentBg", readImage("translucent-bg.png", ImageType.PNG));
153                    map.put("noProfile", readImage("no-profile.png", ImageType.PNG));
154                    map.put("ezVCardVersion", Ezvcard.VERSION);
155                    map.put("ezVCardUrl", Ezvcard.URL);
156                    map.put("scribeIndex", new ScribeIndex());
157                    try {
158                            template.process(map, writer);
159                    } catch (TemplateException e) {
160                            //this should never be thrown because we're always using the same template (it is hard-coded and cannot be changed by the user)
161                            throw new RuntimeException(e);
162                    }
163                    writer.flush();
164            }
165    
166            /**
167             * Reads an image from the classpath.
168             * @param name the file name, relative to this class
169             * @param mediaType the media type of the image
170             * @return the image
171             * @throws IOException
172             */
173            private Photo readImage(String name, ImageType mediaType) throws IOException {
174                    return new Photo(getClass().getResourceAsStream(name), mediaType);
175            }
176    
177            /**
178             * Generates data URIs for the freemarker template.
179             */
180            public static class DataUriGenerator {
181                    public String generate(String contentType, byte[] data) {
182                            return new DataUri(contentType, data).toString();
183                    }
184            }
185    }