@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());
    }
  }
Esempio n. 2
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;
    }
  }