@Grab('com.github.rahulsom:fhir-protobuf-translate:0.1.0') @Grab('ca.uhn.hapi.fhir:hapi-fhir-structures-dstu3:3.1.0') @Grab('org.gperfutils:gbench:0.4.3-groovy-2.4') import ca.uhn.fhir.context.FhirContext import com.github.rahulsom.fhirprotobuf.Converter import com.google.protobuf.util.JsonFormat import org.fhir.stu3.Bundle import org.hl7.fhir.instance.model.api.IBaseResource import java.text.DecimalFormat import java.util.zip.GZIPOutputStream def rootDir = new File('data') if (!rootDir.exists()) { rootDir.mkdirs() } void createProtoFiles(String name) { new File("data/${name}.proto.json").text = Converter.fromFhirJson(new File("data/${name}.json").text) def builder2k = Bundle.newBuilder() JsonFormat.parser().ignoringUnknownFields().merge(new File("data/${name}.proto.json").text, builder2k) def stream2k = new File("data/${name}.buf").newOutputStream() builder2k.build().writeTo(stream2k) stream2k.flush() stream2k.close() } new JsonFactory(rootDir: rootDir). with { createBundle('bundle-2k', [doc, patient]) createProtoFiles('bundle-2k') createBundle('bundle-20k', ([doc, patient] + visits(6) + observations(21))) createProtoFiles('bundle-20k') createProtoFiles('bundle-170k') } def fhirContext = FhirContext.forDstu3() def files = rootDir. listFiles(). findAll { it.name.endsWith('.json') && !it.name.contains('.proto') }. sort { it.size() } def zipLength(byte[] s) { def targetStream = new ByteArrayOutputStream() def zipStream = new GZIPOutputStream(targetStream) zipStream.write(s) zipStream.close() def zipped = targetStream.toByteArray() targetStream.close() return zipped.length } def r = benchmark { def types = ['Input', 'P Json', 'P XML', 'U Json', 'U XML', 'Proto'] def dataFormat = "%-20s | %6s(%6s) | %6s(%6s) | %6s(%6s) | %6s(%6s) | %6s(%6s) | %6s(%6s)" println String.sprintf(dataFormat, ['Filename'] + types.collect { [it, 'Zipped'] }.flatten()) def sepFormat = "%-20s + %14s + %14s + %14s + %14s + %14s + %14s" println String.sprintf(sepFormat, ['-' * 20] + types.collect { '-' * 14 }) files.each { file -> def name = file.name.split(/\./)[0].split('-')[1] IBaseResource resource = fhirContext.newJsonParser().parseResource(file.newReader()) def protoFile = new File(rootDir, "bundle-${name}.buf") def protobufBundle = Bundle.parseFrom(protoFile.newInputStream()) String json = '' String xml = '' String prettyJson = '' String prettyXml = '' byte[] protoByteArray = [] String protoString = '' "Print Pretty JSON - $name" { def parser = fhirContext.newJsonParser() parser.prettyPrint = true prettyJson = parser.encodeResourceToString(resource) } "Print Ugly JSON - $name" { def parser = fhirContext.newJsonParser() parser.prettyPrint = false json = parser.encodeResourceToString(resource) } "Print Pretty XML - $name" { def parser = fhirContext.newXmlParser() parser.prettyPrint = true prettyXml = parser.encodeResourceToString(resource) } "Print Ugly XML - $name" { def parser = fhirContext.newXmlParser() parser.prettyPrint = false xml = parser.encodeResourceToString(resource) } "Serialize Protobuf - $name" { protoByteArray = protobufBundle.toByteArray() } "Humanize Protobuf - $name" { protoString = protobufBundle.toString() } "Parse Pretty JSON - $name" { fhirContext.newJsonParser().parseResource(prettyJson) } "Parse Ugly JSON - $name" { fhirContext.newJsonParser().parseResource(json) } "Parse Pretty XML - $name" { fhirContext.newXmlParser().parseResource(prettyXml) } "Parse Ugly XML - $name" { fhirContext.newXmlParser().parseResource(xml) } "Parse Protobuf - $name" { Bundle.parseFrom(protoByteArray) } println String.sprintf(dataFormat, file.name, format(file.size()), format(zipLength(file.bytes)), format(prettyJson.length()), format(zipLength(prettyJson.bytes)), format(prettyXml.length()), format(zipLength(prettyXml.bytes)), format(json.length()), format(zipLength(json.bytes)), format(xml.length()), format(zipLength(xml.bytes)), format(protoFile.size()), format(zipLength(protoFile.bytes))) } } private static String format(long number) { String[] suffix = ["", "k", "M", "G", "T", "P", "E", "Z", "Y"] // int MAX_LENGTH = 4; String r = new DecimalFormat("##0E0").format(number); def exponent = r.split('E')[1].toInteger() def eng = suffix[exponent / 3 as int] r.split('E')[0] + eng } println '' println '' println '' r.prettyPrint()