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
045  public static final NamespaceDescriptor DEFAULT_NAMESPACE =
046    NamespaceDescriptor.create(DEFAULT_NAMESPACE_NAME_STR).build();
047  public static final NamespaceDescriptor SYSTEM_NAMESPACE =
048    NamespaceDescriptor.create(SYSTEM_NAMESPACE_NAME_STR).build();
049
050  public final static Set<String> RESERVED_NAMESPACES;
051  static {
052    Set<String> set = new HashSet<>();
053    set.add(NamespaceDescriptor.DEFAULT_NAMESPACE_NAME_STR);
054    set.add(NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR);
055    RESERVED_NAMESPACES = Collections.unmodifiableSet(set);
056  }
057  public final static Set<byte[]> RESERVED_NAMESPACES_BYTES;
058  static {
059    Set<byte[]> set = new TreeSet<>(Bytes.BYTES_RAWCOMPARATOR);
060    for (String name : RESERVED_NAMESPACES) {
061      set.add(Bytes.toBytes(name));
062    }
063    RESERVED_NAMESPACES_BYTES = Collections.unmodifiableSet(set);
064  }
065
066  private String name;
067  private Map<String, String> configuration;
068
069  public static final Comparator<NamespaceDescriptor> NAMESPACE_DESCRIPTOR_COMPARATOR =
070    new Comparator<NamespaceDescriptor>() {
071      @Override
072      public int compare(NamespaceDescriptor namespaceDescriptor,
073        NamespaceDescriptor namespaceDescriptor2) {
074        return namespaceDescriptor.getName().compareTo(namespaceDescriptor2.getName());
075      }
076    };
077
078  private NamespaceDescriptor() {
079  }
080
081  private NamespaceDescriptor(String name) {
082    this.name = name;
083  }
084
085  public String getName() {
086    return name;
087  }
088
089  /**
090   * Getter for accessing the configuration value by key
091   */
092  public String getConfigurationValue(String key) {
093    return configuration.get(key);
094  }
095
096  /**
097   * Getter for fetching an unmodifiable {@link #configuration} map.
098   */
099  public Map<String, String> getConfiguration() {
100    // shallow pointer copy
101    return Collections.unmodifiableMap(configuration);
102  }
103
104  /**
105   * Setter for storing a configuration setting in {@link #configuration} map.
106   * @param key   Config key. Same as XML config key e.g. hbase.something.or.other.
107   * @param value String value. If null, removes the setting.
108   */
109  public void setConfiguration(String key, String value) {
110    if (value == null) {
111      removeConfiguration(key);
112    } else {
113      configuration.put(key, value);
114    }
115  }
116
117  /**
118   * Remove a config setting represented by the key from the {@link #configuration} map
119   */
120  public void removeConfiguration(final String key) {
121    configuration.remove(key);
122  }
123
124  @Override
125  public String toString() {
126    StringBuilder s = new StringBuilder();
127    s.append('{');
128    s.append(HConstants.NAME);
129    s.append(" => '");
130    s.append(name);
131    s.append("'");
132    for (Map.Entry<String, String> e : configuration.entrySet()) {
133      String key = e.getKey();
134      String value = e.getValue();
135      if (key == null) {
136        continue;
137      }
138      s.append(", ");
139      s.append(key);
140      s.append(" => '");
141      s.append(value);
142      s.append("'");
143    }
144    s.append('}');
145    return s.toString();
146  }
147
148  public static Builder create(String name) {
149    return new Builder(name);
150  }
151
152  public static Builder create(NamespaceDescriptor ns) {
153    return new Builder(ns);
154  }
155
156  @InterfaceAudience.Public
157  public static class Builder {
158    private String bName;
159    private Map<String, String> bConfiguration = new TreeMap<>();
160
161    private Builder(NamespaceDescriptor ns) {
162      this.bName = ns.name;
163      this.bConfiguration = ns.configuration;
164    }
165
166    private Builder(String name) {
167      this.bName = name;
168    }
169
170    public Builder addConfiguration(Map<String, String> configuration) {
171      this.bConfiguration.putAll(configuration);
172      return this;
173    }
174
175    public Builder addConfiguration(String key, String value) {
176      this.bConfiguration.put(key, value);
177      return this;
178    }
179
180    public Builder removeConfiguration(String key) {
181      this.bConfiguration.remove(key);
182      return this;
183    }
184
185    public NamespaceDescriptor build() {
186      if (this.bName == null) {
187        throw new IllegalArgumentException("A name has to be specified in a namespace.");
188      }
189
190      NamespaceDescriptor desc = new NamespaceDescriptor(this.bName);
191      desc.configuration = this.bConfiguration;
192      return desc;
193    }
194  }
195}