1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.thrift;
20
21 import java.io.UnsupportedEncodingException;
22 import java.nio.ByteBuffer;
23 import java.nio.charset.CharacterCodingException;
24 import java.nio.charset.Charset;
25 import java.nio.charset.CharsetDecoder;
26 import java.security.PrivilegedExceptionAction;
27 import java.text.NumberFormat;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.SortedMap;
33 import java.util.TreeMap;
34
35 import javax.security.auth.Subject;
36 import javax.security.auth.login.AppConfigurationEntry;
37 import javax.security.auth.login.Configuration;
38 import javax.security.auth.login.LoginContext;
39 import javax.security.sasl.Sasl;
40
41 import org.apache.hadoop.hbase.thrift.generated.AlreadyExists;
42 import org.apache.hadoop.hbase.thrift.generated.ColumnDescriptor;
43 import org.apache.hadoop.hbase.thrift.generated.Hbase;
44 import org.apache.hadoop.hbase.thrift.generated.Mutation;
45 import org.apache.hadoop.hbase.thrift.generated.TCell;
46 import org.apache.hadoop.hbase.thrift.generated.TRowResult;
47 import org.apache.thrift.protocol.TBinaryProtocol;
48 import org.apache.thrift.protocol.TProtocol;
49 import org.apache.thrift.transport.TSaslClientTransport;
50 import org.apache.thrift.transport.TSocket;
51 import org.apache.thrift.transport.TTransport;
52
53
54
55
56 public class DemoClient {
57
58 static protected int port;
59 static protected String host;
60 CharsetDecoder decoder = null;
61
62 private static boolean secure = false;
63 private static String serverPrincipal = "hbase";
64
65 public static void main(String[] args) throws Exception {
66
67 if (args.length < 2 || args.length > 4 || (args.length > 2 && !isBoolean(args[2]))) {
68
69 System.out.println("Invalid arguments!");
70 System.out.println("Usage: DemoClient host port [secure=false [server-principal=hbase] ]");
71
72 System.exit(-1);
73 }
74
75 port = Integer.parseInt(args[1]);
76 host = args[0];
77 if (args.length > 2) {
78 secure = Boolean.parseBoolean(args[2]);
79 }
80
81 if (args.length == 4) {
82 serverPrincipal = args[3];
83 }
84
85 final DemoClient client = new DemoClient();
86 Subject.doAs(getSubject(),
87 new PrivilegedExceptionAction<Void>() {
88 @Override
89 public Void run() throws Exception {
90 client.run();
91 return null;
92 }
93 });
94 }
95
96 private static boolean isBoolean(String s){
97 return Boolean.TRUE.toString().equalsIgnoreCase(s) || Boolean.FALSE.toString().equalsIgnoreCase(s);
98 }
99
100 DemoClient() {
101 decoder = Charset.forName("UTF-8").newDecoder();
102 }
103
104
105 private String utf8(byte[] buf) {
106 try {
107 return decoder.decode(ByteBuffer.wrap(buf)).toString();
108 } catch (CharacterCodingException e) {
109 return "[INVALID UTF-8]";
110 }
111 }
112
113
114 private byte[] bytes(String s) {
115 try {
116 return s.getBytes("UTF-8");
117 } catch (UnsupportedEncodingException e) {
118 e.printStackTrace();
119 return null;
120 }
121 }
122
123 private void run() throws Exception {
124 TTransport transport = new TSocket(host, port);
125 if (secure) {
126 Map<String, String> saslProperties = new HashMap<String, String>();
127 saslProperties.put(Sasl.QOP, "auth-conf,auth-int,auth");
128
129
130
131
132
133
134 transport = new TSaslClientTransport("GSSAPI", null,
135 serverPrincipal,
136 host,
137 saslProperties, null, transport);
138 }
139
140 transport.open();
141
142 TProtocol protocol = new TBinaryProtocol(transport, true, true);
143 Hbase.Client client = new Hbase.Client(protocol);
144
145 byte[] t = bytes("demo_table");
146
147
148
149
150 System.out.println("scanning tables...");
151 for (ByteBuffer name : client.getTableNames()) {
152 System.out.println(" found: " + utf8(name.array()));
153 if (utf8(name.array()).equals(utf8(t))) {
154 if (client.isTableEnabled(name)) {
155 System.out.println(" disabling table: " + utf8(name.array()));
156 client.disableTable(name);
157 }
158 System.out.println(" deleting table: " + utf8(name.array()));
159 client.deleteTable(name);
160 }
161 }
162
163
164
165
166 ArrayList<ColumnDescriptor> columns = new ArrayList<ColumnDescriptor>();
167 ColumnDescriptor col;
168 col = new ColumnDescriptor();
169 col.name = ByteBuffer.wrap(bytes("entry:"));
170 col.timeToLive = Integer.MAX_VALUE;
171 col.maxVersions = 10;
172 columns.add(col);
173 col = new ColumnDescriptor();
174 col.name = ByteBuffer.wrap(bytes("unused:"));
175 col.timeToLive = Integer.MAX_VALUE;
176 columns.add(col);
177
178 System.out.println("creating table: " + utf8(t));
179 try {
180 client.createTable(ByteBuffer.wrap(t), columns);
181 } catch (AlreadyExists ae) {
182 System.out.println("WARN: " + ae.message);
183 }
184
185 System.out.println("column families in " + utf8(t) + ": ");
186 Map<ByteBuffer, ColumnDescriptor> columnMap = client.getColumnDescriptors(ByteBuffer.wrap(t));
187 for (ColumnDescriptor col2 : columnMap.values()) {
188 System.out.println(" column: " + utf8(col2.name.array()) + ", maxVer: " + Integer.toString(col2.maxVersions));
189 }
190
191 Map<ByteBuffer, ByteBuffer> dummyAttributes = null;
192 boolean writeToWal = false;
193
194
195
196
197 byte[] invalid = {(byte) 'f', (byte) 'o', (byte) 'o', (byte) '-',
198 (byte) 0xfc, (byte) 0xa1, (byte) 0xa1, (byte) 0xa1, (byte) 0xa1};
199 byte[] valid = {(byte) 'f', (byte) 'o', (byte) 'o', (byte) '-',
200 (byte) 0xE7, (byte) 0x94, (byte) 0x9F, (byte) 0xE3, (byte) 0x83,
201 (byte) 0x93, (byte) 0xE3, (byte) 0x83, (byte) 0xBC, (byte) 0xE3,
202 (byte) 0x83, (byte) 0xAB};
203
204 ArrayList<Mutation> mutations;
205
206 mutations = new ArrayList<Mutation>();
207 mutations.add(new Mutation(false, ByteBuffer.wrap(bytes("entry:foo")),
208 ByteBuffer.wrap(invalid), writeToWal));
209 client.mutateRow(ByteBuffer.wrap(t), ByteBuffer.wrap(bytes("foo")),
210 mutations, dummyAttributes);
211
212
213
214 mutations = new ArrayList<Mutation>();
215 mutations.add(new Mutation(false, ByteBuffer.wrap(bytes("entry:foo")), ByteBuffer.wrap(valid), writeToWal));
216 client.mutateRow(ByteBuffer.wrap(t), ByteBuffer.wrap(valid), mutations, dummyAttributes);
217
218
219
220 mutations = new ArrayList<Mutation>();
221 mutations.add(new Mutation(false, ByteBuffer.wrap(bytes("entry:foo")), ByteBuffer.wrap(invalid), writeToWal));
222 client.mutateRow(ByteBuffer.wrap(t), ByteBuffer.wrap(invalid), mutations, dummyAttributes);
223
224
225
226 ArrayList<ByteBuffer> columnNames = new ArrayList<ByteBuffer>();
227 columnNames.add(ByteBuffer.wrap(bytes("entry:")));
228
229 System.out.println("Starting scanner...");
230 int scanner = client.scannerOpen(ByteBuffer.wrap(t), ByteBuffer.wrap(bytes("")), columnNames, dummyAttributes);
231
232 while (true) {
233 List<TRowResult> entry = client.scannerGet(scanner);
234 if (entry.isEmpty()) {
235 break;
236 }
237 printRow(entry);
238 }
239
240
241
242
243 for (int i = 100; i >= 0; --i) {
244
245 NumberFormat nf = NumberFormat.getInstance();
246 nf.setMinimumIntegerDigits(5);
247 nf.setGroupingUsed(false);
248 byte[] row = bytes(nf.format(i));
249
250 mutations = new ArrayList<Mutation>();
251 mutations.add(new Mutation(false, ByteBuffer.wrap(bytes("unused:")), ByteBuffer.wrap(bytes("DELETE_ME")), writeToWal));
252 client.mutateRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), mutations, dummyAttributes);
253 printRow(client.getRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), dummyAttributes));
254 client.deleteAllRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), dummyAttributes);
255
256
257 try {
258 Thread.sleep(50);
259 } catch (InterruptedException e) {
260
261 }
262
263 mutations = new ArrayList<Mutation>();
264 mutations.add(new Mutation(false, ByteBuffer.wrap(bytes("entry:num")), ByteBuffer.wrap(bytes("0")), writeToWal));
265 mutations.add(new Mutation(false, ByteBuffer.wrap(bytes("entry:foo")), ByteBuffer.wrap(bytes("FOO")), writeToWal));
266 client.mutateRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), mutations, dummyAttributes);
267 printRow(client.getRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), dummyAttributes));
268
269 Mutation m;
270 mutations = new ArrayList<Mutation>();
271 m = new Mutation();
272 m.column = ByteBuffer.wrap(bytes("entry:foo"));
273 m.isDelete = true;
274 mutations.add(m);
275 m = new Mutation();
276 m.column = ByteBuffer.wrap(bytes("entry:num"));
277 m.value = ByteBuffer.wrap(bytes("-1"));
278 mutations.add(m);
279 client.mutateRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), mutations, dummyAttributes);
280 printRow(client.getRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), dummyAttributes));
281
282 mutations = new ArrayList<Mutation>();
283 mutations.add(new Mutation(false, ByteBuffer.wrap(bytes("entry:num")), ByteBuffer.wrap(bytes(Integer.toString(i))), writeToWal));
284 mutations.add(new Mutation(false, ByteBuffer.wrap(bytes("entry:sqr")), ByteBuffer.wrap(bytes(Integer.toString(i * i))), writeToWal));
285 client.mutateRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), mutations, dummyAttributes);
286 printRow(client.getRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), dummyAttributes));
287
288
289 try {
290 Thread.sleep(50);
291 } catch (InterruptedException e) {
292
293 }
294
295 mutations.clear();
296 m = new Mutation();
297 m.column = ByteBuffer.wrap(bytes("entry:num"));
298 m.value= ByteBuffer.wrap(bytes("-999"));
299 mutations.add(m);
300 m = new Mutation();
301 m.column = ByteBuffer.wrap(bytes("entry:sqr"));
302 m.isDelete = true;
303 client.mutateRowTs(ByteBuffer.wrap(t), ByteBuffer.wrap(row), mutations, 1, dummyAttributes);
304 printRow(client.getRow(ByteBuffer.wrap(t), ByteBuffer.wrap(row), dummyAttributes));
305
306 List<TCell> versions = client.getVer(ByteBuffer.wrap(t), ByteBuffer.wrap(row), ByteBuffer.wrap(bytes("entry:num")), 10, dummyAttributes);
307 printVersions(ByteBuffer.wrap(row), versions);
308 if (versions.isEmpty()) {
309 System.out.println("FATAL: wrong # of versions");
310 System.exit(-1);
311 }
312
313 List<TCell> result = client.get(ByteBuffer.wrap(t), ByteBuffer.wrap(row), ByteBuffer.wrap(bytes("entry:foo")), dummyAttributes);
314 if (!result.isEmpty()) {
315 System.out.println("FATAL: shouldn't get here");
316 System.exit(-1);
317 }
318
319 System.out.println("");
320 }
321
322
323
324 columnNames.clear();
325 for (ColumnDescriptor col2 : client.getColumnDescriptors(ByteBuffer.wrap(t)).values()) {
326 System.out.println("column with name: " + new String(col2.name.array()));
327 System.out.println(col2.toString());
328
329 columnNames.add(col2.name);
330 }
331
332 System.out.println("Starting scanner...");
333 scanner = client.scannerOpenWithStop(ByteBuffer.wrap(t), ByteBuffer.wrap(bytes("00020")), ByteBuffer.wrap(bytes("00040")), columnNames, dummyAttributes);
334
335 while (true) {
336 List<TRowResult> entry = client.scannerGet(scanner);
337 if (entry.isEmpty()) {
338 System.out.println("Scanner finished");
339 break;
340 }
341 printRow(entry);
342 }
343
344 transport.close();
345 }
346
347 private void printVersions(ByteBuffer row, List<TCell> versions) {
348 StringBuilder rowStr = new StringBuilder();
349 for (TCell cell : versions) {
350 rowStr.append(utf8(cell.value.array()));
351 rowStr.append("; ");
352 }
353 System.out.println("row: " + utf8(row.array()) + ", values: " + rowStr);
354 }
355
356 private void printRow(TRowResult rowResult) {
357
358
359 TreeMap<String, TCell> sorted = new TreeMap<String, TCell>();
360 for (Map.Entry<ByteBuffer, TCell> column : rowResult.columns.entrySet()) {
361 sorted.put(utf8(column.getKey().array()), column.getValue());
362 }
363
364 StringBuilder rowStr = new StringBuilder();
365 for (SortedMap.Entry<String, TCell> entry : sorted.entrySet()) {
366 rowStr.append(entry.getKey());
367 rowStr.append(" => ");
368 rowStr.append(utf8(entry.getValue().value.array()));
369 rowStr.append("; ");
370 }
371 System.out.println("row: " + utf8(rowResult.row.array()) + ", cols: " + rowStr);
372 }
373
374 private void printRow(List<TRowResult> rows) {
375 for (TRowResult rowResult : rows) {
376 printRow(rowResult);
377 }
378 }
379
380 static Subject getSubject() throws Exception {
381 if (!secure) return new Subject();
382
383
384
385
386
387 LoginContext context = new LoginContext("", new Subject(), null,
388 new Configuration() {
389 @Override
390 public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
391 Map<String, String> options = new HashMap<String, String>();
392 options.put("useKeyTab", "false");
393 options.put("storeKey", "false");
394 options.put("doNotPrompt", "true");
395 options.put("useTicketCache", "true");
396 options.put("renewTGT", "true");
397 options.put("refreshKrb5Config", "true");
398 options.put("isInitiator", "true");
399 String ticketCache = System.getenv("KRB5CCNAME");
400 if (ticketCache != null) {
401 options.put("ticketCache", ticketCache);
402 }
403 options.put("debug", "true");
404
405 return new AppConfigurationEntry[]{
406 new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule",
407 AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
408 options)};
409 }
410 });
411 context.login();
412 return context.getSubject();
413 }
414 }