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