/**
   * Utility method for pattern-matching metadata elements. This method will return <code>true
   * </code> if the given schema, element, qualifier and language match the schema, element,
   * qualifier and language of the <code>DCValue</code> object passed in. Any or all of the element,
   * qualifier and language passed in can be the <code>Item.ANY</code> wildcard.
   *
   * @param schema the schema for the metadata field. <em>Must</em> match the <code>name</code> of
   *     an existing metadata schema.
   * @param element the element to match, or <code>Item.ANY</code>
   * @param qualifier the qualifier to match, or <code>Item.ANY</code>
   * @param language the language to match, or <code>Item.ANY</code>
   * @param metadataValue the Dublin Core value
   * @return <code>true</code> if there is a match
   */
  protected boolean match(
      String schema,
      String element,
      String qualifier,
      String language,
      MetadataValue metadataValue) {

    MetadataField metadataField = metadataValue.getMetadataField();
    MetadataSchema metadataSchema = metadataField.getMetadataSchema();
    // We will attempt to disprove a match - if we can't we have a match
    if (!element.equals(Item.ANY) && !element.equals(metadataField.getElement())) {
      // Elements do not match, no wildcard
      return false;
    }

    if (qualifier == null) {
      // Value must be unqualified
      if (metadataField.getQualifier() != null) {
        // Value is qualified, so no match
        return false;
      }
    } else if (!qualifier.equals(Item.ANY)) {
      // Not a wildcard, so qualifier must match exactly
      if (!qualifier.equals(metadataField.getQualifier())) {
        return false;
      }
    }

    if (language == null) {
      // Value must be null language to match
      if (metadataValue.getLanguage() != null) {
        // Value is qualified, so no match
        return false;
      }
    } else if (!language.equals(Item.ANY)) {
      // Not a wildcard, so language must match exactly
      if (!language.equals(metadataValue.getLanguage())) {
        return false;
      }
    }

    if (!schema.equals(Item.ANY)) {
      if (metadataSchema != null && !metadataSchema.getName().equals(schema)) {
        // The namespace doesn't match
        return false;
      }
    }

    // If we get this far, we have a match
    return true;
  }
 @Override
 public void update(Context context, T dso) throws SQLException, AuthorizeException {
   if (dso.isMetadataModified()) {
     /*
     Update the order of the metadata values
      */
     // A map created to store the latest place for each metadata field
     Map<MetadataField, Integer> fieldToLastPlace = new HashMap<>();
     List<MetadataValue> metadataValues = dso.getMetadata();
     for (MetadataValue metadataValue : metadataValues) {
       // Retrieve & store the place for each metadata value
       int mvPlace = getMetadataValuePlace(fieldToLastPlace, metadataValue);
       metadataValue.setPlace(mvPlace);
     }
   }
 }
 @Override
 public void clearMetadata(
     Context context, T dso, String schema, String element, String qualifier, String lang)
     throws SQLException {
   // We will build a list of values NOT matching the values to clear
   Iterator<MetadataValue> metadata = dso.getMetadata().iterator();
   while (metadata.hasNext()) {
     MetadataValue metadataValue = metadata.next();
     if (match(schema, element, qualifier, lang, metadataValue)) {
       metadataValue.setDSpaceObject(null);
       metadata.remove();
       //                metadataValueService.delete(context, metadataValue);
     }
   }
   dso.setMetadataModified();
 }
 @Override
 public List<MetadataValue> getMetadata(
     T dso, String schema, String element, String qualifier, String lang, String authority) {
   List<MetadataValue> metadata = getMetadata(dso, schema, element, qualifier, lang);
   List<MetadataValue> result = new ArrayList<>(metadata);
   if (!authority.equals(Item.ANY)) {
     Iterator<MetadataValue> iterator = result.iterator();
     while (iterator.hasNext()) {
       MetadataValue metadataValue = iterator.next();
       if (!authority.equals(metadataValue.getAuthority())) {
         iterator.remove();
       }
     }
   }
   return result;
 }
 /**
  * Retrieve the place of the metadata value
  *
  * @param fieldToLastPlace the map containing the latest place of each metadata field
  * @param metadataValue the metadata value that needs to get a place
  * @return The new place for the metadata valu
  */
 protected int getMetadataValuePlace(
     Map<MetadataField, Integer> fieldToLastPlace, MetadataValue metadataValue) {
   MetadataField metadataField = metadataValue.getMetadataField();
   if (fieldToLastPlace.containsKey(metadataField)) {
     fieldToLastPlace.put(metadataField, fieldToLastPlace.get(metadataField) + 1);
   } else {
     // The metadata value place starts at 0
     fieldToLastPlace.put(metadataField, 0);
   }
   return fieldToLastPlace.get(metadataField);
 }
  @Override
  public void addMetadata(
      Context context,
      T dso,
      MetadataField metadataField,
      String lang,
      List<String> values,
      List<String> authorities,
      List<Integer> confidences)
      throws SQLException {
    boolean authorityControlled = metadataAuthorityService.isAuthorityControlled(metadataField);
    boolean authorityRequired = metadataAuthorityService.isAuthorityRequired(metadataField);

    // We will not verify that they are valid entries in the registry
    // until update() is called.
    for (int i = 0; i < values.size(); i++) {

      MetadataValue metadataValue = metadataValueService.create(context, dso, metadataField);
      metadataValue.setLanguage(lang == null ? null : lang.trim());

      // Logic to set Authority and Confidence:
      //  - normalize an empty string for authority to NULL.
      //  - if authority key is present, use given confidence or NOVALUE if not given
      //  - otherwise, preserve confidence if meaningful value was given since it may document a
      // failed authority lookup
      //  - CF_UNSET signifies no authority nor meaningful confidence.
      //  - it's possible to have empty authority & CF_ACCEPTED if e.g. user deletes authority key
      if (authorityControlled) {
        if (authorities != null && authorities.get(i) != null && authorities.get(i).length() > 0) {
          metadataValue.setAuthority(authorities.get(i));
          metadataValue.setConfidence(
              confidences == null ? Choices.CF_NOVALUE : confidences.get(i));
        } else {
          metadataValue.setAuthority(null);
          metadataValue.setConfidence(confidences == null ? Choices.CF_UNSET : confidences.get(i));
        }
        // authority sanity check: if authority is required, was it supplied?
        // XXX FIXME? can't throw a "real" exception here without changing all the callers to expect
        // it, so use a runtime exception
        if (authorityRequired
            && (metadataValue.getAuthority() == null
                || metadataValue.getAuthority().length() == 0)) {
          throw new IllegalArgumentException(
              "The metadata field \""
                  + metadataField.toString()
                  + "\" requires an authority key but none was provided. Value=\""
                  + values.get(i)
                  + "\"");
        }
      }
      if (values.get(i) != null) {
        // remove control unicode char
        String temp = values.get(i).trim();
        char[] dcvalue = temp.toCharArray();
        for (int charPos = 0; charPos < dcvalue.length; charPos++) {
          if (Character.isISOControl(dcvalue[charPos])
              && !String.valueOf(dcvalue[charPos]).equals("\u0009")
              && !String.valueOf(dcvalue[charPos]).equals("\n")
              && !String.valueOf(dcvalue[charPos]).equals("\r")) {
            dcvalue[charPos] = ' ';
          }
        }
        metadataValue.setValue(String.valueOf(dcvalue));
        ;
      } else {
        metadataValue.setValue(null);
      }
      // An update here isn't needed, this is persited upon the merge of the owning object
      //            metadataValueService.update(context, metadataValue);
      dso.addDetails(metadataField.toString());
    }
  }
