code: package it.unibz.inf.ontop.protege.mapping;
  
  import it.unibz.inf.ontop.shaded.com.google.common.collect.ImmutableList;
  import it.unibz.inf.ontop.shaded.com.google.common.collect.Maps;
  import it.unibz.inf.ontop.model.atom.DistinctVariableOnlyDataAtom;
  import it.unibz.inf.ontop.model.atom.RDFAtomPredicate;
  import it.unibz.inf.ontop.model.term.ImmutableTerm;
  import it.unibz.inf.ontop.model.term.Variable;
  import it.unibz.inf.ontop.spec.mapping.TargetAtom;
  import it.unibz.inf.ontop.spec.mapping.pp.SQLPPTriplesMap;
  import it.unibz.inf.ontop.spec.mapping.pp.impl.OntopNativeSQLPPTriplesMap;
  import it.unibz.inf.ontop.utils.ImmutableCollectors;
  import org.apache.commons.rdf.api.IRI;
  
  import java.util.Map;
  import java.util.Optional;
  
  public class TriplesMap {
  
      public enum Status {
          NOT_VALIDATED,
          VALID,
          INVALID
      }
  
      private final SQLPPTriplesMap sqlppTriplesMap;
      private final TriplesMapFactory factory;
  
      private Status status;
      private String sqlErrorMessage;
      private ImmutableList<String> invalidPlaceholders = ImmutableList.of();
  
      public TriplesMap(SQLPPTriplesMap sqlppTriplesMap, TriplesMapFactory factory) {
          this.sqlppTriplesMap = sqlppTriplesMap;
          this.factory = factory;
          this.status = Status.NOT_VALIDATED;
      }
  
      public TriplesMap(String id, String sqlQuery, ImmutableList<TargetAtom> targetQuery,  TriplesMapFactory factory) {
          this(new OntopNativeSQLPPTriplesMap(id, factory.getSourceQuery(sqlQuery), targetQuery), factory);
      }
  
      public String getId() { return sqlppTriplesMap.getId(); }
  
      public String getSqlQuery() { return sqlppTriplesMap.getSourceQuery().getSQL(); }
  
      public ImmutableList<TargetAtom> getTargetAtoms() { return sqlppTriplesMap.getTargetAtoms(); }
  
      public String getTargetRendering() {
          return factory.getTargetRendering(sqlppTriplesMap.getTargetAtoms());
      }
  
      public Status getStatus() { return status; }
  
      public void setStatus(Status status) { this.status = status; }
  
      public String getSqlErrorMessage() { return sqlErrorMessage; }
  
      public void setSqlErrorMessage(String sqlErrorMessage) { this.sqlErrorMessage = sqlErrorMessage; }
  
      public ImmutableList<String> getInvalidPlaceholders() { return invalidPlaceholders; }
  
      public void setInvalidPlaceholders(ImmutableList<String> invalidPlaceholders) { this.invalidPlaceholders = invalidPlaceholders; }
  
  
  
      public SQLPPTriplesMap asSQLPPTriplesMap() { return sqlppTriplesMap; }
  
  
      public TriplesMap createDuplicate(String newId) {
          TriplesMap copy = new TriplesMap(
                  new OntopNativeSQLPPTriplesMap(
                          newId, sqlppTriplesMap.getSourceQuery(), sqlppTriplesMap.getTargetAtoms()),
                  factory);
          copy.status = this.status;
          copy.sqlErrorMessage = this.sqlErrorMessage;
          copy.invalidPlaceholders = this.invalidPlaceholders;
          return copy;
      }
  
      private TriplesMap updateTargetAtoms(ImmutableList<TargetAtom> targetAtoms) {
          return new TriplesMap(
                  new OntopNativeSQLPPTriplesMap(
                          sqlppTriplesMap.getId(), sqlppTriplesMap.getSourceQuery(), targetAtoms),
                  factory);
      }
  
      public TriplesMap renamePredicate(IRI removedIri, IRI newIri) {
          return containsIri(removedIri)
                  ? updateTargetAtoms(sqlppTriplesMap.getTargetAtoms().stream()
                  .map(a -> containsIri(a, removedIri)
                          ? renamePredicate(a, newIri, factory)
                          : a)
                  .collect(ImmutableCollectors.toList()))
                  : this; // has not changed
      }
  
      private static TargetAtom renamePredicate(TargetAtom a, IRI newIri, TriplesMapFactory factory) {
          DistinctVariableOnlyDataAtom projectionAtom = a.getProjectionAtom();
          RDFAtomPredicate predicate = (RDFAtomPredicate) projectionAtom.getPredicate();
  
          Variable predicateVariable = predicate.getClassIRI(a.getSubstitutedTerms()).isPresent()
                  ? predicate.getObject(projectionAtom.getArguments())
                  : predicate.getProperty(projectionAtom.getArguments());
  
          Map.Entry<Variable, ImmutableTerm> newEntry = Maps.immutableEntry(
                  predicateVariable,
                  factory.getConstantIRI(newIri));  // we build a ground term for the IRI
  
          return factory.getTargetAtom(
                  projectionAtom,
                  a.getSubstitution().getImmutableMap().entrySet().stream()
                          .map(e -> e.getKey().equals(predicateVariable) ? newEntry : e)
                          .collect(ImmutableCollectors.toMap()));
      }
  
      public boolean containsIri(IRI iri) {
          return sqlppTriplesMap.getTargetAtoms().stream()
                  .anyMatch(a -> containsIri(a, iri));
      }
  
      private static boolean containsIri(TargetAtom a, IRI iri) {
          return a.getPredicateIRI()
                  .filter(i -> i.equals(iri))
                  .isPresent();
      }
  
      public Optional<TriplesMap> removePredicate(IRI predicateIRI) {
  
          ImmutableList<TargetAtom> newTargetAtoms = sqlppTriplesMap.getTargetAtoms().stream()
                  .filter(a -> !containsIri(a, predicateIRI))
                  .collect(ImmutableCollectors.toList());
  
          if (newTargetAtoms.isEmpty())
              return Optional.empty();
  
          if (newTargetAtoms.size() < sqlppTriplesMap.getTargetAtoms().size())
              return Optional.of(updateTargetAtoms(newTargetAtoms));
  
          return Optional.of(this); // has not changed
      }
  }
  
  
  