001package org.hl7.fhir.convertors.analytics; 002 003import java.io.IOException; 004import java.util.ArrayList; 005import java.util.Collections; 006import java.util.HashMap; 007import java.util.HashSet; 008import java.util.List; 009import java.util.Map; 010import java.util.Set; 011 012import javax.xml.parsers.ParserConfigurationException; 013 014import org.hl7.fhir.convertors.analytics.PackageVisitor.IPackageVisitorProcessor; 015import org.hl7.fhir.exceptions.FHIRException; 016import org.hl7.fhir.exceptions.FHIRFormatError; 017import org.hl7.fhir.utilities.Utilities; 018import org.hl7.fhir.utilities.VersionUtilities; 019import org.hl7.fhir.utilities.npm.NpmPackage; 020import org.xml.sax.SAXException; 021 022public class SearchParameterAnalysis implements IPackageVisitorProcessor { 023 024 public static class SearchParameterTypeUsage { 025 private Set<String> coreUsage = new HashSet<>(); 026 private Set<String> igUsage = new HashSet<>(); 027 public String summary() { 028 return ""+coreUsage.size()+" / "+igUsage.size(); 029 } 030 } 031 032 public static class SearchParameterType { 033 private Map<String, SearchParameterTypeUsage> usages = new HashMap<>(); 034 public void seeUsage(boolean core, String usage, String url) { 035 if (!usages.containsKey(usage)) { 036 usages.put(usage, new SearchParameterTypeUsage()); 037 } 038 SearchParameterTypeUsage tu = usages.get(usage); 039 if (core) { 040 tu.coreUsage.add(url); 041 } else { 042 tu.igUsage.add(url); 043 } 044 045 } 046 } 047 048 public static class SearchParameterVersionAnalysis { 049 private Map<String, SearchParameterType> types = new HashMap<>(); 050 private String version; 051 052 public void seeUsage(boolean core, String type, String usage, String url) { 053// System.out.println("v"+version+" "+Utilities.padRight(url, ' ', 60)+" "+type+"/"+usage); 054 if (type == null) { 055 type = "n/a"; 056 } 057 if (usage == null) { 058 usage = "n/a"; 059 } 060 if (!types.containsKey(type)) { 061 types.put(type, new SearchParameterType()); 062 } 063 SearchParameterType tu = types.get(type); 064 tu.seeUsage(core, usage, url); 065 } 066 067 public void printSummary() { 068 Set<String> usages = new HashSet<>(); 069 for (SearchParameterType tu : types.values()) { 070 usages.addAll(tu.usages.keySet()); 071 } 072 List<String> ul = new ArrayList<String>(); 073 ul.addAll(usages); 074 Collections.sort(ul); 075 System.out.print(Utilities.padRight("", ' ', 10)); 076 for (String u : ul) { 077 System.out.print(Utilities.padRight(u, ' ', 10)); 078 } 079 System.out.println(); 080 for (String t : types.keySet()) { 081 System.out.print(Utilities.padRight(t, ' ', 10)); 082 SearchParameterType tu = types.get(t); 083 for (String u : ul) { 084 SearchParameterTypeUsage uu = tu.usages.get(u); 085 if (uu == null) { 086 System.out.print(Utilities.padRight("0 / 0", ' ', 10)); 087 } else { 088 System.out.print(Utilities.padRight(uu.summary(), ' ', 10)); 089 } 090 } 091 System.out.println(); 092 } 093 094 } 095 096 } 097 098 private Map<String, SearchParameterVersionAnalysis> versions = new HashMap<String, SearchParameterAnalysis.SearchParameterVersionAnalysis>(); 099 100 @Override 101 public void processResource(String pid, NpmPackage npm, String version, String type, String id, byte[] content) throws FHIRException { 102// System.out.println("v"+version+" "+type+" from "+pid); 103 boolean core = pid.startsWith("hl7.fhir.r") && (pid.contains(".core") || pid.contains(".examples")); 104 version = VersionUtilities.getMajMin(version); 105 if (!versions.containsKey(version)) { 106 versions.put(version, new SearchParameterVersionAnalysis()); 107 versions.get(version).version = version; 108 } 109 try { 110 if (VersionUtilities.isR5Plus(version)) { 111 processR5SP(core, versions.get(version), content); 112 } else if (VersionUtilities.isR4BVer(version)) { 113 processR4SP(core, versions.get(version), content); 114 } else if (VersionUtilities.isR4Ver(version)) { 115 processR4SP(core, versions.get(version), content); 116 } else if (VersionUtilities.isR3Ver(version)) { 117 processR3SP(core, versions.get(version), content); 118 } else if (VersionUtilities.isR2Ver(version)) { 119 processR2SP(core, versions.get(version), content); 120 } 121 } catch (IOException e) { 122 throw new FHIRException(e); 123 } 124 } 125 126 private void processR5SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException { 127 org.hl7.fhir.r5.model.Resource res = new org.hl7.fhir.r5.formats.JsonParser().parse(content); 128 if (res instanceof org.hl7.fhir.r5.model.Bundle) { 129 for (org.hl7.fhir.r5.model.Bundle.BundleEntryComponent bnd : ((org.hl7.fhir.r5.model.Bundle) res).getEntry()) { 130 if (bnd.getResource() != null && bnd.getResource() instanceof org.hl7.fhir.r5.model.SearchParameter) { 131 org.hl7.fhir.r5.model.SearchParameter sp = (org.hl7.fhir.r5.model.SearchParameter) bnd.getResource(); 132 analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getProcessingModeElement().primitiveValue(), sp.getUrl()); 133 } 134 } 135 } else { 136 org.hl7.fhir.r5.model.SearchParameter sp = (org.hl7.fhir.r5.model.SearchParameter) res; 137 analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getProcessingModeElement().primitiveValue(), sp.getUrl()); 138 } 139 } 140 141 private void processR4SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException { 142 org.hl7.fhir.r4.model.Resource res = new org.hl7.fhir.r4.formats.JsonParser().parse(content); 143 if (res instanceof org.hl7.fhir.r4.model.Bundle) { 144 for (org.hl7.fhir.r4.model.Bundle.BundleEntryComponent bnd : ((org.hl7.fhir.r4.model.Bundle) res).getEntry()) { 145 if (bnd.getResource() != null && bnd.getResource() instanceof org.hl7.fhir.r4.model.SearchParameter) { 146 org.hl7.fhir.r4.model.SearchParameter sp = (org.hl7.fhir.r4.model.SearchParameter) bnd.getResource(); 147 analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl()); 148 } 149 } 150 } else { 151 org.hl7.fhir.r4.model.SearchParameter sp = (org.hl7.fhir.r4.model.SearchParameter) res; 152 analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl()); 153 } 154 } 155 156 private void processR3SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException { 157 org.hl7.fhir.dstu3.model.Resource res = new org.hl7.fhir.dstu3.formats.JsonParser().parse(content); 158 if (res instanceof org.hl7.fhir.dstu3.model.Bundle) { 159 for (org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent bnd : ((org.hl7.fhir.dstu3.model.Bundle) res).getEntry()) { 160 if (bnd.getResource() != null && bnd.getResource() instanceof org.hl7.fhir.dstu3.model.SearchParameter) { 161 org.hl7.fhir.dstu3.model.SearchParameter sp = (org.hl7.fhir.dstu3.model.SearchParameter) bnd.getResource(); 162 analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl()); 163 } 164 } 165 } else { 166 org.hl7.fhir.dstu3.model.SearchParameter sp = (org.hl7.fhir.dstu3.model.SearchParameter) res; 167 analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl()); 168 } 169 } 170 171 private void processR2SP(boolean core, SearchParameterVersionAnalysis analysis, byte[] content) throws FHIRFormatError, IOException { 172 org.hl7.fhir.dstu2.model.Resource res = new org.hl7.fhir.dstu2.formats.JsonParser().parse(content); 173 if (res instanceof org.hl7.fhir.dstu2.model.Bundle) { 174 for (org.hl7.fhir.dstu2.model.Bundle.BundleEntryComponent bnd : ((org.hl7.fhir.dstu2.model.Bundle) res).getEntry()) { 175 if (bnd.getResource() != null && bnd.getResource() instanceof org.hl7.fhir.dstu2.model.SearchParameter) { 176 org.hl7.fhir.dstu2.model.SearchParameter sp = (org.hl7.fhir.dstu2.model.SearchParameter) bnd.getResource(); 177 analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl()); 178 } 179 } 180 } else { 181 org.hl7.fhir.dstu2.model.SearchParameter sp = (org.hl7.fhir.dstu2.model.SearchParameter) res; 182 analysis.seeUsage(core, sp.getTypeElement().primitiveValue(), sp.getXpathUsageElement().primitiveValue(), sp.getUrl()); 183 } 184 } 185 186 public static void main(String[] args) throws Exception { 187 new SearchParameterAnalysis().execute(); 188 } 189 190 private void execute() throws IOException, ParserConfigurationException, SAXException { 191 PackageVisitor pv = new PackageVisitor(); 192 pv.getResourceTypes().add("SearchParameter"); 193 pv.getResourceTypes().add("Bundle"); 194 pv.setOldVersions(false); 195 pv.setCorePackages(true); 196 pv.setProcessor(this); 197 pv.visitPackages(); 198 199 printSummary(); 200 } 201 202 private void printSummary() { 203 for (String v : versions.keySet()) { 204 System.out.println("-- v"+v+"---------------------"); 205 versions.get(v).printSummary(); 206 System.out.println(""); 207 } 208 209 } 210}