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}