001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase;
019
020import java.util.Collections;
021import java.util.Comparator;
022import java.util.HashSet;
023import java.util.Map;
024import java.util.Set;
025import java.util.TreeMap;
026import java.util.TreeSet;
027import org.apache.hadoop.hbase.util.Bytes;
028import org.apache.yetus.audience.InterfaceAudience;
029
030/**
031 * Namespace POJO class. Used to represent and define namespaces. Descriptors will be persisted in
032 * an hbase table. This works since namespaces are essentially metadata of a group of tables as
033 * opposed to a more tangible container.
034 */
035@InterfaceAudience.Public
036public class NamespaceDescriptor {
037
038  /** System namespace name. */
039  public static final byte[] SYSTEM_NAMESPACE_NAME = Bytes.toBytes("hbase");
040  public static final String SYSTEM_NAMESPACE_NAME_STR = Bytes.toString(SYSTEM_NAMESPACE_NAME);
041  /** Default namespace name. */
042  public static final byte[] DEFAULT_NAMESPACE_NAME = Bytes.toBytes("default");
043  public static final String DEFAULT_NAMESPACE_NAME_STR = Bytes.toString(DEFAULT_NAMESPACE_NAME);
044  /** Backup namespace name. */
045  public static final byte[] BACKUP_NAMESPACE_NAME = Bytes.toBytes("backup");
046  public static final String BACKUP_NAMESPACE_NAME_STR = Bytes.toString(BACKUP_NAMESPACE_NAME);
047
048  public static final NamespaceDescriptor DEFAULT_NAMESPACE =
049    NamespaceDescriptor.create(DEFAULT_NAMESPACE_NAME_STR).build();
050  public static final NamespaceDescriptor SYSTEM_NAMESPACE =
051    NamespaceDescriptor.create(SYSTEM_NAMESPACE_NAME_STR).build();
052
053  public final static Set<String> RESERVED_NAMESPACES;
054  static {
055    Set<String> set = new HashSet<>();
056    set.add(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR);
057    set.add(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR);
058    RESERVED_NAMESPACES = Collections.unmodifiableSet(set);
059  }
060  public final static Set<byte[]> RESERVED_NAMESPACES_BYTES;
061  static {
062    Set<byte[]> set = new TreeSet<>(Bytes.BYTES_RAWCOMPARATOR);
063    for (String name : RESERVED_NAMESPACES) {
064      set.add(Bytes.toBytes(name));
065    }
066    RESERVED_NAMESPACES_BYTES = Collections.unmodifiableSet(set);
067  }
068
069  private String name;
070  private Map<String, String> configuration;
071
072  public static final Comparator<NamespaceDescriptor> NAMESPACE_DESCRIPTOR_COMPARATOR =
073    new Comparator<NamespaceDescriptor>() {
074      @Override
075      public int compare(NamespaceDescriptor namespaceDescriptor,
076        NamespaceDescriptor namespaceDescriptor2) {
077        return namespaceDescriptor.getName().compareTo(namespaceDescriptor2.getName());
078      }
079    };
080
081  private NamespaceDescriptor() {
082  }
083
084  private NamespaceDescriptor(String name) {
085    this.name = name;
086  }
087
088  public String getName() {
089    return name;
090  }
091
092  /**
093   * Getter for accessing the configuration value by key
094   */
095  public String getConfigurationValue(String key) {
096    return configuration.get(key);
097  }
098
099  /**
100   * Getter for fetching an unmodifiable {@link #configuration} map.
101   */
102  public Map<String, String> getConfiguration() {
103    // shallow pointer copy
104    return Collections.unmodifiableMap(configuration);
105  }
106
107  /**
108   * Setter for storing a configuration setting in {@link #configuration} map.
109   * @param key   Config key. Same as XML config key e.g. hbase.something.or.other.
110   * @param value String value. If null, removes the setting.
111   */
112  public void setConfiguration(String key, String value) {
113    if (value == null) {
114      removeConfiguration(key);
115    } else {
116      configuration.put(key, value);
117    }
118  }
119
120  /**
121   * Remove a config setting represented by the key from the {@link #configuration} map
122   */
123  public void removeConfiguration(final String key) {
124    configuration.remove(key);
125  }
126
127  @Override
128  public String toString() {
129    StringBuilder s = new StringBuilder();
130    s.append('{');
131    s.append(HConstants.NAME);
132    s.append(" => '");
133    s.append(name);
134    s.append("'");
135    for (Map.Entry<String, String> e : configuration.entrySet()) {
136      String key = e.getKey();
137      String value = e.getValue();
138      if (key == null) {
139        continue;
140      }
141      s.append(", ");
142      s.append(key);
143      s.append(" => '");
144      s.append(value);
145      s.append("'");
146    }
147    s.append('}');
148    return s.toString();
149  }
150
151  public static Builder create(String name) {
152    return new Builder(name);
153  }
154
155  public static Builder create(NamespaceDescriptor ns) {
156    return new Builder(ns);
157  }
158
159  @InterfaceAudience.Public
160  public static class Builder {
161    private String bName;
162    private Map<String, String> bConfiguration = new TreeMap<>();
163
164    private Builder(NamespaceDescriptor ns) {
165      this.bName = ns.name;
166      this.bConfiguration.putAll(ns.configuration);
167    }
168
169    private Builder(String name) {
170      this.bName = name;
171    }
172
173    public Builder addConfiguration(Map<String, String> configuration) {
174      this.bConfiguration.putAll(configuration);
175      return this;
176    }
177
178    public Builder addConfiguration(String key, String value) {
179      this.bConfiguration.put(key, value);
180      return this;
181    }
182
183    public Builder removeConfiguration(String key) {
184      this.bConfiguration.remove(key);
185      return this;
186    }
187
188    public NamespaceDescriptor build() {
189      if (this.bName == null) {
190        throw new IllegalArgumentException("A name has to be specified in a namespace.");
191      }
192
193      NamespaceDescriptor desc = new NamespaceDescriptor(this.bName);
194      desc.configuration = this.bConfiguration;
195      return desc;
196    }
197  }
198}