Coverage Summary for Class: KeyView (org.kitodo.dataeditor.ruleset)

Class Method, % Line, %
KeyView 92,3% (12/13) 94,9% (56/59)
KeyView$1 100% (1/1) 100% (1/1)
Total 92,9% (13/14) 95% (57/60)


 /*
  * (c) Kitodo. Key to digital objects e. V. <contact@kitodo.org>
  *
  * This file is part of the Kitodo project.
  *
  * It is licensed under GNU General Public License version 3 or later.
  *
  * For the full copyright and license information, please read the
  * GPL3-License.txt file that was distributed with this source code.
  */
 
 package org.kitodo.dataeditor.ruleset;
 
 import java.math.BigInteger;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.time.MonthDay;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale.LanguageRange;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.regex.Pattern;
 
 import org.kitodo.api.MetadataEntry;
 import org.kitodo.api.dataeditor.rulesetmanagement.DatesSimpleMetadataViewInterface;
 import org.kitodo.api.dataeditor.rulesetmanagement.Domain;
 import org.kitodo.api.dataeditor.rulesetmanagement.InputType;
 
 /**
  * A view on a key.
  */
 class KeyView extends AbstractKeyView<KeyDeclaration> implements DatesSimpleMetadataViewInterface {
     /**
      * The schema in which the part of the date relevant to this division is
      * stored. Apart from the dates built into Java and interpreted by the
      * runtime, there is still the special string “{@code yyyy/yyyy}”, which
      * stands for a double year, eg. an operation year that starts on a day
      * other than January 1. This works in conjunction with {@link #yearBegin}.
      */
     private String scheme;
 
     /**
      * The settings for this key.
      */
     private Settings settings;
 
     /**
      * Annual start of operation year.
      */
     private MonthDay yearBegin;
 
     /**
      * A new key view is created.
      *
      * @param keyDeclaration
      *            the key declaration
      * @param rule
      *            the rule
      * @param settings
      *            the settings
      * @param priorityList
      *            the user’s wish list for the preferred human language
      */
     KeyView(KeyDeclaration keyDeclaration, Rule rule, Settings settings,
             List<LanguageRange> priorityList) {
 
         super(keyDeclaration, rule, priorityList);
         this.settings = settings;
     }
 
     /**
      * Returns the predefined values for a new key.
      *
      * @return the predefined values
      */
     @Override
     public Collection<String> getDefaultItems() {
         return declaration.getDefaultItems();
     }
 
     /**
      * Returns the input field type for the input field for this metadata key.
      *
      * @return the input type
      */
     @Override
     public InputType getInputType() {
         /*
          * If the metadata key has a type that requires a special input field,
          * return the corresponding field type.
          */
         switch (declaration.getType()) {
             case ANY_URI:
                 return InputType.ONE_LINE_TEXT;
             case BOOLEAN:
                 return InputType.BOOLEAN;
             case DATE:
                 return InputType.DATE;
             case INTEGER:
                 return InputType.INTEGER;
             default:
                 // do nothing
         }
 
         /*
          * If the metadata key defines options, return the corresponding
          * selection type.
          */
         if (declaration.isWithOptions()) {
             if (rule.isRepeatable()) {
                 return InputType.MULTIPLE_SELECTION;
             }
             if (settings.isMultiline(declaration.getId())) {
                 return InputType.MULTI_LINE_SINGLE_SELECTION;
             } else {
                 return InputType.ONE_LINE_SINGLE_SELECTION;
             }
         }
 
         // otherwise, check if the key is required to have an enlarged text box
         if (settings.isMultiline(declaration.getId())) {
             return InputType.MULTI_LINE_TEXT;
         } else {
             return InputType.ONE_LINE_TEXT;
         }
     }
 
     @Override
     public String getScheme() {
         return scheme;
     }
 
     @Override
     public int getMinDigits() {
         return declaration.getMinDigits();
     }
     
     @Override
     public Map<String, String> getSelectItems(List<Map<MetadataEntry, Boolean>> metadata) {
         return rule.getSelectItems(declaration.getSelectItems(priorityList), metadata);
     }
 
     @Override
     public MonthDay getYearBegin() {
         return yearBegin;
     }
 
     @Override
     public boolean isEditable() {
         return settings.isEditable(declaration.getId());
     }
 
     /**
      * Checks if a URI is in the configured namespace, if one has been
      * specified. Typically, a namespace is used as a URL prefix. For namespaces
      * on the WWW ending in {@code /}, the {@code /} required. For the other
      * namespaces on the WWW ending in {@code #}, the {@code #} is optional.
      * Both spellings are equivalent. Then there is the spelling with braces.
      * This is no longer a valid URL, but is also allowed here. If the name
      * space is not on the WWW (i.e. does not start with {@code http}), the
      * variant is also allowed to be a simple prefix. However, this only needs
      * to be checked if the namespace has not ended with a {@code /}, otherwise
      * the test is equivalent.
      *
      * @param uri
      *            URI for which you want to check if it is in the specified
      *            namespace.
      * @return true, if the URI is in the specified namespace or no namespace is
      *         specified
      */
     private boolean isLocatedInTheNamespace(String uri) {
         Optional<String> optionalNamespace = declaration.getNamespace();
         if (optionalNamespace.isPresent()) {
             String namespaceAsStated = optionalNamespace.get();
             boolean endsWithSlash = namespaceAsStated.endsWith("/");
             String wwwNamespacePrefix = endsWithSlash || namespaceAsStated.endsWith("#") ? namespaceAsStated
                     : namespaceAsStated.concat("#");
             if (uri.startsWith(wwwNamespacePrefix) || uri.startsWith('{' + namespaceAsStated + '}')) {
                 return true;
             }
             return !endsWithSlash && !namespaceAsStated.toLowerCase().startsWith("http")
                     && uri.startsWith(namespaceAsStated);
         }
         return true;
     }
 
     /**
      * Checks if a value for a key is valid. This means a basic check, if the
      * value fits the key at all and can be saved. If this check fails, the
      * interface should reject the input.
      *
      * @return whether a value is valid
      */
     @Override
     public boolean isValid(String value, List<Map<MetadataEntry, Boolean>> metadata) {
         /*
          * Some data types are easily validated by Java built-in functions. We
          * will not implement it here again but try to create a corresponding
          * object. So it’s just about whether the constructor throws no mistake.
          * This simplifies the examination considerably.
          */
         try {
             if (Objects.isNull(declaration) || Objects.isNull(value)) {
                 return false;
             }
             switch (declaration.getType()) {
                 case ANY_URI:
                     if (!isLocatedInTheNamespace(value)) {
                         return false;
                     }
                     new URI(value);
                     break;
                 case DATE:
                     DateTimeFormatter.ISO_LOCAL_DATE.parse(value);
                     break;
                 case INTEGER:
                     new BigInteger(value);
                     break;
                 default:
                     if (!isLocatedInTheNamespace(value)) {
                         return false;
                     }
             }
         } catch (URISyntaxException | DateTimeParseException | NumberFormatException e) {
             return false;
         }
 
         // If the key has options, then the value must be in it.
         if (declaration.isWithOptions()
                 && !rule.getSelectItems(declaration.getSelectItems(priorityList), metadata).containsKey(value)) {
             return false;
         }
 
         /*
          * Then we check against the regular expression, if there is one. The
          * tests can be combined with each other, then all conditions must
          * apply.
          */
         Optional<Pattern> optionalPattern = declaration.getPattern();
         if (!optionalPattern.isPresent()) {
             return true;
         }
         return optionalPattern.get().matcher(value).matches();
     }
 
     void setScheme(String scheme) {
         this.scheme = scheme;
     }
 
     void setYearBegin(MonthDay yearBegin) {
         this.yearBegin = yearBegin;
     }
 
     @Override
     public Optional<Domain> getDomain() {
         return declaration.getDomain();
     }
 }