View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.accumulo.core.iterators.conf;
18  
19  import java.util.Collection;
20  import java.util.HashSet;
21  import java.util.Set;
22  
23  import org.apache.accumulo.core.data.Key;
24  import org.apache.accumulo.core.iterators.conf.ColumnUtil.ColFamHashKey;
25  import org.apache.accumulo.core.iterators.conf.ColumnUtil.ColHashKey;
26  import org.apache.accumulo.core.util.Pair;
27  import org.apache.hadoop.io.Text;
28  
29  public class ColumnSet {
30    private Set<ColFamHashKey> objectsCF;
31    private Set<ColHashKey> objectsCol;
32    
33    private ColHashKey lookupCol = new ColHashKey();
34    private ColFamHashKey lookupCF = new ColFamHashKey();
35    
36    public ColumnSet() {
37      objectsCF = new HashSet<ColFamHashKey>();
38      objectsCol = new HashSet<ColHashKey>();
39    }
40    
41    public ColumnSet(Collection<String> objectStrings) {
42      this();
43      
44      for (String column : objectStrings) {
45        Pair<Text,Text> pcic = ColumnSet.decodeColumns(column);
46        
47        if (pcic.getSecond() == null) {
48          add(pcic.getFirst());
49        } else {
50          add(pcic.getFirst(), pcic.getSecond());
51        }
52      }
53    }
54    
55    protected void add(Text colf) {
56      objectsCF.add(new ColFamHashKey(new Text(colf)));
57    }
58    
59    protected void add(Text colf, Text colq) {
60      objectsCol.add(new ColHashKey(colf, colq));
61    }
62    
63    public boolean contains(Key key) {
64      // lookup column family and column qualifier
65      if (objectsCol.size() > 0) {
66        lookupCol.set(key);
67        if (objectsCol.contains(lookupCol))
68          return true;
69      }
70      
71      // lookup just column family
72      if (objectsCF.size() > 0) {
73        lookupCF.set(key);
74        return objectsCF.contains(lookupCF);
75      }
76      
77      return false;
78    }
79    
80    public boolean isEmpty() {
81      return objectsCol.size() == 0 && objectsCF.size() == 0;
82    }
83  
84    public static String encodeColumns(Text columnFamily, Text columnQualifier) {
85      StringBuilder sb = new StringBuilder();
86      
87      encode(sb, columnFamily);
88      if (columnQualifier != null) {
89        sb.append(':');
90        encode(sb, columnQualifier);
91      }
92      
93      return sb.toString();
94    }
95    
96    static void encode(StringBuilder sb, Text t) {
97      for (int i = 0; i < t.getLength(); i++) {
98        int b = (0xff & t.getBytes()[i]);
99        
100       // very inefficient code
101       if ((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || b == '_' || b == '-') {
102         sb.append((char) b);
103       } else {
104         sb.append('%');
105         sb.append(String.format("%02x", b));
106       }
107     }
108   }
109 
110   public static boolean isValidEncoding(String enc) {
111     for (char c : enc.toCharArray()) {
112       boolean validChar = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == ':' || c == '%';
113       if (!validChar)
114         return false;
115     }
116     
117     return true;
118   }
119 
120   public static Pair<Text,Text> decodeColumns(String columns) {
121     if (!isValidEncoding(columns))
122       throw new IllegalArgumentException("Invalid encoding " + columns);
123   
124     String[] cols = columns.split(":");
125     
126     if (cols.length == 1) {
127       return new Pair<Text,Text>(decode(cols[0]), null);
128     } else if (cols.length == 2) {
129       return new Pair<Text,Text>(decode(cols[0]), decode(cols[1]));
130     } else {
131       throw new IllegalArgumentException(columns);
132     }
133   }
134 
135   static Text decode(String s) {
136     Text t = new Text();
137     
138     byte[] sb = s.getBytes();
139     
140     // very inefficient code
141     for (int i = 0; i < sb.length; i++) {
142       if (sb[i] != '%') {
143         t.append(new byte[] {sb[i]}, 0, 1);
144       } else {
145         byte hex[] = new byte[] {sb[++i], sb[++i]};
146         String hs = new String(hex);
147         int b = Integer.parseInt(hs, 16);
148         t.append(new byte[] {(byte) b}, 0, 1);
149       }
150     }
151     
152     return t;
153   }
154 }