├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── HBaseIA │ │ └── TwitBase │ │ └── AsyncUsersTool.java └── resources │ └── simplelogger.properties └── test └── java └── HBaseIA └── TwitBase └── AppTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .classpath 3 | .project 4 | .settings/org.eclipse.core.resources.prefs 5 | .settings/org.eclipse.jdt.core.prefs 6 | .settings/org.eclipse.m2e.core.prefs 7 | *.jar 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HBase In Action: asynchbase TwitBase client 2 | 3 | [http://www.manning.com/dimidukkhurana][0] 4 | 5 | ## Compiling the project 6 | 7 | Code is managed by maven. Be sure to install maven on your platform 8 | before running these commands. Also be aware that HBase is not yet 9 | supported on the OpenJDK platform, the default JVM installed on most 10 | modern Linux distributions. You'll want to install the Oracle (Sun) 11 | Java 6 runtime and make sure it's configured on your `$PATH` before 12 | you continue. Again, on Ubuntu, you may find the [`oab-java6`][1] 13 | utility to be of use. 14 | 15 | To build a self-contained jar: 16 | 17 | $ mvn package 18 | 19 | The jar created using this by default will allow you to interact with 20 | HBase running in standalone mode on your local machine. If you want 21 | to interact with a remote (possibly fully distributed) HBase 22 | deployment, you need to edit the [`HBaseClient`][2] constructor in the 23 | source and recompile the jar. 24 | 25 | ## Using the asynchbase TwitBase client 26 | 27 | This client uses [asynchbase][3] for communication with HBase. The 28 | client assumes you have an existing TwitBase schema containing User 29 | data. Run the application with this command: 30 | 31 | $ java -cp target/twitbase-async-1.0.0.jar \ 32 | HBaseIA.TwitBase.AsyncUsersTool update 33 | 34 | ## License 35 | 36 | Copyright (C) 2012 Nick Dimiduk, Amandeep Khurana 37 | 38 | Distributed under the [Apache License, version 2.0][4], the same as HBase. 39 | 40 | [0]: http://www.manning.com/dimidukkhurana 41 | [1]: https://github.com/flexiondotorg/oab-java6 42 | [2]: http://tsunanet.net/~tsuna/asynchbase/api/org/hbase/async/HBaseClient.html 43 | [3]: https://github.com/OpenTSDB/asynchbase 44 | [4]: http://www.apache.org/licenses/LICENSE-2.0.html 45 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 5 | 4.0.0 6 | 7 | HBaseIA 8 | twitbase-async 9 | 1.0.1 10 | 11 | twitbase-async 12 | http://www.manning.com/dimidukkhurana/ 13 | 14 | 15 | UTF-8 16 | 17 | 18 | 19 | 20 | org.hbase 21 | asynchbase 22 | 1.3.2 23 | 24 | 25 | org.slf4j 26 | slf4j-api 27 | 1.6.6 28 | 29 | 30 | org.slf4j 31 | slf4j-simple 32 | 1.6.6 33 | 34 | 35 | 36 | junit 37 | junit 38 | 3.8.1 39 | test 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.apache.maven.plugins 47 | maven-compiler-plugin 48 | 2.5.1 49 | 50 | 1.6 51 | 1.6 52 | 53 | 54 | 55 | maven-assembly-plugin 56 | 2.3 57 | 58 | 59 | jar-with-dependencies 60 | package 61 | 62 | single 63 | 64 | 65 | 66 | jar-with-dependencies 67 | 68 | false 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/main/java/HBaseIA/TwitBase/AsyncUsersTool.java: -------------------------------------------------------------------------------- 1 | package HBaseIA.TwitBase; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | import org.hbase.async.HBaseClient; 8 | import org.hbase.async.KeyValue; 9 | import org.hbase.async.PutRequest; 10 | import org.hbase.async.Scanner; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import com.stumbleupon.async.Callback; 15 | import com.stumbleupon.async.Deferred; 16 | import com.stumbleupon.async.DeferredGroupException; 17 | 18 | public class AsyncUsersTool { 19 | 20 | static final byte[] TABLE_NAME = "users".getBytes(); 21 | static final byte[] INFO_FAM = "info".getBytes(); 22 | static final byte[] PASSWORD_COL = "password".getBytes(); 23 | static final byte[] EMAIL_COL = "email".getBytes(); 24 | 25 | public static final String usage = 26 | "usertool action ...\n" + 27 | " help - print this message and exit.\n" + 28 | " update - update passwords for all installed users.\n"; 29 | 30 | static byte[] mkNewPassword(byte[] seed) { 31 | UUID u = UUID.randomUUID(); 32 | return u.toString().replace("-", "").toLowerCase().getBytes(); 33 | } 34 | 35 | static void latency() throws Exception { 36 | if (System.currentTimeMillis() % 3 == 0) { 37 | LOG.info("a thread is napping..."); 38 | Thread.sleep(1000); 39 | } 40 | } 41 | 42 | static boolean entropy(Boolean val) { 43 | if (System.currentTimeMillis() % 5 == 0) { 44 | LOG.info("entropy strikes!"); 45 | return false; 46 | } 47 | return (val == null) ? Boolean.TRUE : val; 48 | } 49 | 50 | static final class UpdateResult { 51 | public String userId; 52 | public boolean success; 53 | } 54 | 55 | @SuppressWarnings("serial") 56 | static final class UpdateFailedException extends Exception { 57 | public UpdateResult result; 58 | 59 | public UpdateFailedException(UpdateResult r) { 60 | this.result = r; 61 | } 62 | } 63 | 64 | @SuppressWarnings("serial") 65 | static final class SendMessageFailedException extends Exception { 66 | public SendMessageFailedException() { 67 | super("Failed to send message!"); 68 | } 69 | } 70 | 71 | static final class InterpretResponse 72 | implements Callback { 73 | 74 | private String userId; 75 | 76 | InterpretResponse(String userId) { 77 | this.userId = userId; 78 | } 79 | 80 | public UpdateResult call(Boolean response) throws Exception { 81 | latency(); 82 | 83 | UpdateResult r = new UpdateResult(); 84 | r.userId = this.userId; 85 | r.success = entropy(response); 86 | if (!r.success) 87 | throw new UpdateFailedException(r); 88 | 89 | latency(); 90 | return r; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return String.format("InterpretResponse<%s>", userId); 96 | } 97 | } 98 | 99 | static final class ResultToMessage 100 | implements Callback { 101 | 102 | public String call(UpdateResult r) throws Exception { 103 | latency(); 104 | String fmt = "password change for user %s successful."; 105 | latency(); 106 | return String.format(fmt, r.userId); 107 | } 108 | 109 | @Override 110 | public String toString() { 111 | return "ResultToMessage"; 112 | } 113 | } 114 | 115 | static final class FailureToMessage 116 | implements Callback { 117 | 118 | public String call(UpdateFailedException e) throws Exception { 119 | latency(); 120 | String fmt = "%s, your password is unchanged!"; 121 | latency(); 122 | return String.format(fmt, e.result.userId); 123 | } 124 | 125 | @Override 126 | public String toString() { 127 | return "FailureToMessage"; 128 | } 129 | } 130 | 131 | static final class SendMessage 132 | implements Callback { 133 | 134 | public Boolean call(String s) throws Exception { 135 | latency(); 136 | if (entropy(null)) 137 | throw new SendMessageFailedException(); 138 | LOG.info(s); 139 | latency(); 140 | return Boolean.TRUE; 141 | } 142 | 143 | @Override 144 | public String toString() { 145 | return "SendMessage"; 146 | } 147 | } 148 | 149 | static List> doList(HBaseClient client) 150 | throws Throwable { 151 | final Scanner scanner = client.newScanner(TABLE_NAME); 152 | scanner.setFamily(INFO_FAM); 153 | scanner.setQualifier(PASSWORD_COL); 154 | 155 | ArrayList> rows = null; 156 | ArrayList> workers 157 | = new ArrayList>(); 158 | while ((rows = scanner.nextRows(1).joinUninterruptibly()) != null) { 159 | LOG.info("received a page of users."); 160 | for (ArrayList row : rows) { 161 | KeyValue kv = row.get(0); 162 | byte[] expected = kv.value(); 163 | String userId = new String(kv.key()); 164 | PutRequest put = new PutRequest( 165 | TABLE_NAME, kv.key(), kv.family(), 166 | kv.qualifier(), mkNewPassword(expected)); 167 | Deferred d = client.compareAndSet(put, expected) 168 | .addCallback(new InterpretResponse(userId)) 169 | .addCallbacks(new ResultToMessage(), new FailureToMessage()) 170 | .addCallback(new SendMessage()); 171 | workers.add(d); 172 | } 173 | } 174 | return workers; 175 | } 176 | 177 | public static void main(String[] args) throws Throwable { 178 | if (args.length == 0 || "help".equals(args[0])) { 179 | System.out.println(usage); 180 | System.exit(0); 181 | } 182 | 183 | final HBaseClient client = new HBaseClient("localhost"); 184 | 185 | if ("update".equals(args[0])) { 186 | Deferred> d = Deferred.group(doList(client)); 187 | try { 188 | d.join(); 189 | } catch (DeferredGroupException e) { 190 | LOG.info(e.getCause().getMessage()); 191 | } 192 | } 193 | 194 | client.shutdown().joinUninterruptibly(); 195 | } 196 | 197 | static final Logger LOG = LoggerFactory.getLogger(AsyncUsersTool.class); 198 | } 199 | -------------------------------------------------------------------------------- /src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | org.slf4j.simplelogger.showdatetime = false 2 | org.slf4j.simplelogger.showShortLogname = true 3 | 4 | org.slf4j.simplelogger.log.org.hbase.async = warn 5 | org.slf4j.simplelogger.log.org.apache.zookeeper = warn 6 | org.slf4j.simplelogger.log.org.apache.zookeeper.client = error 7 | -------------------------------------------------------------------------------- /src/test/java/HBaseIA/TwitBase/AppTest.java: -------------------------------------------------------------------------------- 1 | package HBaseIA.TwitBase; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | --------------------------------------------------------------------------------