001/*
002 * Licensed under the Apache License, Version 2.0 (the "License");
003 * you may not use this file except in compliance with the License.
004 * You may obtain a copy of the License at
005 *
006 *     http://www.apache.org/licenses/LICENSE-2.0
007 *
008 * Unless required by applicable law or agreed to in writing, software
009 * distributed under the License is distributed on an "AS IS" BASIS,
010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011 * See the License for the specific language governing permissions and
012 * limitations under the License.
013 */
014package org.gbif.common.parsers;
015
016import org.gbif.api.vocabulary.License;
017import org.gbif.common.parsers.core.EnumParser;
018import org.gbif.common.parsers.core.ParseResult;
019
020import java.net.URI;
021import java.util.regex.Pattern;
022
023import javax.annotation.Nullable;
024
025import org.apache.commons.lang3.StringUtils;
026
027/**
028 * Singleton implementation of the dictionary that uses the file /dictionaries/parse/license.txt to lookup a
029 * License by its URI or its acronym/title, e.g. a lookup by "CC-BY 4.0" returns License.CC_BY_4_0.
030 * </br>
031 * The dictionary file must enforce the <a href="http://www.gbif.org/terms/licences">GBIF Licensing Policy</a>.
032 * Non-CC licenses that GBIF considers equal to one of its three supported CC licenses (CC0 1.0, CC-BY 4.0 and CC-BY-NC
033 * 4.0) can be added to this file.
034 * </br>
035 * Note a lookup by license acronym/title without a version number defaults to the latest version of that license,
036 * e.g. a lookup by "CC-BY" returns License.CC_BY_4_0.
037 */
038public class LicenseParser extends EnumParser<License> {
039
040  private static final String COMMENT_MARKER = "#";
041  private static final String LICENSE_FILEPATH = "/dictionaries/parse/license.tsv";
042  //allows us to remove the protocol part for http:// and https://
043  private static final Pattern REMOVE_HTTP_PATTERN = Pattern.compile("^https?:\\/\\/", Pattern.CASE_INSENSITIVE);
044  private static LicenseParser singletonObject = null;
045
046  private LicenseParser() {
047    super(License.class, true);
048    // also make sure we have all enum values and their parameters title and url mapped
049    for (License l : License.values()) {
050      add(l.name(), l);
051      add(l.getLicenseTitle(), l);
052      add(l.getLicenseUrl(), l);
053    }
054    // use dict file last
055    init(LicenseParser.class.getResourceAsStream(LICENSE_FILEPATH), COMMENT_MARKER);
056  }
057
058  @Override
059  protected String normalize(String value) {
060    if(value == null){
061      return null;
062    }
063    return super.normalize(REMOVE_HTTP_PATTERN.matcher(value).replaceAll(""));
064  }
065
066  public static LicenseParser getInstance() {
067    synchronized (ContinentParser.class) {
068      if (singletonObject == null) {
069        singletonObject = new LicenseParser();
070      }
071    }
072    return singletonObject;
073  }
074
075  /**
076   * Parse license supplied in two parts: URI and title. First parse URI. Only if no URI supplied, parse title.
077   * supplied.
078   *
079   * @param uri   optional license URI
080   * @param title optional license title
081   *
082   * @return License corresponding to license URI or title, License.UNSPECIFIED if both URI and title not supplied,
083   * otherwise defaults to License.UNSUPPORTED
084   */
085  public License parseUriThenTitle(@Nullable URI uri, @Nullable String title) {
086    if (uri == null && StringUtils.isEmpty(title)) {
087      return License.UNSPECIFIED;
088    }
089
090    if (uri != null) {
091      ParseResult<License> result = singletonObject.parse(uri.toString());
092      if (result.isSuccessful()) {
093        return result.getPayload();
094      }
095    }
096
097    if (StringUtils.isNotEmpty(title)) {
098      ParseResult<License> result = singletonObject.parse(title);
099      if (result.isSuccessful()) {
100        return result.getPayload();
101      }
102    }
103
104    return License.UNSUPPORTED;
105  }
106}