/* * Copyright (C) 2014 Jörg Prante * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, see http://www.gnu.org/licenses * or write to the Free Software Foundation, Inc., 51 Franklin Street, * Fifth Floor, Boston, MA 02110-1301 USA. * * The interactive user interfaces in modified source and object code * versions of this program must display Appropriate Legal Notices, * as required under Section 5 of the GNU Affero General Public License. * */ package org.xbib.standardnumber; import java.net.URI; import java.util.Arrays; import java.util.Collection; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * ISO 26324: Digital Object Identifier System (DOI) * * Z39.50 BIB-1 Use Attribute 1094 * * DOI is an acronym for "digital object identifier", meaning a "digital identifier of an object" * rather than an "identifier of a digital object". The DOI system was initiated by the * International DOI Foundation in 1998, and initially developed with the collaboration * of some participants in ISO/TC46/SC9. Due to its application in the fields of * information and documentation and previous collaboration with some ISO/TC46/SC9 participants, * it was introduced as a possible work item in 2004 and further developed from 2006 to 2010. * * The DOI system is designed to work over the Internet. A DOI name is permanently assigned * to an object to provide a resolvable persistent network link to current information about * that object, including where the object, or information about it, can be found on the * Internet. While information about an object can change over time, its DOI name will not * change. A DOI name can be resolved within the DOI system to values of one or more types * of data relating to the object identified by that DOI name, such as a URL, an e-mail address, * other identifiers and descriptive metadata. * * The DOI system enables the construction of automated services and transactions. * Applications of the DOI system include but are not limited to managing information * and documentation location and access; managing metadata; facilitating electronic * transactions; persistent unique identification of any form of any data; and commercial * and non-commercial transactions. * * The content of an object associated with a DOI name is described unambiguously * by DOI metadata, based on a structured extensible data model that enables the object * to be associated with metadata of any desired degree of precision and granularity * to support description and services. The data model supports interoperability * between DOI applications. * * The scope of the DOI system is not defined by reference to the type of content * (format, etc.) of the referent, but by reference to the functionalities it provides * and the context of use. The DOI system provides, within networks of DOI applications, * for unique identification, persistence, resolution, metadata and semantic interoperability. * */ public class DOI extends AbstractStandardNumber implements Comparable<DOI>, StandardNumber { private static final Pattern DOI_PATTERN = Pattern.compile("\\b10\\.\\d{4}([.][0-9]+)*/[a-z0-9/\\-.()<>_:;\\\\]+\\b"); private static final Pattern DOI_URI_PATTERN = Pattern.compile("\\b(https?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]\\b"); private Object raw; private String value; private URI infoURI; private URI httpDoi; private URI httpDxDoi; @Override public String type() { return "doi"; } @Override public int compareTo(DOI doi) { return doi != null ? normalizedValue().compareTo(doi.normalizedValue()) : -1; } @Override public DOI set(CharSequence value) { this.raw = value; return this; } @Override public DOI createChecksum(boolean checksum) { return this; } @Override public DOI normalize() { if (raw == null) { return this; } make(raw); return this; } @Override public boolean isValid() { return value != null; } @Override public DOI verify() throws NumberFormatException { if (value == null) { throw new NumberFormatException(); } return this; } @Override public String normalizedValue() { return value; } @Override public String format() { return httpDoi != null ? httpDoi.toString() : ""; // preferred form } @Override public Collection<String> getTypedVariants() { return Arrays.asList( value != null ? type().toUpperCase() + " " + value : null, infoURI != null ? type().toUpperCase() + " " + infoURI.toString() : null, httpDoi != null ? type().toUpperCase() + " " + httpDoi.toString() : null, httpDxDoi != null ? type().toUpperCase() + " " + httpDxDoi.toString() : null ); } public DOI reset() { this.value = null; return this; } private void make(Object o) { // DOIs are case insensitive in ASCII // DOI service only use upper casing, we use lowercasing (better for search engines) String content = o.toString().toLowerCase(Locale.US); // is it an already a DOI URI? Matcher m = DOI_URI_PATTERN.matcher(content); if (m.find()) { URI u = URI.create(content.substring(m.start(), m.end())); if ("http".equals(u.getScheme()) && ("dx.doi.org".equals(u.getHost()) || "doi.org".equals(u.getHost()))) { content = u.getRawPath(); } else { return; } } m = DOI_PATTERN.matcher(content); if (m.find()) { this.value = content.substring(m.start(), m.end()); this.infoURI = URI.create("info:doi:" + value); this.httpDoi = URI.create("http://doi.org/" + value); this.httpDxDoi = URI.create("http://dx.doi.org/" + value); } } }