/**
   * Returns the LSRN identifier for the given node. The method will first try to obtain an
   * explicitly specified ID as encoded by the following SIO attribute structure:
   *
   * <pre>{@code
   * root [
   *   'has attribute'/'has identifier' (SIO_000008/SIO_000067)
   *     [
   *       rdf:type $identifierClass;
   *       'has value' (SIO_000300) $ID
   *     ]
   * ]
   * }</pre>
   *
   * <p>If no such structure is attached to root, then the method will fall back to parsing the ID
   * from the root's URI, using the regular expressions associated with the given LSRN identifier
   * class.
   *
   * @param root the root resource
   * @param lsrnIdentifierType the LSRN identifier type URI (e.g. lsrn:UniProt_Identifier).
   * @return the database identifier of the given node
   */
  public static String getID(Resource root, Resource lsrnIdentifierType) {
    Collection<String> identifiers = SIOUtils.getAttributeValues(root, lsrnIdentifierType);
    identifiers.addAll(SIOUtils.getAttributeValues(root, SIO.has_identifier, lsrnIdentifierType));

    if (identifiers.size() > 0) {
      if (identifiers.size() > 1) {
        log.warn(
            String.format(
                "%s has multiple IDs of type %s, returning only the first ID",
                root, lsrnIdentifierType));
      }
      return identifiers.iterator().next();
    }

    log.info(String.format("%s has no explicit ID, attempting to parse URI", root));
    if (!root.isURIResource()) {
      log.warn(
          "could not determine the database ID, resource has no attached LSRN ID and is a blank node");
      return null;
    }

    String uri = root.getURI();
    for (Pattern pattern : Config.getConfig().getURIPatterns(lsrnIdentifierType)) {
      Matcher matcher = pattern.matcher(uri);
      if (matcher.groupCount() < 1) {
        log.warn(String.format("URI pattern '%s' does not contain any capturing groups", pattern));
        continue;
      }
      if (matcher.find()) {
        String match = matcher.group(1);
        if (!match.isEmpty()) return match;
      }
    }

    log.warn(
        String.format(
            "could not determine lsrn ID for %s, it has no attached ID and does not match any known URI pattern",
            root));
    return null;
  }
 /**
  * Returns a Resource in the specified model that is an instance of the specified type with the
  * specified ID. The Resource will be created with an appropriate URI (@link {@link
  * #OUTPUT_URI_PATTERN}).
  *
  * @param model the model in which to create the new Resource
  * @param type the type (class) of the new instance
  * @param id the id of the new instance
  * @return a Resource view of the new instance
  */
 public static Resource createInstance(Model model, Resource type, String id) {
   Matcher matcher = TYPE_PATTERN.matcher(type.getURI());
   if (matcher.find()) {
     String namespace = matcher.group(1);
     String uri = getURI(namespace, id);
     Resource lsrnNode = model.createResource(uri, type);
     SIOUtils.createAttribute(lsrnNode, SIO.has_identifier, getIdentifierClass(namespace), id);
     return lsrnNode;
   } else {
     throw new IllegalArgumentException(
         "at present this method only works with LSRN database record classes");
   }
 }
 /**
  * Adds the LSRN SIO identifier structure to an LSRN-typed Resource. Attempts to use the URL of
  * the Resource to determine the ID.
  *
  * @param lsrnNode
  */
 public static void addIdentifier(Resource lsrnNode) {
   if (lsrnNode.isURIResource()) {
     Matcher idMatcher = ID_PATTERN.matcher(lsrnNode.getURI());
     if (idMatcher.find()) {
       String id = idMatcher.group(1);
       for (Resource type : RdfUtils.getTypes(lsrnNode).toList()) {
         if (!type.isURIResource()) continue;
         Matcher typeMatcher = TYPE_PATTERN.matcher(type.getURI());
         if (typeMatcher.find()) {
           String idTypeURI = OUTPUT_ID_TYPE_PATTERN.replace("$NS", typeMatcher.group(1));
           SIOUtils.createAttribute(
               lsrnNode, SIO.has_identifier, ResourceFactory.createResource(idTypeURI), id);
         }
       }
     }
   }
 }