001/* 002Copyright (c) 2011+, HL7, Inc 003All rights reserved. 004 005Redistribution and use in source and binary forms, with or without modification, 006are permitted provided that the following conditions are met: 007 008 * Redistributions of source code must retain the above copyright notice, this 009 list of conditions and the following disclaimer. 010 * Redistributions in binary form must reproduce the above copyright notice, 011 this list of conditions and the following disclaimer in the documentation 012 and/or other materials provided with the distribution. 013 * Neither the name of HL7 nor the names of its contributors may be used to 014 endorse or promote products derived from this software without specific 015 prior written permission. 016 017THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 018ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 019WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 020IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 021INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 022NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 023PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 024WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 025ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 026POSSIBILITY OF SUCH DAMAGE. 027 028*/ 029package org.hl7.fhir.utilities; 030 031 032import java.io.IOException; 033import java.io.InputStream; 034import java.io.InputStreamReader; 035import java.io.OutputStream; 036import java.io.OutputStreamWriter; 037import java.io.UnsupportedEncodingException; 038 039import org.hl7.fhir.exceptions.FHIRException; 040 041/** 042 * A file processor that reads a templated source file with markers ([%columnname%]), reads data 043 * from a CSV file and inserts data from that CSV file into those markers. Supports loops to 044 * interate through the CSV file. 045 * @author Ewout 046 * 047 */ 048public class CSVProcessor { 049 050 public class DataReader extends CSVReader { 051 052 public DataReader(InputStream data) throws UnsupportedEncodingException { 053 super(data); 054 } 055 056 public void process() throws IOException, FHIRException { 057 String[] titles = parseLine(); 058 while (ready()) 059 { 060 String[] values = parseLine(); 061 processLine(titles, values); 062 } 063 close(); 064 } 065 066 private void processLine(String[] titles, String[] values) throws FHIRException { 067 count++; 068 String src = loop; 069 while (src.contains("[%")) { 070 int i1 = src.indexOf("[%"); 071 int i2 = src.indexOf("%]"); 072 String s1 = src.substring(0, i1); 073 String s2 = src.substring(i1 + 2, i2).trim(); 074 String s3 = src.substring(i2+2); 075 if ("count".equals(s2)) 076 src = s1+Integer.toString(count)+s3; 077 else { 078 boolean b = false; 079 for (String t : titles) { 080 if (t.equals(s2)) { 081 src = s1+getColumn(titles, values, s2)+s3; 082 b = true; 083 } 084 } 085 if (!b) 086 throw new FHIRException("unknown column: '"+s2+"'"); 087 } 088 } 089 dest.append(src); 090 } 091 } 092 093 private InputStream source; 094 private DataReader data; 095 private OutputStreamWriter out; 096 097 private String start; 098 private String loop; 099 private int count = 0; 100 private String stop; 101 private StringBuilder dest; 102 103 public void setSource(InputStream source) { 104 this.source = source; 105 } 106 107 public void setData(InputStream data) { 108 try { 109 this.data = new DataReader(data); 110 } catch (UnsupportedEncodingException e) { 111 // DataReader is fixed to "UTF-8", so this exception cannot really occur 112 } 113 } 114 115 public void setOutput(OutputStream out) throws UnsupportedEncodingException { 116 this.out = new OutputStreamWriter(out, "UTF-8"); 117 } 118 119 public void process() throws IOException, FHIRException { 120 buildTemplate(readSource()); 121 dest = new StringBuilder(); 122 dest.append(start); 123 data.process(); 124 dest.append(stop); 125 out.write(dest.toString()); 126 out.close(); 127 } 128 129 private void buildTemplate(String template) throws FHIRException { 130 int i = template.indexOf("[%loop"); 131 if (i < 0) 132 throw new FHIRException("Unable to process template - didn't find [%loop"); 133 start = template.substring(0, i); 134 template = template.substring(i+6); 135 i = template.indexOf("%]"); 136 if (i < 0) 137 throw new FHIRException("Unable to process template - didn't find %] matching [%loop"); 138 String tmp = template.substring(0, i); 139 if (tmp != null && !tmp.equals("")) { 140 if (!tmp.startsWith(" count=")) 141 throw new FHIRException("Unable to process template - unrecognised content on [%loop"); 142 count = Integer.parseInt(tmp.substring(7)); 143 } 144 145 template = template.substring(i+2); 146 i = template.indexOf("[%endloop%]"); 147 if (i < 0) 148 throw new FHIRException("Unable to process template - didn't find [%endloop%]"); 149 loop = template.substring(0, i); 150 stop = template.substring(i+11); 151 } 152 153 private String readSource() throws IOException { 154 StringBuilder s = new StringBuilder(); 155 InputStreamReader r = new InputStreamReader(source,"UTF-8"); 156 while (r.ready()) { 157 s.append((char) r.read()); 158 } 159 r.close(); 160 return s.toString(); 161 } 162 163}