View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.util;
20  
21  import java.util.StringTokenizer;
22  import java.util.regex.Matcher;
23  import java.util.regex.Pattern;
24  
25  import org.apache.hadoop.classification.InterfaceAudience;
26  import org.apache.hadoop.classification.InterfaceStability;
27  
28  /**
29   * Utility creating hbase friendly keys.
30   * Use fabricating row names or column qualifiers.
31   * <p>TODO: Add createSchemeless key, a key that doesn't care if scheme is
32   * http or https.
33   * @see Bytes#split(byte[], byte[], int)
34   */
35  @InterfaceAudience.Public
36  @InterfaceStability.Stable
37  @Deprecated // seems unused
38  public class Keying {
39    private static final String SCHEME = "r:";
40    private static final Pattern URI_RE_PARSER =
41      Pattern.compile("^([^:/?#]+://(?:[^/?#@]+@)?)([^:/?#]+)(.*)$");
42  
43    /**
44     * Makes a key out of passed URI for use as row name or column qualifier.
45     *
46     * This method runs transforms on the passed URI so it sits better
47     * as a key (or portion-of-a-key) in hbase.  The <code>host</code> portion of
48     * the URI authority is reversed so subdomains sort under their parent
49     * domain.  The returned String is an opaque URI of an artificial
50     * <code>r:</code> scheme to prevent the result being considered an URI of
51     * the original scheme.  Here is an example of the transform: The url
52     * <code>http://lucene.apache.org/index.html?query=something#middle<code> is
53     * returned as
54     * <code>r:http://org.apache.lucene/index.html?query=something#middle</code>
55     * The transforms are reversible.  No transform is done if passed URI is
56     * not hierarchical.
57     *
58     * <p>If authority <code>userinfo</code> is present, will mess up the sort
59     * (until we do more work).</p>
60     *
61     * @param u URL to transform.
62     * @return An opaque URI of artificial 'r' scheme with host portion of URI
63     * authority reversed (if present).
64     * @see #keyToUri(String)
65     * @see <a href="http://www.ietf.org/rfc/rfc2396.txt">RFC2396</a>
66     */
67    public static String createKey(final String u) {
68      if (u.startsWith(SCHEME)) {
69        throw new IllegalArgumentException("Starts with " + SCHEME);
70      }
71      Matcher m = getMatcher(u);
72      if (m == null || !m.matches()) {
73        // If no match, return original String.
74        return u;
75      }
76      return SCHEME + m.group(1) + reverseHostname(m.group(2)) + m.group(3);
77    }
78  
79    /**
80     * Reverse the {@link #createKey(String)} transform.
81     *
82     * @param s <code>URI</code> made by {@link #createKey(String)}.
83     * @return 'Restored' URI made by reversing the {@link #createKey(String)}
84     * transform.
85     */
86    public static String keyToUri(final String s) {
87      if (!s.startsWith(SCHEME)) {
88        return s;
89      }
90      Matcher m = getMatcher(s.substring(SCHEME.length()));
91      if (m == null || !m.matches()) {
92        // If no match, return original String.
93        return s;
94      }
95      return m.group(1) + reverseHostname(m.group(2)) + m.group(3);
96    }
97  
98    private static Matcher getMatcher(final String u) {
99      if (u == null || u.length() <= 0) {
100       return null;
101     }
102     return URI_RE_PARSER.matcher(u);
103   }
104 
105   private static String reverseHostname(final String hostname) {
106     if (hostname == null) {
107       return "";
108     }
109     StringBuilder sb = new StringBuilder(hostname.length());
110     for (StringTokenizer st = new StringTokenizer(hostname, ".", false);
111         st.hasMoreElements();) {
112       Object next = st.nextElement();
113       if (sb.length() > 0) {
114         sb.insert(0, ".");
115       }
116       sb.insert(0, next);
117     }
118     return sb.toString();
119   }
120 
121 }