001package org.hl7.fhir.r5.terminologies.utilities; 002 003import java.util.List; 004 005import org.hl7.fhir.exceptions.FHIRException; 006import org.hl7.fhir.exceptions.TerminologyServiceException; 007import org.hl7.fhir.r5.context.IWorkerContext; 008import org.hl7.fhir.r5.model.OperationOutcome.IssueType; 009import org.hl7.fhir.r5.terminologies.utilities.TerminologyOperationContext.TerminologyServiceProtectionException; 010import org.hl7.fhir.utilities.Utilities; 011import org.hl7.fhir.utilities.i18n.I18nConstants; 012import org.hl7.fhir.utilities.validation.ValidationOptions; 013 014import java.util.ArrayList; 015 016public class TerminologyOperationContext { 017 018 public static class TerminologyServiceProtectionException extends FHIRException { 019 020 private TerminologyServiceErrorClass error; 021 private IssueType type; 022 023 public TerminologyServiceProtectionException(String message, TerminologyServiceErrorClass error, IssueType type) { 024 super(message); 025 this.error = error; 026 this.type = type; 027 } 028 029 public TerminologyServiceErrorClass getError() { 030 return error; 031 } 032 033 public IssueType getType() { 034 return type; 035 } 036 037 } 038 039 public static boolean debugging = java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments().toString().indexOf("-agentlib:jdwp") > 0; 040 private static final int EXPANSION_DEAD_TIME_SECS = 60; 041 private long deadTime; 042 private int nestCount = 0; 043 private long startTime; 044 private List<String> contexts = new ArrayList<>(); 045 private IWorkerContext worker; 046 private boolean original; 047 private ValidationOptions options; 048 private String name; 049 private List<String> notes = new ArrayList<>(); 050 051 public TerminologyOperationContext(IWorkerContext worker, ValidationOptions options, String name) { 052 super(); 053 this.worker = worker; 054 this.original = true; 055 this.options = options; 056 this.name = name; 057 this.startTime = System.currentTimeMillis(); 058 059 if (EXPANSION_DEAD_TIME_SECS == 0 || debugging) { 060 deadTime = 0; 061 } else { 062 deadTime = System.currentTimeMillis() + (EXPANSION_DEAD_TIME_SECS * 1000); 063 } 064 } 065 066 private TerminologyOperationContext(ValidationOptions options, String name) { 067 super(); 068 this.options = options; 069 this.name = name; 070 this.startTime = System.currentTimeMillis(); 071 } 072 073 public TerminologyOperationContext copy() { 074 TerminologyOperationContext ret = new TerminologyOperationContext(this.options, name); 075 ret.worker = worker; 076 ret.contexts.addAll(contexts); 077 ret.deadTime = deadTime; 078 ret.notes = notes; 079 ret.startTime = startTime; 080 ret.nestCount = nestCount + 1; 081 return ret; 082 } 083 084 public void deadCheck(String note) { 085 note(note); 086 if (deadTime != 0 && System.currentTimeMillis() > deadTime) { 087 System.out.println(); 088 System.out.println("Operation took too long - longer than "+(deadTime - startTime)+"ms"); 089 for (String s : notes) { 090 System.out.println(s); 091 } 092 throw new TerminologyServiceProtectionException(worker.formatMessage(I18nConstants.VALUESET_TOO_COSTLY_TIME, contexts.get(0), EXPANSION_DEAD_TIME_SECS, name+" (local)"), TerminologyServiceErrorClass.TOO_COSTLY, IssueType.TOOCOSTLY); 093 } 094 } 095 096 public void seeContext(String context) { 097 if (contexts.contains(context)) { 098 throw new TerminologyServiceProtectionException(worker.formatMessage(I18nConstants.VALUESET_CIRCULAR_REFERENCE, context, contexts.toString()), TerminologyServiceErrorClass.PROCESSING, IssueType.PROCESSING); 099 } 100 contexts.add(context); 101 } 102 103 public boolean isOriginal() { 104 return original; 105 } 106 107 public ValidationOptions getOptions() { 108 return options; 109 } 110 111 public void note(String s) { 112 s = Utilities.padLeft("", ' ', nestCount)+" "+(System.currentTimeMillis() - startTime)+" "+s; 113 notes.add(s); 114 } 115}