Example #7
0
  public void updateMetadata() throws SQLException, AuthorizeException {
    // Map counting number of values for each element/qualifier.
    // Keys are Strings: "element" or "element.qualifier"
    // Values are Integers indicating number of values written for a
    // element/qualifier
    Map<String, Integer> elementCount = new HashMap<String, Integer>();

    modifiedMetadata = false;

    // Arrays to store the working information required
    int[] placeNum = new int[getMetadata().size()];
    boolean[] storedDC = new boolean[getMetadata().size()];
    MetadataField[] dcFields = new MetadataField[getMetadata().size()];

    // Work out the place numbers for the in memory DC
    for (int dcIdx = 0; dcIdx < getMetadata().size(); dcIdx++) {
      DCValue dcv = getMetadata().get(dcIdx);

      // Work out the place number for ordering
      int current = 0;

      // Key into map is "element" or "element.qualifier"
      String key = dcv.element + ((dcv.qualifier == null) ? "" : ("." + dcv.qualifier));

      Integer currentInteger = elementCount.get(key);
      if (currentInteger != null) {
        current = currentInteger.intValue();
      }

      current++;
      elementCount.put(key, Integer.valueOf(current));

      // Store the calculated place number, reset the stored flag, and cache the metadatafield
      placeNum[dcIdx] = current;
      storedDC[dcIdx] = false;
      dcFields[dcIdx] = getMetadataField(dcv);
      if (dcFields[dcIdx] == null) {
        // Bad DC field, log and throw exception
        log.warn("Invalid metadata field: [" + dcv.getField() + "] : [" + dcv.value + "]");
        throw new SQLException("Invalid metadata field: [" + dcv.getField() + "]");
      }
    }

    // Now the precalculations are done, iterate through the existing metadata
    // looking for matches
    TableRowIterator tri = retrieveMetadata();
    if (tri != null) {
      try {
        while (tri.hasNext()) {
          TableRow tr = tri.next();
          // Assume that we will remove this row, unless we get a match
          boolean removeRow = true;

          // Go through the in-memory metadata, unless we've already decided to keep this row
          for (int dcIdx = 0; dcIdx < getMetadata().size() && removeRow; dcIdx++) {
            // Only process if this metadata has not already been matched to something in the DB
            if (!storedDC[dcIdx]) {
              boolean matched = true;
              DCValue dcv = getMetadata().get(dcIdx);

              // Check the metadata field is the same
              if (matched && dcFields[dcIdx].getFieldID() != tr.getIntColumn("metadata_field_id")) {
                matched = false;
              }

              // Check the place is the same
              if (matched && placeNum[dcIdx] != tr.getIntColumn("place")) {
                matched = false;
              }

              // Check the text is the same
              if (matched) {
                String text = tr.getStringColumn("text_value");
                if (dcv.value == null && text == null) {
                  matched = true;
                } else if (dcv.value != null && dcv.value.equals(text)) {
                  matched = true;
                } else {
                  matched = false;
                }
              }

              // Check the language is the same
              if (matched) {
                String lang = tr.getStringColumn("text_lang");
                if (dcv.language == null && lang == null) {
                  matched = true;
                } else if (dcv.language != null && dcv.language.equals(lang)) {
                  matched = true;
                } else {
                  matched = false;
                }
              }

              // check that authority and confidence match
              if (matched) {
                String auth = tr.getStringColumn("authority");
                int conf = tr.getIntColumn("confidence");
                if (!((dcv.authority == null && auth == null)
                    || (dcv.authority != null && auth != null && dcv.authority.equals(auth))
                        && dcv.confidence == conf)) {
                  matched = false;
                }
              }

              // If the db record is identical to the in memory values
              if (matched) {
                // Flag that the metadata is already in the DB
                storedDC[dcIdx] = true;

                // Flag that we are not going to remove the row
                removeRow = false;
              }
            }
          }

          // If after processing all the metadata values, we didn't find a match
          // delete this row from the DB
          if (removeRow) {
            DatabaseManager.delete(ourContext, tr);
            modifiedMetadata = true;
          }
        }
      } finally {
        tri.close();
      }
    }

    // Add missing in-memory DC
    for (int dcIdx = 0; dcIdx < getMetadata().size(); dcIdx++) {
      // Only write values that are not already in the db
      if (!storedDC[dcIdx]) {
        DCValue dcv = getMetadata().get(dcIdx);

        // Write DCValue
        MetadataValue metadata = new MetadataValue();
        metadata.setResourceId(getID());
        metadata.setResourceTypeId(getType());
        metadata.setFieldId(dcFields[dcIdx].getFieldID());
        metadata.setValue(dcv.value);
        metadata.setLanguage(dcv.language);
        metadata.setPlace(placeNum[dcIdx]);
        metadata.setAuthority(dcv.authority);
        metadata.setConfidence(dcv.confidence);
        metadata.create(ourContext);
        modifiedMetadata = true;
      }
    }

    if (modifiedMetadata) {
      ourContext.addEvent(
          new Event(
              Event.MODIFY_METADATA, getType(), getID(), getDetails(), getIdentifiers(ourContext)));
      modifiedMetadata = false;
    }
  }