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