001/*
002 * (C) Copyright 2020 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     bdelbosc
018 */
019package org.nuxeo.lib.stream.log;
020
021import java.util.Objects;
022import java.util.regex.Pattern;
023
024/**
025 * An identifier composed of a namespace and a specific name with 2 string representations:<br>
026 * - an uniform resource name (urn) represented as a relative path: {@code namespace/name}<br>
027 * - an identifier (id): encode the urn as {@code namespace-name}<br>
028 *
029 *
030 * When there is no namespace, URN and id are identical.
031 *
032 * @since 11.1
033 */
034public class Name {
035    public static final String NAMESPACE_GLOBAL = "_GLOBAL_";
036
037    public static final String NAMESPACE_URN_SEP = "/";
038
039    public static final String NAMESPACE_ID_SEP = "-";
040
041    protected static final Pattern VALID_NAMESPACE_PATTERN = Pattern.compile("[A-Za-z][A-Za-z0-9_]*");
042
043    protected static final Pattern VALID_LOG_NAME_PATTERN = Pattern.compile("[A-Za-z0-9][A-Za-z0-9_\\-]*");
044
045    protected static final Pattern VALID_LOG_NAME_WITHOUT_NS_PATTERN = Pattern.compile("[A-Za-z0-9][A-Za-z0-9_]*");
046
047    protected final String namespace;
048
049    protected final String name;
050
051    protected final String id;
052
053    protected final String urn;
054
055    private Name(String namespace, String name) {
056        checkNameSpace(namespace);
057        this.namespace = namespace;
058        this.name = name;
059        if (NAMESPACE_GLOBAL.equals(namespace)) {
060            checkLogNameWithoutNamespace(name);
061            this.id = name;
062            this.urn = name;
063        } else {
064            checkLogName(name);
065            this.id = namespace + NAMESPACE_ID_SEP + name;
066            this.urn = namespace + NAMESPACE_URN_SEP + name;
067        }
068    }
069
070    public static Name of(String namespace, String name) {
071        return new Name(namespace, name);
072    }
073
074    public static Name ofUrn(String urn) {
075        Objects.requireNonNull(urn, "Null URN");
076        int pos = urn.indexOf(NAMESPACE_URN_SEP);
077        if (pos < 0) {
078            return new Name(NAMESPACE_GLOBAL, urn);
079        }
080        return new Name(urn.substring(0, pos), urn.substring(pos + 1));
081    }
082
083    public static Name ofId(String id) {
084        Objects.requireNonNull(id, "Null id");
085        int pos = id.indexOf(NAMESPACE_ID_SEP);
086        if (pos < 0) {
087            return new Name(NAMESPACE_GLOBAL, id);
088        }
089        return new Name(id.substring(0, pos), id.substring(pos + 1));
090    }
091
092    public static String idOfUrn(String urn) {
093        return Name.ofUrn(urn).getId();
094    }
095
096    public static String urnOfId(String id) {
097        return Name.ofId(id).getUrn();
098    }
099
100    public String getNamespace() {
101        return namespace;
102    }
103
104    public String getName() {
105        return name;
106    }
107
108    public String getId() {
109        return id;
110    }
111
112    public String getUrn() {
113        return urn;
114    }
115
116    @Override
117    public String toString() {
118        return "Name{id='" + id + "', urn='" + urn + "'}";
119    }
120
121    protected static void checkLogName(String name) {
122        if (!VALID_LOG_NAME_PATTERN.matcher(name).matches()) {
123            throw new IllegalArgumentException("Invalid name: '" + name + "'.");
124        }
125    }
126
127    protected static void checkLogNameWithoutNamespace(String name) {
128        if (!VALID_LOG_NAME_WITHOUT_NS_PATTERN.matcher(name).matches()) {
129            throw new IllegalArgumentException("Invalid name without namespace: '" + name + "'");
130        }
131    }
132
133    protected static void checkNameSpace(String name) {
134        if (!VALID_NAMESPACE_PATTERN.matcher(name).matches() && !NAMESPACE_GLOBAL.equals(name)) {
135            throw new IllegalArgumentException("Invalid namespace: '" + name + "'");
136        }
137    }
138
139    @Override
140    public boolean equals(Object o) {
141        if (this == o) {
142            return true;
143        }
144        if (o == null || getClass() != o.getClass()) {
145            return false;
146        }
147        Name otherName = (Name) o;
148        return Objects.equals(urn, otherName.urn);
149    }
150
151    @Override
152    public int hashCode() {
153        return Objects.hash(urn);
154    }
155}