<commit_before>package org.oasis.datacore.rest.server.parsing.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.oasis.datacore.core.meta.model.DCField;
import org.oasis.datacore.core.meta.model.DCModel;


/**
 * Keeps the state of parsing (path in model instance) in order to be able
 * to display error messages that pinpoint to error location.
 * 
 * @author mdutoo
 *
 */
public class DCResourceParsingContext {
   
   protected Stack<DCResourceValue> resourceValueStack = new Stack<DCResourceValue>(); // TODO or of String only ??

   // TODO or same list, with error level in Log and boolean hasError ?!?
   private List<ResourceParsingLog> errors = null;
   private List<ResourceParsingLog> warnings = null;
   
   /**
    * For multi resource parsing, requires enter(DCModel, uri) first
    */
   public DCResourceParsingContext() {
      
   }
   
   /**
    * For single resource parsing
    * @param model
    * @param uri
    */
   public DCResourceParsingContext(DCModel model, String uri) {
      this.enter(model, uri);
   }
   
   public DCResourceValue peekResourceValue() {
      return this.resourceValueStack.peek();
   }
   
   public void enter(DCModel model, String uri) {
      this.resourceValueStack.add(new DCResourceValue(model.getName(), null, uri));
   }
   
   public void enter(DCField field, Object value) {
      String fullValuedPath;
      if (this.resourceValueStack.isEmpty()) {
         fullValuedPath = "Missing root model name";
      } else {
         DCResourceValue previousResourceValue = this.resourceValueStack.peek();
         fullValuedPath = previousResourceValue.getFullValuedPath() + "/"
               + ((value == null) ? field.getName() : field.getName() + "[='" + value + "']");
         // TODO test if enough xpath-like in addition to being a value path (which is particularly ugly in list case)
      }
      this.resourceValueStack.add(new DCResourceValue(fullValuedPath, field,  value));
   }
   public void exit() {
      this.resourceValueStack.pop();
   }
   
   public void addError(String message) {
      this.addError(message, null);
   }

   public void addError(String message, Exception ex) {
      String fieldFullPath = this.resourceValueStack.peek().getFullValuedPath();
      this.getOrCreateErrors().add(new ResourceParsingLog(fieldFullPath, message, ex));
   }

   public boolean hasErrors() {
      return this.errors != null;
   }
   
   public List<ResourceParsingLog> getErrors() {
      return this.errors;
   }
   
   public void addWarning(String message) {
      this.addWarning(message, null);<commit_msg>resource : better logging of parsing errors<commit_after>package org.oasis.datacore.rest.server.parsing.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.oasis.datacore.core.meta.model.DCField;
import org.oasis.datacore.core.meta.model.DCModel;


/**
 * Keeps the state of parsing (path in model instance) in order to be able
 * to display error messages that pinpoint to error location.
 * 
 * TODO LATER OPT less context for performance unless enabled in request context ?
 * 
 * @author mdutoo
 *
 */
public class DCResourceParsingContext {
   
   protected Stack<DCResourceValue> resourceValueStack = new Stack<DCResourceValue>(); // TODO or of String only ??

   // TODO or same list, with error level in Log and boolean hasError ?!?
   private List<ResourceParsingLog> errors = null;
   private List<ResourceParsingLog> warnings = null;
   
   /**
    * For multi resource parsing, requires enter(DCModel, uri) first
    */
   public DCResourceParsingContext() {
      
   }
   
   /**
    * For single resource parsing
    * @param model
    * @param uri
    */
   public DCResourceParsingContext(DCModel model, String uri) {
      this.enter(model, uri);
   }
   
   public DCResourceValue peekResourceValue() {
      return this.resourceValueStack.peek();
   }
   
   public void enter(DCModel model, String uri) {
      this.resourceValueStack.add(new DCResourceValue(model.getName(), null, uri));
   }
   
   public void enter(DCField field, Object value) {
      String fullValuedPath;
      if (this.resourceValueStack.isEmpty()) {
         fullValuedPath = "Missing root model name";
      } else {
         // TODO LATER OPT less context for performance unless enabled in request context ?
         DCResourceValue previousResourceValue = this.resourceValueStack.peek();
         fullValuedPath = previousResourceValue.getFullValuedPath() + "/" + field.getName();
         if (!(value instanceof List<?> || value instanceof Map<?,?>)) {
            fullValuedPath += "[='" + ((value == null) ? "null" : value) + "']";
         }
      }
      this.resourceValueStack.add(new DCResourceValue(fullValuedPath, field,  value));
   }
   public void exit() {
      this.resourceValueStack.pop();
   }
   
   public void addError(String message) {
      this.addError(message, null);
   }

   public void addError(String message, Exception ex) {
      String fieldFullPath = this.resourceValueStack.peek().getFullValuedPath();
      this.getOrCreateErrors().add(new ResourceParsingLog(fieldFullPath, message, ex));
   }

   public boolean hasErrors() {
      return this.errors != null;
   }
   
   public List<ResourceParsingLog> getErrors() {
      return this.errors;
   }
   
   public void addWarning(String message) {
      this.addWarning(message, null);
{'fraction_non_alphanumeric': 0.10546105640107431, 'fraction_numerical': 0.0, 'mean_word_length': 3.2158490566037736, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5837688', 'n_tokens_mistral': 1607, 'n_tokens_neox': 1619, 'n_words': 421}