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 }